@adhdev/daemon-standalone 0.9.82-rc.172 → 0.9.82-rc.173
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +769 -685
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/index-BSeeeP5M.css +1 -0
- package/public/assets/index-DcGt6j-i.js +99 -0
- package/public/index.html +2 -2
- package/vendor/mcp-server/index.js +9 -5
- package/vendor/mcp-server/index.js.map +1 -1
package/dist/index.js
CHANGED
|
@@ -35008,6 +35008,261 @@ var require_dist3 = __commonJS({
|
|
|
35008
35008
|
};
|
|
35009
35009
|
}
|
|
35010
35010
|
});
|
|
35011
|
+
async function getGitRepoStatus(workspace, options = {}) {
|
|
35012
|
+
const lastCheckedAt = Date.now();
|
|
35013
|
+
const includeSubmodules = options.includeSubmodules !== false;
|
|
35014
|
+
try {
|
|
35015
|
+
const repo = await resolveGitRepository(workspace, options);
|
|
35016
|
+
let parsed = await readPorcelainStatus(repo, options);
|
|
35017
|
+
let upstreamProbe = getInitialUpstreamProbe(parsed);
|
|
35018
|
+
if (options.refreshUpstream) {
|
|
35019
|
+
upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
|
|
35020
|
+
if (upstreamProbe.upstreamStatus === "fresh") {
|
|
35021
|
+
parsed = await readPorcelainStatus(repo, options);
|
|
35022
|
+
}
|
|
35023
|
+
}
|
|
35024
|
+
const head = await readHead(repo, options);
|
|
35025
|
+
const stashCount = await readStashCount(repo, options);
|
|
35026
|
+
let submodules;
|
|
35027
|
+
if (includeSubmodules) {
|
|
35028
|
+
submodules = await getSubmoduleStatuses(repo, options);
|
|
35029
|
+
}
|
|
35030
|
+
return {
|
|
35031
|
+
workspace: repo.workspace,
|
|
35032
|
+
repoRoot: repo.repoRoot,
|
|
35033
|
+
isGitRepo: true,
|
|
35034
|
+
branch: parsed.branch,
|
|
35035
|
+
headCommit: head.commit,
|
|
35036
|
+
headMessage: head.message,
|
|
35037
|
+
upstream: parsed.upstream,
|
|
35038
|
+
upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
|
|
35039
|
+
upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
|
|
35040
|
+
upstreamFetchError: upstreamProbe.upstreamFetchError,
|
|
35041
|
+
ahead: parsed.ahead,
|
|
35042
|
+
behind: parsed.behind,
|
|
35043
|
+
staged: parsed.staged,
|
|
35044
|
+
modified: parsed.modified,
|
|
35045
|
+
untracked: parsed.untracked,
|
|
35046
|
+
deleted: parsed.deleted,
|
|
35047
|
+
renamed: parsed.renamed,
|
|
35048
|
+
hasConflicts: parsed.conflictFiles.length > 0,
|
|
35049
|
+
conflictFiles: parsed.conflictFiles,
|
|
35050
|
+
stashCount,
|
|
35051
|
+
lastCheckedAt,
|
|
35052
|
+
submodules
|
|
35053
|
+
};
|
|
35054
|
+
} catch (error48) {
|
|
35055
|
+
if (error48 instanceof GitCommandError) {
|
|
35056
|
+
return emptyStatus(workspace, lastCheckedAt, error48);
|
|
35057
|
+
}
|
|
35058
|
+
return emptyStatus(
|
|
35059
|
+
workspace,
|
|
35060
|
+
lastCheckedAt,
|
|
35061
|
+
new GitCommandError("git_command_failed", "Failed to read Git status", { cause: error48 })
|
|
35062
|
+
);
|
|
35063
|
+
}
|
|
35064
|
+
}
|
|
35065
|
+
async function readPorcelainStatus(repo, options) {
|
|
35066
|
+
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
35067
|
+
return parsePorcelainV2Status(statusOutput.stdout);
|
|
35068
|
+
}
|
|
35069
|
+
function getInitialUpstreamProbe(parsed) {
|
|
35070
|
+
return {
|
|
35071
|
+
upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
|
|
35072
|
+
};
|
|
35073
|
+
}
|
|
35074
|
+
async function refreshTrackedUpstream(repo, parsed, options) {
|
|
35075
|
+
if (!parsed.upstream || !parsed.branch) {
|
|
35076
|
+
return { upstreamStatus: "no_upstream" };
|
|
35077
|
+
}
|
|
35078
|
+
const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
|
|
35079
|
+
if (!remoteName) {
|
|
35080
|
+
return {
|
|
35081
|
+
upstreamStatus: "stale",
|
|
35082
|
+
upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
|
|
35083
|
+
};
|
|
35084
|
+
}
|
|
35085
|
+
try {
|
|
35086
|
+
await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
|
|
35087
|
+
return {
|
|
35088
|
+
upstreamStatus: "fresh",
|
|
35089
|
+
upstreamFetchedAt: Date.now()
|
|
35090
|
+
};
|
|
35091
|
+
} catch (error48) {
|
|
35092
|
+
return {
|
|
35093
|
+
upstreamStatus: "stale",
|
|
35094
|
+
upstreamFetchError: formatGitError(error48)
|
|
35095
|
+
};
|
|
35096
|
+
}
|
|
35097
|
+
}
|
|
35098
|
+
async function readBranchRemote(repo, branch, options) {
|
|
35099
|
+
try {
|
|
35100
|
+
const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
|
|
35101
|
+
return result.stdout.trim() || null;
|
|
35102
|
+
} catch {
|
|
35103
|
+
return null;
|
|
35104
|
+
}
|
|
35105
|
+
}
|
|
35106
|
+
function inferRemoteName(upstream) {
|
|
35107
|
+
const [remoteName] = upstream.split("/");
|
|
35108
|
+
return remoteName?.trim() || null;
|
|
35109
|
+
}
|
|
35110
|
+
function formatGitError(error48) {
|
|
35111
|
+
if (error48 instanceof GitCommandError) {
|
|
35112
|
+
return error48.stderr || error48.message;
|
|
35113
|
+
}
|
|
35114
|
+
if (error48 instanceof Error) {
|
|
35115
|
+
return error48.message;
|
|
35116
|
+
}
|
|
35117
|
+
return String(error48);
|
|
35118
|
+
}
|
|
35119
|
+
function parsePorcelainV2Status(output) {
|
|
35120
|
+
const parsed = {
|
|
35121
|
+
branch: null,
|
|
35122
|
+
upstream: null,
|
|
35123
|
+
ahead: 0,
|
|
35124
|
+
behind: 0,
|
|
35125
|
+
staged: 0,
|
|
35126
|
+
modified: 0,
|
|
35127
|
+
untracked: 0,
|
|
35128
|
+
deleted: 0,
|
|
35129
|
+
renamed: 0,
|
|
35130
|
+
conflictFiles: []
|
|
35131
|
+
};
|
|
35132
|
+
for (const line of output.split("\n")) {
|
|
35133
|
+
if (!line) continue;
|
|
35134
|
+
if (line.startsWith("# branch.head ")) {
|
|
35135
|
+
const branch = line.slice("# branch.head ".length).trim();
|
|
35136
|
+
parsed.branch = branch && branch !== "(detached)" ? branch : null;
|
|
35137
|
+
continue;
|
|
35138
|
+
}
|
|
35139
|
+
if (line.startsWith("# branch.upstream ")) {
|
|
35140
|
+
parsed.upstream = line.slice("# branch.upstream ".length).trim() || null;
|
|
35141
|
+
continue;
|
|
35142
|
+
}
|
|
35143
|
+
if (line.startsWith("# branch.ab ")) {
|
|
35144
|
+
const match = line.match(/\+(-?\d+)\s+-(-?\d+)/);
|
|
35145
|
+
if (match) {
|
|
35146
|
+
parsed.ahead = Number.parseInt(match[1] ?? "0", 10) || 0;
|
|
35147
|
+
parsed.behind = Number.parseInt(match[2] ?? "0", 10) || 0;
|
|
35148
|
+
}
|
|
35149
|
+
continue;
|
|
35150
|
+
}
|
|
35151
|
+
if (line.startsWith("? ")) {
|
|
35152
|
+
parsed.untracked += 1;
|
|
35153
|
+
continue;
|
|
35154
|
+
}
|
|
35155
|
+
if (line.startsWith("u ")) {
|
|
35156
|
+
const fields = line.split(" ");
|
|
35157
|
+
const filePath = fields.slice(10).join(" ");
|
|
35158
|
+
if (filePath) parsed.conflictFiles.push(filePath);
|
|
35159
|
+
continue;
|
|
35160
|
+
}
|
|
35161
|
+
if (line.startsWith("1 ") || line.startsWith("2 ")) {
|
|
35162
|
+
const fields = line.split(" ");
|
|
35163
|
+
const xy = fields[1] ?? "..";
|
|
35164
|
+
const indexStatus = xy[0] ?? ".";
|
|
35165
|
+
const worktreeStatus = xy[1] ?? ".";
|
|
35166
|
+
if (isStagedStatus(indexStatus)) parsed.staged += 1;
|
|
35167
|
+
if (worktreeStatus === "M" || worktreeStatus === "T") parsed.modified += 1;
|
|
35168
|
+
if (indexStatus === "D" || worktreeStatus === "D") parsed.deleted += 1;
|
|
35169
|
+
if (indexStatus === "R" || worktreeStatus === "R") parsed.renamed += 1;
|
|
35170
|
+
if (xy.includes("U")) {
|
|
35171
|
+
const filePath = fields.slice(line.startsWith("2 ") ? 9 : 8).join(" ").split(" ")[0] ?? "";
|
|
35172
|
+
if (filePath) parsed.conflictFiles.push(filePath);
|
|
35173
|
+
}
|
|
35174
|
+
}
|
|
35175
|
+
}
|
|
35176
|
+
parsed.conflictFiles = Array.from(new Set(parsed.conflictFiles));
|
|
35177
|
+
return parsed;
|
|
35178
|
+
}
|
|
35179
|
+
async function readHead(repo, options) {
|
|
35180
|
+
try {
|
|
35181
|
+
const result = await runGit(repo, ["log", "-1", "--pretty=%h%x00%s"], options);
|
|
35182
|
+
const text = result.stdout.trimEnd();
|
|
35183
|
+
if (!text) return { commit: null, message: null };
|
|
35184
|
+
const [commit, ...messageParts] = text.split("\0");
|
|
35185
|
+
return {
|
|
35186
|
+
commit: commit || null,
|
|
35187
|
+
message: messageParts.join("\0") || null
|
|
35188
|
+
};
|
|
35189
|
+
} catch {
|
|
35190
|
+
return { commit: null, message: null };
|
|
35191
|
+
}
|
|
35192
|
+
}
|
|
35193
|
+
async function readStashCount(repo, options) {
|
|
35194
|
+
try {
|
|
35195
|
+
const result = await runGit(repo, ["stash", "list", "--format=%gd"], options);
|
|
35196
|
+
return result.stdout.split("\n").filter((line) => line.trim().length > 0).length;
|
|
35197
|
+
} catch {
|
|
35198
|
+
return 0;
|
|
35199
|
+
}
|
|
35200
|
+
}
|
|
35201
|
+
function isStagedStatus(status) {
|
|
35202
|
+
return status !== "." && status !== "?" && status !== "U";
|
|
35203
|
+
}
|
|
35204
|
+
function emptyStatus(workspace, lastCheckedAt, error48) {
|
|
35205
|
+
return {
|
|
35206
|
+
workspace,
|
|
35207
|
+
repoRoot: null,
|
|
35208
|
+
isGitRepo: false,
|
|
35209
|
+
branch: null,
|
|
35210
|
+
headCommit: null,
|
|
35211
|
+
headMessage: null,
|
|
35212
|
+
upstream: null,
|
|
35213
|
+
upstreamStatus: "unavailable",
|
|
35214
|
+
ahead: 0,
|
|
35215
|
+
behind: 0,
|
|
35216
|
+
staged: 0,
|
|
35217
|
+
modified: 0,
|
|
35218
|
+
untracked: 0,
|
|
35219
|
+
deleted: 0,
|
|
35220
|
+
renamed: 0,
|
|
35221
|
+
hasConflicts: false,
|
|
35222
|
+
conflictFiles: [],
|
|
35223
|
+
stashCount: 0,
|
|
35224
|
+
lastCheckedAt,
|
|
35225
|
+
error: error48.stderr || error48.message,
|
|
35226
|
+
reason: error48.reason
|
|
35227
|
+
};
|
|
35228
|
+
}
|
|
35229
|
+
async function getSubmoduleStatuses(repo, options) {
|
|
35230
|
+
if (!repo.repoRoot) return [];
|
|
35231
|
+
try {
|
|
35232
|
+
const result = await runGit(repo, ["submodule", "status", "--recursive"], options);
|
|
35233
|
+
return parseSubmoduleStatusOutput(result.stdout, repo.repoRoot, options.submoduleIgnorePaths);
|
|
35234
|
+
} catch {
|
|
35235
|
+
return [];
|
|
35236
|
+
}
|
|
35237
|
+
}
|
|
35238
|
+
function parseSubmoduleStatusOutput(output, repoRoot, ignorePaths) {
|
|
35239
|
+
const submodules = [];
|
|
35240
|
+
const ignoreSet = new Set(ignorePaths || []);
|
|
35241
|
+
for (const line of output.split("\n")) {
|
|
35242
|
+
if (!line.trim()) continue;
|
|
35243
|
+
const match = line.match(/^([\-+\s])([0-9a-f]{40})\s+(\S+)(?:\s+\(([^)]+)\))?/);
|
|
35244
|
+
if (!match) continue;
|
|
35245
|
+
const prefix = match[1];
|
|
35246
|
+
const commit = match[2];
|
|
35247
|
+
const path40 = match[3];
|
|
35248
|
+
if (ignoreSet.has(path40)) continue;
|
|
35249
|
+
submodules.push({
|
|
35250
|
+
path: path40,
|
|
35251
|
+
commit,
|
|
35252
|
+
repoPath: repoRoot + "/" + path40,
|
|
35253
|
+
dirty: prefix === "+",
|
|
35254
|
+
outOfSync: prefix === "-",
|
|
35255
|
+
lastCheckedAt: Date.now()
|
|
35256
|
+
});
|
|
35257
|
+
}
|
|
35258
|
+
return submodules;
|
|
35259
|
+
}
|
|
35260
|
+
var init_git_status = __esm2({
|
|
35261
|
+
"src/git/git-status.ts"() {
|
|
35262
|
+
"use strict";
|
|
35263
|
+
init_git_executor();
|
|
35264
|
+
}
|
|
35265
|
+
});
|
|
35011
35266
|
var git_worktree_exports = {};
|
|
35012
35267
|
__export2(git_worktree_exports, {
|
|
35013
35268
|
createWorktree: () => createWorktree,
|
|
@@ -35540,6 +35795,16 @@ ${error48.message || ""}`;
|
|
|
35540
35795
|
return { meshes: [] };
|
|
35541
35796
|
}
|
|
35542
35797
|
}
|
|
35798
|
+
function normalizeCapabilityTags(value) {
|
|
35799
|
+
if (!Array.isArray(value)) return void 0;
|
|
35800
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35801
|
+
const tags = value.map((tag) => typeof tag === "string" ? tag.trim() : "").filter(Boolean).filter((tag) => {
|
|
35802
|
+
if (seen.has(tag)) return false;
|
|
35803
|
+
seen.add(tag);
|
|
35804
|
+
return true;
|
|
35805
|
+
});
|
|
35806
|
+
return tags.length ? tags : void 0;
|
|
35807
|
+
}
|
|
35543
35808
|
function saveMeshConfig(config2) {
|
|
35544
35809
|
const path40 = getMeshConfigPath();
|
|
35545
35810
|
(0, import_fs2.writeFileSync)(path40, JSON.stringify(config2, null, 2), { encoding: "utf-8", mode: 384 });
|
|
@@ -35825,6 +36090,7 @@ ${error48.message || ""}`;
|
|
|
35825
36090
|
repoRoot: opts.repoRoot,
|
|
35826
36091
|
daemonId: opts.daemonId,
|
|
35827
36092
|
machineId: opts.machineId,
|
|
36093
|
+
capabilities: normalizeCapabilityTags(opts.capabilities),
|
|
35828
36094
|
userOverrides: opts.userOverrides || {},
|
|
35829
36095
|
policy: opts.policy || {},
|
|
35830
36096
|
isLocalWorktree: opts.isLocalWorktree,
|
|
@@ -37349,6 +37615,367 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
37349
37615
|
LEDGER_CACHE_TTL_MS = 100;
|
|
37350
37616
|
}
|
|
37351
37617
|
});
|
|
37618
|
+
async function fastForwardMeshNode(args) {
|
|
37619
|
+
const workspace = typeof args.workspace === "string" ? args.workspace.trim() : "";
|
|
37620
|
+
const nodeId = normalizeOptionalString(args.nodeId);
|
|
37621
|
+
const meshId = normalizeOptionalString(args.meshId);
|
|
37622
|
+
const requestedBranch = normalizeOptionalString(args.branch);
|
|
37623
|
+
const trigger = normalizeOptionalString(args.trigger) || "manual";
|
|
37624
|
+
const updateSubmodules = args.updateSubmodules === true;
|
|
37625
|
+
const dryRun = args.dryRun === true || args.execute !== true;
|
|
37626
|
+
const plannedSteps = buildPlannedSteps(updateSubmodules);
|
|
37627
|
+
const base = {
|
|
37628
|
+
...nodeId ? { nodeId } : {},
|
|
37629
|
+
...meshId ? { meshId } : {},
|
|
37630
|
+
workspace,
|
|
37631
|
+
dryRun,
|
|
37632
|
+
updateSubmodules,
|
|
37633
|
+
plannedSteps,
|
|
37634
|
+
trigger
|
|
37635
|
+
};
|
|
37636
|
+
if (!workspace) {
|
|
37637
|
+
return block(base, "invalid_workspace", ["workspace_required"]);
|
|
37638
|
+
}
|
|
37639
|
+
const current = await getGitRepoStatus(workspace, {
|
|
37640
|
+
...STATUS_OPTIONS,
|
|
37641
|
+
submoduleIgnorePaths: args.submoduleIgnorePaths,
|
|
37642
|
+
timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
|
|
37643
|
+
});
|
|
37644
|
+
const earlyBlockers = collectPreflightBlockers(current, requestedBranch);
|
|
37645
|
+
if (earlyBlockers.length > 0) {
|
|
37646
|
+
const result2 = {
|
|
37647
|
+
...block(base, chooseBlockCode(current, earlyBlockers), earlyBlockers),
|
|
37648
|
+
current,
|
|
37649
|
+
finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(chooseBlockCode(current, earlyBlockers)))
|
|
37650
|
+
};
|
|
37651
|
+
await appendFastForwardLedger(result2, "blocked");
|
|
37652
|
+
return result2;
|
|
37653
|
+
}
|
|
37654
|
+
if (current.behind === 0) {
|
|
37655
|
+
const result2 = {
|
|
37656
|
+
...base,
|
|
37657
|
+
success: true,
|
|
37658
|
+
code: "already_up_to_date",
|
|
37659
|
+
allowed: true,
|
|
37660
|
+
willRun: false,
|
|
37661
|
+
executed: false,
|
|
37662
|
+
blockingReasons: [],
|
|
37663
|
+
current,
|
|
37664
|
+
preStatus: current,
|
|
37665
|
+
postStatus: current,
|
|
37666
|
+
finalBranchConvergenceState: buildConvergenceState(current, "up_to_date")
|
|
37667
|
+
};
|
|
37668
|
+
await appendFastForwardLedger(result2, "noop");
|
|
37669
|
+
return result2;
|
|
37670
|
+
}
|
|
37671
|
+
const ancestorCheck = await verifyHeadIsAncestorOfUpstream(workspace, current.upstream || "", args.timeoutMs);
|
|
37672
|
+
if (!ancestorCheck.ok) {
|
|
37673
|
+
const result2 = {
|
|
37674
|
+
...block(base, "non_fast_forward", ["head_is_not_ancestor_of_upstream"]),
|
|
37675
|
+
current,
|
|
37676
|
+
preStatus: current,
|
|
37677
|
+
operationError: ancestorCheck.error,
|
|
37678
|
+
finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
|
|
37679
|
+
};
|
|
37680
|
+
await appendFastForwardLedger(result2, "blocked");
|
|
37681
|
+
return result2;
|
|
37682
|
+
}
|
|
37683
|
+
if (dryRun) {
|
|
37684
|
+
const result2 = {
|
|
37685
|
+
...base,
|
|
37686
|
+
success: true,
|
|
37687
|
+
code: "fast_forward_available",
|
|
37688
|
+
allowed: true,
|
|
37689
|
+
willRun: false,
|
|
37690
|
+
executed: false,
|
|
37691
|
+
blockingReasons: [],
|
|
37692
|
+
current,
|
|
37693
|
+
preStatus: current,
|
|
37694
|
+
finalBranchConvergenceState: buildConvergenceState(current, "fast_forward_available")
|
|
37695
|
+
};
|
|
37696
|
+
await appendFastForwardLedger(result2, "dry_run");
|
|
37697
|
+
return result2;
|
|
37698
|
+
}
|
|
37699
|
+
try {
|
|
37700
|
+
await runGit(workspace, ["merge", "--ff-only", current.upstream || ""], { timeoutMs: args.timeoutMs ?? 3e4 });
|
|
37701
|
+
} catch (error48) {
|
|
37702
|
+
const result2 = {
|
|
37703
|
+
...block(base, "merge_ff_only_failed", ["merge_ff_only_failed"]),
|
|
37704
|
+
current,
|
|
37705
|
+
preStatus: current,
|
|
37706
|
+
operationError: formatGitError2(error48),
|
|
37707
|
+
finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
|
|
37708
|
+
};
|
|
37709
|
+
await appendFastForwardLedger(result2, "failed");
|
|
37710
|
+
return result2;
|
|
37711
|
+
}
|
|
37712
|
+
let postStatus = await getGitRepoStatus(workspace, {
|
|
37713
|
+
...STATUS_OPTIONS,
|
|
37714
|
+
submoduleIgnorePaths: args.submoduleIgnorePaths,
|
|
37715
|
+
timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
|
|
37716
|
+
});
|
|
37717
|
+
const submoduleIssues = collectSubmoduleBlockers(postStatus, "post");
|
|
37718
|
+
let submoduleFollowUpRequired = false;
|
|
37719
|
+
let operationError;
|
|
37720
|
+
if (submoduleIssues.length > 0) {
|
|
37721
|
+
if (updateSubmodules) {
|
|
37722
|
+
try {
|
|
37723
|
+
await runGit(workspace, ["submodule", "update", "--init", "--recursive"], { timeoutMs: args.timeoutMs ?? 6e4 });
|
|
37724
|
+
postStatus = await getGitRepoStatus(workspace, {
|
|
37725
|
+
...STATUS_OPTIONS,
|
|
37726
|
+
submoduleIgnorePaths: args.submoduleIgnorePaths,
|
|
37727
|
+
timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
|
|
37728
|
+
});
|
|
37729
|
+
} catch (error48) {
|
|
37730
|
+
operationError = formatGitError2(error48);
|
|
37731
|
+
}
|
|
37732
|
+
} else {
|
|
37733
|
+
submoduleFollowUpRequired = true;
|
|
37734
|
+
}
|
|
37735
|
+
}
|
|
37736
|
+
const postBlockers = collectPostExecutionBlockers(postStatus);
|
|
37737
|
+
if (operationError) postBlockers.push("submodule_update_failed");
|
|
37738
|
+
if (submoduleFollowUpRequired) postBlockers.push("submodule_update_required");
|
|
37739
|
+
const success2 = postBlockers.length === 0 || submoduleFollowUpRequired;
|
|
37740
|
+
const code = postBlockers.length === 0 ? "fast_forward_applied" : submoduleFollowUpRequired ? "fast_forward_applied_submodule_update_required" : "post_verify_failed";
|
|
37741
|
+
const result = {
|
|
37742
|
+
...base,
|
|
37743
|
+
success: success2,
|
|
37744
|
+
code,
|
|
37745
|
+
allowed: true,
|
|
37746
|
+
willRun: true,
|
|
37747
|
+
executed: true,
|
|
37748
|
+
blockingReasons: postBlockers,
|
|
37749
|
+
current,
|
|
37750
|
+
preStatus: current,
|
|
37751
|
+
postStatus,
|
|
37752
|
+
...operationError ? { operationError } : {},
|
|
37753
|
+
finalBranchConvergenceState: buildConvergenceState(
|
|
37754
|
+
postStatus,
|
|
37755
|
+
postBlockers.length === 0 ? "fast_forwarded" : submoduleFollowUpRequired ? "follow_up_required" : "post_verify_failed"
|
|
37756
|
+
)
|
|
37757
|
+
};
|
|
37758
|
+
await appendFastForwardLedger(result, success2 ? "executed" : "failed");
|
|
37759
|
+
return result;
|
|
37760
|
+
}
|
|
37761
|
+
function buildPlannedSteps(updateSubmodules) {
|
|
37762
|
+
const steps = [
|
|
37763
|
+
{
|
|
37764
|
+
operation: "refresh_upstream",
|
|
37765
|
+
description: "Refresh the tracked upstream remote ref before trusting ahead/behind state.",
|
|
37766
|
+
safe: true,
|
|
37767
|
+
willMutateWorktree: false
|
|
37768
|
+
},
|
|
37769
|
+
{
|
|
37770
|
+
operation: "verify_clean_worktree",
|
|
37771
|
+
description: "Require clean staged/modified/untracked/deleted/renamed/conflict/stash/submodule state.",
|
|
37772
|
+
safe: true,
|
|
37773
|
+
willMutateWorktree: false
|
|
37774
|
+
},
|
|
37775
|
+
{
|
|
37776
|
+
operation: "verify_fast_forward",
|
|
37777
|
+
description: "Require ahead=0, behind>0, and HEAD to be an ancestor of the upstream ref.",
|
|
37778
|
+
safe: true,
|
|
37779
|
+
willMutateWorktree: false
|
|
37780
|
+
},
|
|
37781
|
+
{
|
|
37782
|
+
operation: "merge_ff_only",
|
|
37783
|
+
description: "Apply git merge --ff-only against the tracked upstream; no force, reset, rebase, push, or deploy.",
|
|
37784
|
+
safe: true,
|
|
37785
|
+
willMutateWorktree: true
|
|
37786
|
+
}
|
|
37787
|
+
];
|
|
37788
|
+
if (updateSubmodules) {
|
|
37789
|
+
steps.push({
|
|
37790
|
+
operation: "submodule_update",
|
|
37791
|
+
description: "If the fast-forward changes gitlinks, run git submodule update --init --recursive and re-verify submodules.",
|
|
37792
|
+
safe: true,
|
|
37793
|
+
willMutateWorktree: true
|
|
37794
|
+
});
|
|
37795
|
+
}
|
|
37796
|
+
steps.push({
|
|
37797
|
+
operation: "verify_post_status",
|
|
37798
|
+
description: "Re-read daemon-owned git status and report final branch convergence state.",
|
|
37799
|
+
safe: true,
|
|
37800
|
+
willMutateWorktree: false
|
|
37801
|
+
});
|
|
37802
|
+
return steps;
|
|
37803
|
+
}
|
|
37804
|
+
function collectPreflightBlockers(status, requestedBranch) {
|
|
37805
|
+
const blockers = [];
|
|
37806
|
+
if (!status.isGitRepo) blockers.push("not_git_repo");
|
|
37807
|
+
if (!status.branch) blockers.push("detached_head_or_unknown_branch");
|
|
37808
|
+
if (requestedBranch && status.branch !== requestedBranch) blockers.push("branch_mismatch");
|
|
37809
|
+
if (!status.upstream) blockers.push("upstream_missing");
|
|
37810
|
+
if (status.upstreamStatus !== "fresh") blockers.push("upstream_not_fresh");
|
|
37811
|
+
if (status.hasConflicts) blockers.push("conflicts_present");
|
|
37812
|
+
if (status.staged > 0) blockers.push("staged_changes_present");
|
|
37813
|
+
if (status.modified > 0) blockers.push("modified_changes_present");
|
|
37814
|
+
if (status.untracked > 0) blockers.push("untracked_changes_present");
|
|
37815
|
+
if (status.deleted > 0) blockers.push("deleted_changes_present");
|
|
37816
|
+
if (status.renamed > 0) blockers.push("renamed_changes_present");
|
|
37817
|
+
if (status.stashCount > 0) blockers.push("stash_entries_present");
|
|
37818
|
+
blockers.push(...collectSubmoduleBlockers(status, "pre"));
|
|
37819
|
+
if (status.ahead > 0 && status.behind > 0) {
|
|
37820
|
+
blockers.push("branch_diverged_from_upstream");
|
|
37821
|
+
blockers.push("branch_has_local_commits");
|
|
37822
|
+
} else if (status.ahead > 0) blockers.push("branch_has_local_commits");
|
|
37823
|
+
return blockers;
|
|
37824
|
+
}
|
|
37825
|
+
function collectPostExecutionBlockers(status) {
|
|
37826
|
+
const blockers = [];
|
|
37827
|
+
if (!status.isGitRepo) blockers.push("post_not_git_repo");
|
|
37828
|
+
if (status.hasConflicts) blockers.push("post_conflicts_present");
|
|
37829
|
+
if (status.ahead !== 0) blockers.push("post_branch_ahead");
|
|
37830
|
+
if (status.behind !== 0) blockers.push("post_branch_still_behind");
|
|
37831
|
+
if (status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0) {
|
|
37832
|
+
blockers.push("post_working_tree_not_clean");
|
|
37833
|
+
}
|
|
37834
|
+
if (status.stashCount > 0) blockers.push("post_stash_entries_present");
|
|
37835
|
+
blockers.push(...collectSubmoduleBlockers(status, "post"));
|
|
37836
|
+
return blockers;
|
|
37837
|
+
}
|
|
37838
|
+
function collectSubmoduleBlockers(status, phase) {
|
|
37839
|
+
const submodules = Array.isArray(status.submodules) ? status.submodules : [];
|
|
37840
|
+
const blockers = [];
|
|
37841
|
+
for (const submodule of submodules) {
|
|
37842
|
+
if (submodule.error) blockers.push(`${phase}_submodule_status_error:${submodule.path}`);
|
|
37843
|
+
if (submodule.dirty) blockers.push(`${phase}_submodule_dirty:${submodule.path}`);
|
|
37844
|
+
if (submodule.outOfSync) blockers.push(`${phase}_submodule_out_of_sync:${submodule.path}`);
|
|
37845
|
+
}
|
|
37846
|
+
return blockers;
|
|
37847
|
+
}
|
|
37848
|
+
function chooseBlockCode(status, blockers) {
|
|
37849
|
+
if (blockers.includes("not_git_repo")) return "not_git_repo";
|
|
37850
|
+
if (blockers.includes("branch_mismatch")) return "branch_mismatch";
|
|
37851
|
+
if (blockers.includes("upstream_missing")) return "upstream_missing";
|
|
37852
|
+
if (blockers.includes("upstream_not_fresh")) return "upstream_not_fresh";
|
|
37853
|
+
if (blockers.some((reason) => reason.includes("submodule"))) return "submodule_not_clean";
|
|
37854
|
+
if (blockers.includes("branch_diverged_from_upstream")) return "branch_diverged";
|
|
37855
|
+
if (blockers.includes("branch_has_local_commits") || status.ahead > 0) return "branch_ahead";
|
|
37856
|
+
if (blockers.some((reason) => reason.includes("changes") || reason.includes("conflicts") || reason.includes("stash"))) return "dirty_worktree";
|
|
37857
|
+
return "preflight_blocked";
|
|
37858
|
+
}
|
|
37859
|
+
function codeToConvergenceStatus(code) {
|
|
37860
|
+
if (code === "branch_diverged" || code === "branch_ahead" || code === "non_fast_forward") return "not_mergeable";
|
|
37861
|
+
if (code === "dirty_worktree" || code === "submodule_not_clean") return "blocked_review";
|
|
37862
|
+
return "blocked";
|
|
37863
|
+
}
|
|
37864
|
+
async function verifyHeadIsAncestorOfUpstream(workspace, upstream, timeoutMs) {
|
|
37865
|
+
if (!upstream) return { ok: false, error: "missing upstream" };
|
|
37866
|
+
try {
|
|
37867
|
+
await runGit(workspace, ["merge-base", "--is-ancestor", "HEAD", upstream], { timeoutMs: timeoutMs ?? 15e3 });
|
|
37868
|
+
return { ok: true };
|
|
37869
|
+
} catch (error48) {
|
|
37870
|
+
return { ok: false, error: formatGitError2(error48) };
|
|
37871
|
+
}
|
|
37872
|
+
}
|
|
37873
|
+
function block(base, code, blockingReasons) {
|
|
37874
|
+
const normalizedReasons = normalizeBlockingReasons(blockingReasons);
|
|
37875
|
+
return {
|
|
37876
|
+
...base,
|
|
37877
|
+
success: false,
|
|
37878
|
+
code,
|
|
37879
|
+
allowed: false,
|
|
37880
|
+
willRun: false,
|
|
37881
|
+
executed: false,
|
|
37882
|
+
blockingReasons: normalizedReasons
|
|
37883
|
+
};
|
|
37884
|
+
}
|
|
37885
|
+
function normalizeBlockingReasons(reasons) {
|
|
37886
|
+
const normalized = /* @__PURE__ */ new Set();
|
|
37887
|
+
for (const reason of reasons) {
|
|
37888
|
+
normalized.add(reason);
|
|
37889
|
+
}
|
|
37890
|
+
if ([
|
|
37891
|
+
"conflicts_present",
|
|
37892
|
+
"staged_changes_present",
|
|
37893
|
+
"modified_changes_present",
|
|
37894
|
+
"untracked_changes_present",
|
|
37895
|
+
"deleted_changes_present",
|
|
37896
|
+
"renamed_changes_present"
|
|
37897
|
+
].some((reason) => normalized.has(reason))) {
|
|
37898
|
+
normalized.add("working_tree_not_clean");
|
|
37899
|
+
}
|
|
37900
|
+
return Array.from(normalized);
|
|
37901
|
+
}
|
|
37902
|
+
function buildConvergenceState(status, convergenceStatus) {
|
|
37903
|
+
return {
|
|
37904
|
+
status: convergenceStatus,
|
|
37905
|
+
branch: status.branch,
|
|
37906
|
+
headCommit: status.headCommit,
|
|
37907
|
+
upstream: status.upstream,
|
|
37908
|
+
ahead: status.ahead,
|
|
37909
|
+
behind: status.behind,
|
|
37910
|
+
dirty: status.staged + status.modified + status.untracked + status.deleted + status.renamed > 0 || status.hasConflicts,
|
|
37911
|
+
stashCount: status.stashCount,
|
|
37912
|
+
submodules: summarizeSubmodules(status.submodules)
|
|
37913
|
+
};
|
|
37914
|
+
}
|
|
37915
|
+
function summarizeSubmodules(submodules) {
|
|
37916
|
+
return (submodules || []).map((submodule) => ({
|
|
37917
|
+
path: submodule.path,
|
|
37918
|
+
commit: submodule.commit,
|
|
37919
|
+
dirty: submodule.dirty,
|
|
37920
|
+
outOfSync: submodule.outOfSync,
|
|
37921
|
+
...submodule.error ? { error: submodule.error } : {}
|
|
37922
|
+
}));
|
|
37923
|
+
}
|
|
37924
|
+
function normalizeOptionalString(value) {
|
|
37925
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
37926
|
+
}
|
|
37927
|
+
function formatGitError2(error48) {
|
|
37928
|
+
if (error48 instanceof GitCommandError) {
|
|
37929
|
+
return error48.stderr || error48.stdout || error48.message;
|
|
37930
|
+
}
|
|
37931
|
+
if (error48 instanceof Error) return error48.message;
|
|
37932
|
+
return String(error48);
|
|
37933
|
+
}
|
|
37934
|
+
async function appendFastForwardLedger(result, outcome) {
|
|
37935
|
+
if (!result.meshId) return;
|
|
37936
|
+
try {
|
|
37937
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
37938
|
+
appendLedgerEntry2(result.meshId, {
|
|
37939
|
+
kind: "direct_fast_forward",
|
|
37940
|
+
...result.nodeId ? { nodeId: result.nodeId } : {},
|
|
37941
|
+
payload: {
|
|
37942
|
+
operation: "mesh_fast_forward_node",
|
|
37943
|
+
trigger: result.trigger || "manual",
|
|
37944
|
+
outcome,
|
|
37945
|
+
code: result.code,
|
|
37946
|
+
workspace: result.workspace,
|
|
37947
|
+
allowed: result.allowed,
|
|
37948
|
+
dryRun: result.dryRun,
|
|
37949
|
+
willRun: result.willRun,
|
|
37950
|
+
executed: result.executed,
|
|
37951
|
+
branch: result.postStatus?.branch ?? result.current?.branch,
|
|
37952
|
+
upstream: result.postStatus?.upstream ?? result.current?.upstream,
|
|
37953
|
+
before: result.current ? {
|
|
37954
|
+
headCommit: result.current.headCommit,
|
|
37955
|
+
ahead: result.current.ahead,
|
|
37956
|
+
behind: result.current.behind
|
|
37957
|
+
} : void 0,
|
|
37958
|
+
after: result.postStatus ? {
|
|
37959
|
+
headCommit: result.postStatus.headCommit,
|
|
37960
|
+
ahead: result.postStatus.ahead,
|
|
37961
|
+
behind: result.postStatus.behind
|
|
37962
|
+
} : void 0,
|
|
37963
|
+
blockingReasons: result.blockingReasons
|
|
37964
|
+
}
|
|
37965
|
+
});
|
|
37966
|
+
} catch (error48) {
|
|
37967
|
+
result.ledgerError = error48 instanceof Error ? error48.message : String(error48);
|
|
37968
|
+
}
|
|
37969
|
+
}
|
|
37970
|
+
var STATUS_OPTIONS;
|
|
37971
|
+
var init_mesh_fast_forward = __esm2({
|
|
37972
|
+
"src/mesh/mesh-fast-forward.ts"() {
|
|
37973
|
+
"use strict";
|
|
37974
|
+
init_git_status();
|
|
37975
|
+
init_git_executor();
|
|
37976
|
+
STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15e3 };
|
|
37977
|
+
}
|
|
37978
|
+
});
|
|
37352
37979
|
function loadDatabaseCtor() {
|
|
37353
37980
|
if (DatabaseCtor) return DatabaseCtor;
|
|
37354
37981
|
const runtimeRequire = typeof require === "function" ? require : (0, import_module.createRequire)(import_meta.url);
|
|
@@ -37374,6 +38001,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
37374
38001
|
import_path7 = require("path");
|
|
37375
38002
|
import_module = require("module");
|
|
37376
38003
|
init_mesh_ledger();
|
|
38004
|
+
init_mesh_work_queue();
|
|
37377
38005
|
import_meta = {};
|
|
37378
38006
|
BeadsDB = class _BeadsDB {
|
|
37379
38007
|
static instance;
|
|
@@ -37595,25 +38223,29 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
37595
38223
|
return row !== void 0;
|
|
37596
38224
|
}
|
|
37597
38225
|
// O(1) claim: transaction ensures only one session claims a pending task
|
|
37598
|
-
claimNextQueueTask(meshId, nodeId, sessionId) {
|
|
38226
|
+
claimNextQueueTask(meshId, nodeId, sessionId, capabilityTags = []) {
|
|
37599
38227
|
return this.transaction(() => {
|
|
37600
38228
|
this.ensureLegacyQueueMigrated(meshId);
|
|
37601
38229
|
if (this.hasActiveAssignment(meshId, sessionId, nodeId)) return null;
|
|
37602
|
-
const
|
|
38230
|
+
const rows = [
|
|
38231
|
+
...this.db.prepare(`
|
|
37603
38232
|
SELECT payload FROM mesh_queue
|
|
37604
38233
|
WHERE mesh_id = ? AND status = 'pending' AND target_session_id = ?
|
|
37605
|
-
ORDER BY created_at ASC
|
|
37606
|
-
`).
|
|
38234
|
+
ORDER BY created_at ASC
|
|
38235
|
+
`).all(meshId, sessionId),
|
|
38236
|
+
...this.db.prepare(`
|
|
37607
38237
|
SELECT payload FROM mesh_queue
|
|
37608
38238
|
WHERE mesh_id = ? AND status = 'pending' AND target_node_id = ? AND target_session_id IS NULL
|
|
37609
|
-
ORDER BY created_at ASC
|
|
37610
|
-
`).
|
|
38239
|
+
ORDER BY created_at ASC
|
|
38240
|
+
`).all(meshId, nodeId),
|
|
38241
|
+
...this.db.prepare(`
|
|
37611
38242
|
SELECT payload FROM mesh_queue
|
|
37612
38243
|
WHERE mesh_id = ? AND status = 'pending' AND target_node_id IS NULL AND target_session_id IS NULL
|
|
37613
|
-
ORDER BY created_at ASC
|
|
37614
|
-
`).
|
|
37615
|
-
|
|
37616
|
-
const entry = JSON.parse(row.payload);
|
|
38244
|
+
ORDER BY created_at ASC
|
|
38245
|
+
`).all(meshId)
|
|
38246
|
+
];
|
|
38247
|
+
const entry = rows.map((row) => JSON.parse(row.payload)).find((candidate) => nodeSatisfiesRequiredTags(candidate.requiredTags, capabilityTags));
|
|
38248
|
+
if (!entry) return null;
|
|
37617
38249
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
37618
38250
|
entry.status = "assigned";
|
|
37619
38251
|
entry.assignedNodeId = nodeId;
|
|
@@ -37759,6 +38391,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
37759
38391
|
__clearMeshQueueForTests: () => __clearMeshQueueForTests,
|
|
37760
38392
|
__replaceMeshQueueForTests: () => __replaceMeshQueueForTests,
|
|
37761
38393
|
__resetBeadsDBForTests: () => __resetBeadsDBForTests,
|
|
38394
|
+
buildMeshNodeCapabilityTags: () => buildMeshNodeCapabilityTags,
|
|
37762
38395
|
cancelTask: () => cancelTask,
|
|
37763
38396
|
claimNextTask: () => claimNextTask,
|
|
37764
38397
|
cleanupTerminalDirectDispatches: () => cleanupTerminalDirectDispatches,
|
|
@@ -37769,6 +38402,8 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
37769
38402
|
getQueue: () => getQueue,
|
|
37770
38403
|
insertDirectDispatch: () => insertDirectDispatch,
|
|
37771
38404
|
markStaleDirectDispatches: () => markStaleDirectDispatches,
|
|
38405
|
+
nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
|
|
38406
|
+
normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
|
|
37772
38407
|
normalizeMeshTaskMode: () => normalizeMeshTaskMode,
|
|
37773
38408
|
recordTaskAutoLaunch: () => recordTaskAutoLaunch,
|
|
37774
38409
|
requeueTask: () => requeueTask,
|
|
@@ -37803,6 +38438,35 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
37803
38438
|
]
|
|
37804
38439
|
};
|
|
37805
38440
|
}
|
|
38441
|
+
function normalizeMeshCapabilityTags(value) {
|
|
38442
|
+
if (!Array.isArray(value)) return [];
|
|
38443
|
+
const seen = /* @__PURE__ */ new Set();
|
|
38444
|
+
return value.map((tag) => typeof tag === "string" ? tag.trim() : "").filter(Boolean).filter((tag) => {
|
|
38445
|
+
if (seen.has(tag)) return false;
|
|
38446
|
+
seen.add(tag);
|
|
38447
|
+
return true;
|
|
38448
|
+
});
|
|
38449
|
+
}
|
|
38450
|
+
function firstProviderPriority(policy) {
|
|
38451
|
+
const raw = policy && typeof policy === "object" && !Array.isArray(policy) ? policy.providerPriority : void 0;
|
|
38452
|
+
if (!Array.isArray(raw)) return void 0;
|
|
38453
|
+
return raw.find((type) => typeof type === "string" && type.trim())?.trim();
|
|
38454
|
+
}
|
|
38455
|
+
function buildMeshNodeCapabilityTags(node, providerType) {
|
|
38456
|
+
const provider = typeof providerType === "string" && providerType.trim() ? providerType.trim() : firstProviderPriority(node?.policy);
|
|
38457
|
+
return normalizeMeshCapabilityTags([
|
|
38458
|
+
...Array.isArray(node?.capabilities) ? node.capabilities : [],
|
|
38459
|
+
`os=${process.platform}`,
|
|
38460
|
+
`arch=${process.arch}`,
|
|
38461
|
+
...provider ? [`provider=${provider}`] : []
|
|
38462
|
+
]);
|
|
38463
|
+
}
|
|
38464
|
+
function nodeSatisfiesRequiredTags(requiredTags, capabilityTags) {
|
|
38465
|
+
const required2 = normalizeMeshCapabilityTags(requiredTags);
|
|
38466
|
+
if (required2.length === 0) return true;
|
|
38467
|
+
const available = new Set(normalizeMeshCapabilityTags(capabilityTags));
|
|
38468
|
+
return required2.every((tag) => available.has(tag));
|
|
38469
|
+
}
|
|
37806
38470
|
function withQueueLock(_meshId, fn) {
|
|
37807
38471
|
return BeadsDB.getInstance().transaction(fn);
|
|
37808
38472
|
}
|
|
@@ -37820,6 +38484,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
37820
38484
|
taskMode: modeValidation.taskMode,
|
|
37821
38485
|
targetNodeId: opts?.targetNodeId,
|
|
37822
38486
|
targetSessionId: opts?.targetSessionId,
|
|
38487
|
+
requiredTags: normalizeMeshCapabilityTags(opts?.requiredTags),
|
|
37823
38488
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
37824
38489
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
37825
38490
|
};
|
|
@@ -37832,8 +38497,8 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
37832
38497
|
function getMeshQueueRevision(meshId) {
|
|
37833
38498
|
return BeadsDB.getInstance().getQueueRevision(meshId);
|
|
37834
38499
|
}
|
|
37835
|
-
function claimNextTask(meshId, nodeId, sessionId) {
|
|
37836
|
-
return BeadsDB.getInstance().claimNextQueueTask(meshId, nodeId, sessionId);
|
|
38500
|
+
function claimNextTask(meshId, nodeId, sessionId, capabilityTags) {
|
|
38501
|
+
return BeadsDB.getInstance().claimNextQueueTask(meshId, nodeId, sessionId, capabilityTags);
|
|
37837
38502
|
}
|
|
37838
38503
|
function updateTaskStatus(meshId, taskId, status, opts) {
|
|
37839
38504
|
requireMeshHostQueueOwner(opts);
|
|
@@ -38129,6 +38794,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
38129
38794
|
});
|
|
38130
38795
|
var mesh_events_exports = {};
|
|
38131
38796
|
__export2(mesh_events_exports, {
|
|
38797
|
+
__resetIdleAutoFastForwardForTests: () => __resetIdleAutoFastForwardForTests,
|
|
38132
38798
|
clearPendingMeshCoordinatorEvents: () => clearPendingMeshCoordinatorEvents,
|
|
38133
38799
|
drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
|
|
38134
38800
|
getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
|
|
@@ -38149,6 +38815,9 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
38149
38815
|
function readWorkerResultMetadata(event) {
|
|
38150
38816
|
return readRecord2(event.workerResult) || readRecord2(event.meshWorkerResult) || readRecord2(event.structuredResult);
|
|
38151
38817
|
}
|
|
38818
|
+
function __resetIdleAutoFastForwardForTests() {
|
|
38819
|
+
idleAutoFastForwardLastAttempt.clear();
|
|
38820
|
+
}
|
|
38152
38821
|
function sweepExpiredRemoteIdleSessions() {
|
|
38153
38822
|
const now = Date.now();
|
|
38154
38823
|
for (const [key, session] of remoteIdleSessions) {
|
|
@@ -38574,13 +39243,14 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
38574
39243
|
};
|
|
38575
39244
|
}
|
|
38576
39245
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
38577
|
-
const
|
|
39246
|
+
const mesh = getMeshWithCache(components, meshId);
|
|
39247
|
+
const node = mesh?.nodes.find((n) => n.id === nodeId);
|
|
39248
|
+
const capabilityTags = buildMeshNodeCapabilityTags(node, providerType);
|
|
39249
|
+
const task = claimNextTask(meshId, nodeId, sessionId, capabilityTags);
|
|
38578
39250
|
if (!task) {
|
|
38579
39251
|
return false;
|
|
38580
39252
|
}
|
|
38581
39253
|
LOG2.info("MeshQueue", `Node ${nodeId} (${sessionId}) pulled task ${task.id}`);
|
|
38582
|
-
const mesh = getMeshWithCache(components, meshId);
|
|
38583
|
-
const node = mesh?.nodes.find((n) => n.id === nodeId);
|
|
38584
39254
|
if (node?.daemonId && components.dispatchMeshCommand) {
|
|
38585
39255
|
const isLocalNode = components.cliManager.adapters.has(sessionId);
|
|
38586
39256
|
if (!isLocalNode) {
|
|
@@ -38886,6 +39556,55 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
38886
39556
|
}
|
|
38887
39557
|
await maybeAutoLaunchOneQueueSession(components, meshId, mesh);
|
|
38888
39558
|
}
|
|
39559
|
+
async function maybeAutoFastForwardIdleNode(components, args) {
|
|
39560
|
+
const mesh = getMeshWithCache(components, args.meshId);
|
|
39561
|
+
const node = mesh?.nodes?.find((candidate) => candidate?.id === args.nodeId || candidate?.nodeId === args.nodeId);
|
|
39562
|
+
const workspace = readNonEmptyString2(node?.workspace);
|
|
39563
|
+
if (!workspace) return;
|
|
39564
|
+
if (!(0, import_fs9.existsSync)(workspace)) return;
|
|
39565
|
+
const throttleKey = `${args.meshId}:${args.nodeId}`;
|
|
39566
|
+
const now = Date.now();
|
|
39567
|
+
const lastAttempt = idleAutoFastForwardLastAttempt.get(throttleKey) || 0;
|
|
39568
|
+
if (now - lastAttempt < IDLE_AUTO_FAST_FORWARD_THROTTLE_MS) return;
|
|
39569
|
+
idleAutoFastForwardLastAttempt.set(throttleKey, now);
|
|
39570
|
+
const submoduleIgnorePaths = Array.isArray(node?.policy?.submoduleIgnorePaths) ? node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
|
|
39571
|
+
try {
|
|
39572
|
+
const dryRun = await fastForwardMeshNode({
|
|
39573
|
+
meshId: args.meshId,
|
|
39574
|
+
nodeId: args.nodeId,
|
|
39575
|
+
workspace,
|
|
39576
|
+
execute: false,
|
|
39577
|
+
dryRun: true,
|
|
39578
|
+
updateSubmodules: false,
|
|
39579
|
+
submoduleIgnorePaths,
|
|
39580
|
+
trigger: "idle_auto"
|
|
39581
|
+
});
|
|
39582
|
+
if (!dryRun || dryRun.code !== "fast_forward_available" || dryRun.allowed !== true) return;
|
|
39583
|
+
await fastForwardMeshNode({
|
|
39584
|
+
meshId: args.meshId,
|
|
39585
|
+
nodeId: args.nodeId,
|
|
39586
|
+
workspace,
|
|
39587
|
+
execute: true,
|
|
39588
|
+
dryRun: false,
|
|
39589
|
+
updateSubmodules: false,
|
|
39590
|
+
submoduleIgnorePaths,
|
|
39591
|
+
trigger: "idle_auto"
|
|
39592
|
+
});
|
|
39593
|
+
} catch (e) {
|
|
39594
|
+
LOG2.warn("MeshFastForward", `Idle auto fast-forward check failed for ${args.nodeId}: ${e?.message || e}`);
|
|
39595
|
+
}
|
|
39596
|
+
}
|
|
39597
|
+
function runIdleMaintenanceThenAssignQueue(components, args) {
|
|
39598
|
+
setImmediate(() => {
|
|
39599
|
+
maybeAutoFastForwardIdleNode(components, args).finally(() => {
|
|
39600
|
+
try {
|
|
39601
|
+
tryAssignQueueTask(components, args.meshId, args.nodeId, args.sessionId, args.providerType);
|
|
39602
|
+
} catch (e) {
|
|
39603
|
+
LOG2.warn("MeshQueue", `Failed to assign idle queue task after maintenance for ${args.nodeId}: ${e?.message || e}`);
|
|
39604
|
+
}
|
|
39605
|
+
});
|
|
39606
|
+
});
|
|
39607
|
+
}
|
|
38889
39608
|
function buildMeshSystemMessage(args) {
|
|
38890
39609
|
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
38891
39610
|
if (args.event === "agent:generating_completed") {
|
|
@@ -39107,9 +39826,7 @@ Next step: ${nextStep}`;
|
|
|
39107
39826
|
updateDirectDispatchStatus(args.meshId, sessionId, "completed");
|
|
39108
39827
|
setImmediate(() => cleanupTerminalDirectDispatches());
|
|
39109
39828
|
if (nodeId && providerType) {
|
|
39110
|
-
|
|
39111
|
-
tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
39112
|
-
});
|
|
39829
|
+
runIdleMaintenanceThenAssignQueue(components, { meshId: args.meshId, nodeId, sessionId, providerType });
|
|
39113
39830
|
}
|
|
39114
39831
|
}
|
|
39115
39832
|
} else if (args.event === "agent:ready") {
|
|
@@ -39163,8 +39880,14 @@ Next step: ${nextStep}`;
|
|
|
39163
39880
|
expiresAt: Date.now() + REMOTE_IDLE_SESSION_TTL_MS
|
|
39164
39881
|
});
|
|
39165
39882
|
setImmediate(() => {
|
|
39166
|
-
|
|
39167
|
-
|
|
39883
|
+
maybeAutoFastForwardIdleNode(components, { meshId: args.meshId, nodeId, sessionId, providerType }).finally(() => {
|
|
39884
|
+
try {
|
|
39885
|
+
const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
39886
|
+
if (assigned) remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
|
|
39887
|
+
} catch (e) {
|
|
39888
|
+
LOG2.warn("MeshQueue", `Failed to assign idle queue task after maintenance for ${nodeId}: ${e?.message || e}`);
|
|
39889
|
+
}
|
|
39890
|
+
});
|
|
39168
39891
|
});
|
|
39169
39892
|
}
|
|
39170
39893
|
} else if (args.event === "agent:generating_started") {
|
|
@@ -39446,6 +40169,8 @@ Next step: ${nextStep}`;
|
|
|
39446
40169
|
var remoteIdleSessions;
|
|
39447
40170
|
var meshByWorkspaceCache;
|
|
39448
40171
|
var MESH_WORKSPACE_CACHE_TTL_MS;
|
|
40172
|
+
var IDLE_AUTO_FAST_FORWARD_THROTTLE_MS;
|
|
40173
|
+
var idleAutoFastForwardLastAttempt;
|
|
39449
40174
|
var REFINE_TERMINAL_EVENTS;
|
|
39450
40175
|
var MAX_PENDING_EVENTS_BYTES;
|
|
39451
40176
|
var MAX_PENDING_EVENTS_KEEP;
|
|
@@ -39468,10 +40193,13 @@ Next step: ${nextStep}`;
|
|
|
39468
40193
|
init_mesh_ledger();
|
|
39469
40194
|
init_mesh_work_queue();
|
|
39470
40195
|
init_beads_db();
|
|
40196
|
+
init_mesh_fast_forward();
|
|
39471
40197
|
REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
|
|
39472
40198
|
remoteIdleSessions = /* @__PURE__ */ new Map();
|
|
39473
40199
|
meshByWorkspaceCache = /* @__PURE__ */ new Map();
|
|
39474
40200
|
MESH_WORKSPACE_CACHE_TTL_MS = 5e3;
|
|
40201
|
+
IDLE_AUTO_FAST_FORWARD_THROTTLE_MS = 30 * 60 * 1e3;
|
|
40202
|
+
idleAutoFastForwardLastAttempt = /* @__PURE__ */ new Map();
|
|
39475
40203
|
REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
|
|
39476
40204
|
MAX_PENDING_EVENTS_BYTES = 100 * 1024;
|
|
39477
40205
|
MAX_PENDING_EVENTS_KEEP = 50;
|
|
@@ -46972,6 +47700,7 @@ ${lastSnapshot}`;
|
|
|
46972
47700
|
buildMeshHostRequiredFailure: () => buildMeshHostRequiredFailure,
|
|
46973
47701
|
buildMeshLedgerReconciliationEvidence: () => buildMeshLedgerReconciliationEvidence,
|
|
46974
47702
|
buildMeshLedgerReplicaEvidence: () => buildMeshLedgerReplicaEvidence,
|
|
47703
|
+
buildMeshNodeCapabilityTags: () => buildMeshNodeCapabilityTags,
|
|
46975
47704
|
buildP2pRelayFailurePayload: () => buildP2pRelayFailurePayload,
|
|
46976
47705
|
buildPinnedGlobalInstallCommand: () => buildPinnedGlobalInstallCommand,
|
|
46977
47706
|
buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
|
|
@@ -47099,6 +47828,7 @@ ${lastSnapshot}`;
|
|
|
47099
47828
|
maybeRunDaemonUpgradeHelperFromEnv: () => maybeRunDaemonUpgradeHelperFromEnv2,
|
|
47100
47829
|
namedKeyToAnsi: () => namedKeyToAnsi,
|
|
47101
47830
|
namedKeysToAnsi: () => namedKeysToAnsi,
|
|
47831
|
+
nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
|
|
47102
47832
|
normalizeActiveChatData: () => normalizeActiveChatData,
|
|
47103
47833
|
normalizeChatMessage: () => normalizeChatMessage,
|
|
47104
47834
|
normalizeChatMessageKind: () => normalizeChatMessageKind,
|
|
@@ -47110,6 +47840,7 @@ ${lastSnapshot}`;
|
|
|
47110
47840
|
normalizeInteractivePrompt: () => normalizeInteractivePrompt,
|
|
47111
47841
|
normalizeInteractivePromptResponse: () => normalizeInteractivePromptResponse2,
|
|
47112
47842
|
normalizeManagedStatus: () => normalizeManagedStatus,
|
|
47843
|
+
normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
|
|
47113
47844
|
normalizeMeshDaemonRole: () => normalizeMeshDaemonRole,
|
|
47114
47845
|
normalizeMeshTaskMode: () => normalizeMeshTaskMode,
|
|
47115
47846
|
normalizeMeshWorkerResult: () => normalizeMeshWorkerResult,
|
|
@@ -47168,7 +47899,6 @@ ${lastSnapshot}`;
|
|
|
47168
47899
|
startLocalIpcServer: () => startLocalIpcServer2,
|
|
47169
47900
|
suggestMeshRefineConfig: () => suggestMeshRefineConfig,
|
|
47170
47901
|
summarizeGitStatus: () => summarizeGitStatus,
|
|
47171
|
-
syncMeshes: () => syncMeshes,
|
|
47172
47902
|
triggerMeshQueue: () => triggerMeshQueue,
|
|
47173
47903
|
unregisterMeshCoordinator: () => unregisterMeshCoordinator,
|
|
47174
47904
|
updateConfig: () => updateConfig,
|
|
@@ -47405,256 +48135,7 @@ ${lastSnapshot}`;
|
|
|
47405
48135
|
}
|
|
47406
48136
|
init_repo_mesh_types();
|
|
47407
48137
|
init_git_executor();
|
|
47408
|
-
|
|
47409
|
-
async function getGitRepoStatus(workspace, options = {}) {
|
|
47410
|
-
const lastCheckedAt = Date.now();
|
|
47411
|
-
const includeSubmodules = options.includeSubmodules !== false;
|
|
47412
|
-
try {
|
|
47413
|
-
const repo = await resolveGitRepository(workspace, options);
|
|
47414
|
-
let parsed = await readPorcelainStatus(repo, options);
|
|
47415
|
-
let upstreamProbe = getInitialUpstreamProbe(parsed);
|
|
47416
|
-
if (options.refreshUpstream) {
|
|
47417
|
-
upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
|
|
47418
|
-
if (upstreamProbe.upstreamStatus === "fresh") {
|
|
47419
|
-
parsed = await readPorcelainStatus(repo, options);
|
|
47420
|
-
}
|
|
47421
|
-
}
|
|
47422
|
-
const head = await readHead(repo, options);
|
|
47423
|
-
const stashCount = await readStashCount(repo, options);
|
|
47424
|
-
let submodules;
|
|
47425
|
-
if (includeSubmodules) {
|
|
47426
|
-
submodules = await getSubmoduleStatuses(repo, options);
|
|
47427
|
-
}
|
|
47428
|
-
return {
|
|
47429
|
-
workspace: repo.workspace,
|
|
47430
|
-
repoRoot: repo.repoRoot,
|
|
47431
|
-
isGitRepo: true,
|
|
47432
|
-
branch: parsed.branch,
|
|
47433
|
-
headCommit: head.commit,
|
|
47434
|
-
headMessage: head.message,
|
|
47435
|
-
upstream: parsed.upstream,
|
|
47436
|
-
upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
|
|
47437
|
-
upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
|
|
47438
|
-
upstreamFetchError: upstreamProbe.upstreamFetchError,
|
|
47439
|
-
ahead: parsed.ahead,
|
|
47440
|
-
behind: parsed.behind,
|
|
47441
|
-
staged: parsed.staged,
|
|
47442
|
-
modified: parsed.modified,
|
|
47443
|
-
untracked: parsed.untracked,
|
|
47444
|
-
deleted: parsed.deleted,
|
|
47445
|
-
renamed: parsed.renamed,
|
|
47446
|
-
hasConflicts: parsed.conflictFiles.length > 0,
|
|
47447
|
-
conflictFiles: parsed.conflictFiles,
|
|
47448
|
-
stashCount,
|
|
47449
|
-
lastCheckedAt,
|
|
47450
|
-
submodules
|
|
47451
|
-
};
|
|
47452
|
-
} catch (error48) {
|
|
47453
|
-
if (error48 instanceof GitCommandError) {
|
|
47454
|
-
return emptyStatus(workspace, lastCheckedAt, error48);
|
|
47455
|
-
}
|
|
47456
|
-
return emptyStatus(
|
|
47457
|
-
workspace,
|
|
47458
|
-
lastCheckedAt,
|
|
47459
|
-
new GitCommandError("git_command_failed", "Failed to read Git status", { cause: error48 })
|
|
47460
|
-
);
|
|
47461
|
-
}
|
|
47462
|
-
}
|
|
47463
|
-
async function readPorcelainStatus(repo, options) {
|
|
47464
|
-
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
47465
|
-
return parsePorcelainV2Status(statusOutput.stdout);
|
|
47466
|
-
}
|
|
47467
|
-
function getInitialUpstreamProbe(parsed) {
|
|
47468
|
-
return {
|
|
47469
|
-
upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
|
|
47470
|
-
};
|
|
47471
|
-
}
|
|
47472
|
-
async function refreshTrackedUpstream(repo, parsed, options) {
|
|
47473
|
-
if (!parsed.upstream || !parsed.branch) {
|
|
47474
|
-
return { upstreamStatus: "no_upstream" };
|
|
47475
|
-
}
|
|
47476
|
-
const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
|
|
47477
|
-
if (!remoteName) {
|
|
47478
|
-
return {
|
|
47479
|
-
upstreamStatus: "stale",
|
|
47480
|
-
upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
|
|
47481
|
-
};
|
|
47482
|
-
}
|
|
47483
|
-
try {
|
|
47484
|
-
await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
|
|
47485
|
-
return {
|
|
47486
|
-
upstreamStatus: "fresh",
|
|
47487
|
-
upstreamFetchedAt: Date.now()
|
|
47488
|
-
};
|
|
47489
|
-
} catch (error48) {
|
|
47490
|
-
return {
|
|
47491
|
-
upstreamStatus: "stale",
|
|
47492
|
-
upstreamFetchError: formatGitError(error48)
|
|
47493
|
-
};
|
|
47494
|
-
}
|
|
47495
|
-
}
|
|
47496
|
-
async function readBranchRemote(repo, branch, options) {
|
|
47497
|
-
try {
|
|
47498
|
-
const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
|
|
47499
|
-
return result.stdout.trim() || null;
|
|
47500
|
-
} catch {
|
|
47501
|
-
return null;
|
|
47502
|
-
}
|
|
47503
|
-
}
|
|
47504
|
-
function inferRemoteName(upstream) {
|
|
47505
|
-
const [remoteName] = upstream.split("/");
|
|
47506
|
-
return remoteName?.trim() || null;
|
|
47507
|
-
}
|
|
47508
|
-
function formatGitError(error48) {
|
|
47509
|
-
if (error48 instanceof GitCommandError) {
|
|
47510
|
-
return error48.stderr || error48.message;
|
|
47511
|
-
}
|
|
47512
|
-
if (error48 instanceof Error) {
|
|
47513
|
-
return error48.message;
|
|
47514
|
-
}
|
|
47515
|
-
return String(error48);
|
|
47516
|
-
}
|
|
47517
|
-
function parsePorcelainV2Status(output) {
|
|
47518
|
-
const parsed = {
|
|
47519
|
-
branch: null,
|
|
47520
|
-
upstream: null,
|
|
47521
|
-
ahead: 0,
|
|
47522
|
-
behind: 0,
|
|
47523
|
-
staged: 0,
|
|
47524
|
-
modified: 0,
|
|
47525
|
-
untracked: 0,
|
|
47526
|
-
deleted: 0,
|
|
47527
|
-
renamed: 0,
|
|
47528
|
-
conflictFiles: []
|
|
47529
|
-
};
|
|
47530
|
-
for (const line of output.split("\n")) {
|
|
47531
|
-
if (!line) continue;
|
|
47532
|
-
if (line.startsWith("# branch.head ")) {
|
|
47533
|
-
const branch = line.slice("# branch.head ".length).trim();
|
|
47534
|
-
parsed.branch = branch && branch !== "(detached)" ? branch : null;
|
|
47535
|
-
continue;
|
|
47536
|
-
}
|
|
47537
|
-
if (line.startsWith("# branch.upstream ")) {
|
|
47538
|
-
parsed.upstream = line.slice("# branch.upstream ".length).trim() || null;
|
|
47539
|
-
continue;
|
|
47540
|
-
}
|
|
47541
|
-
if (line.startsWith("# branch.ab ")) {
|
|
47542
|
-
const match = line.match(/\+(-?\d+)\s+-(-?\d+)/);
|
|
47543
|
-
if (match) {
|
|
47544
|
-
parsed.ahead = Number.parseInt(match[1] ?? "0", 10) || 0;
|
|
47545
|
-
parsed.behind = Number.parseInt(match[2] ?? "0", 10) || 0;
|
|
47546
|
-
}
|
|
47547
|
-
continue;
|
|
47548
|
-
}
|
|
47549
|
-
if (line.startsWith("? ")) {
|
|
47550
|
-
parsed.untracked += 1;
|
|
47551
|
-
continue;
|
|
47552
|
-
}
|
|
47553
|
-
if (line.startsWith("u ")) {
|
|
47554
|
-
const fields = line.split(" ");
|
|
47555
|
-
const filePath = fields.slice(10).join(" ");
|
|
47556
|
-
if (filePath) parsed.conflictFiles.push(filePath);
|
|
47557
|
-
continue;
|
|
47558
|
-
}
|
|
47559
|
-
if (line.startsWith("1 ") || line.startsWith("2 ")) {
|
|
47560
|
-
const fields = line.split(" ");
|
|
47561
|
-
const xy = fields[1] ?? "..";
|
|
47562
|
-
const indexStatus = xy[0] ?? ".";
|
|
47563
|
-
const worktreeStatus = xy[1] ?? ".";
|
|
47564
|
-
if (isStagedStatus(indexStatus)) parsed.staged += 1;
|
|
47565
|
-
if (worktreeStatus === "M" || worktreeStatus === "T") parsed.modified += 1;
|
|
47566
|
-
if (indexStatus === "D" || worktreeStatus === "D") parsed.deleted += 1;
|
|
47567
|
-
if (indexStatus === "R" || worktreeStatus === "R") parsed.renamed += 1;
|
|
47568
|
-
if (xy.includes("U")) {
|
|
47569
|
-
const filePath = fields.slice(line.startsWith("2 ") ? 9 : 8).join(" ").split(" ")[0] ?? "";
|
|
47570
|
-
if (filePath) parsed.conflictFiles.push(filePath);
|
|
47571
|
-
}
|
|
47572
|
-
}
|
|
47573
|
-
}
|
|
47574
|
-
parsed.conflictFiles = Array.from(new Set(parsed.conflictFiles));
|
|
47575
|
-
return parsed;
|
|
47576
|
-
}
|
|
47577
|
-
async function readHead(repo, options) {
|
|
47578
|
-
try {
|
|
47579
|
-
const result = await runGit(repo, ["log", "-1", "--pretty=%h%x00%s"], options);
|
|
47580
|
-
const text = result.stdout.trimEnd();
|
|
47581
|
-
if (!text) return { commit: null, message: null };
|
|
47582
|
-
const [commit, ...messageParts] = text.split("\0");
|
|
47583
|
-
return {
|
|
47584
|
-
commit: commit || null,
|
|
47585
|
-
message: messageParts.join("\0") || null
|
|
47586
|
-
};
|
|
47587
|
-
} catch {
|
|
47588
|
-
return { commit: null, message: null };
|
|
47589
|
-
}
|
|
47590
|
-
}
|
|
47591
|
-
async function readStashCount(repo, options) {
|
|
47592
|
-
try {
|
|
47593
|
-
const result = await runGit(repo, ["stash", "list", "--format=%gd"], options);
|
|
47594
|
-
return result.stdout.split("\n").filter((line) => line.trim().length > 0).length;
|
|
47595
|
-
} catch {
|
|
47596
|
-
return 0;
|
|
47597
|
-
}
|
|
47598
|
-
}
|
|
47599
|
-
function isStagedStatus(status) {
|
|
47600
|
-
return status !== "." && status !== "?" && status !== "U";
|
|
47601
|
-
}
|
|
47602
|
-
function emptyStatus(workspace, lastCheckedAt, error48) {
|
|
47603
|
-
return {
|
|
47604
|
-
workspace,
|
|
47605
|
-
repoRoot: null,
|
|
47606
|
-
isGitRepo: false,
|
|
47607
|
-
branch: null,
|
|
47608
|
-
headCommit: null,
|
|
47609
|
-
headMessage: null,
|
|
47610
|
-
upstream: null,
|
|
47611
|
-
upstreamStatus: "unavailable",
|
|
47612
|
-
ahead: 0,
|
|
47613
|
-
behind: 0,
|
|
47614
|
-
staged: 0,
|
|
47615
|
-
modified: 0,
|
|
47616
|
-
untracked: 0,
|
|
47617
|
-
deleted: 0,
|
|
47618
|
-
renamed: 0,
|
|
47619
|
-
hasConflicts: false,
|
|
47620
|
-
conflictFiles: [],
|
|
47621
|
-
stashCount: 0,
|
|
47622
|
-
lastCheckedAt,
|
|
47623
|
-
error: error48.stderr || error48.message,
|
|
47624
|
-
reason: error48.reason
|
|
47625
|
-
};
|
|
47626
|
-
}
|
|
47627
|
-
async function getSubmoduleStatuses(repo, options) {
|
|
47628
|
-
if (!repo.repoRoot) return [];
|
|
47629
|
-
try {
|
|
47630
|
-
const result = await runGit(repo, ["submodule", "status", "--recursive"], options);
|
|
47631
|
-
return parseSubmoduleStatusOutput(result.stdout, repo.repoRoot, options.submoduleIgnorePaths);
|
|
47632
|
-
} catch {
|
|
47633
|
-
return [];
|
|
47634
|
-
}
|
|
47635
|
-
}
|
|
47636
|
-
function parseSubmoduleStatusOutput(output, repoRoot, ignorePaths) {
|
|
47637
|
-
const submodules = [];
|
|
47638
|
-
const ignoreSet = new Set(ignorePaths || []);
|
|
47639
|
-
for (const line of output.split("\n")) {
|
|
47640
|
-
if (!line.trim()) continue;
|
|
47641
|
-
const match = line.match(/^([\-+\s])([0-9a-f]{40})\s+(\S+)(?:\s+\(([^)]+)\))?/);
|
|
47642
|
-
if (!match) continue;
|
|
47643
|
-
const prefix = match[1];
|
|
47644
|
-
const commit = match[2];
|
|
47645
|
-
const path40 = match[3];
|
|
47646
|
-
if (ignoreSet.has(path40)) continue;
|
|
47647
|
-
submodules.push({
|
|
47648
|
-
path: path40,
|
|
47649
|
-
commit,
|
|
47650
|
-
repoPath: repoRoot + "/" + path40,
|
|
47651
|
-
dirty: prefix === "+",
|
|
47652
|
-
outOfSync: prefix === "-",
|
|
47653
|
-
lastCheckedAt: Date.now()
|
|
47654
|
-
});
|
|
47655
|
-
}
|
|
47656
|
-
return submodules;
|
|
47657
|
-
}
|
|
48138
|
+
init_git_status();
|
|
47658
48139
|
var import_promises2 = require("fs/promises");
|
|
47659
48140
|
var path23 = __toESM2(require("path"));
|
|
47660
48141
|
init_git_executor();
|
|
@@ -48062,6 +48543,7 @@ ${lastSnapshot}`;
|
|
|
48062
48543
|
function createGitSnapshotStore(options = {}) {
|
|
48063
48544
|
return new InMemoryGitSnapshotStore(options);
|
|
48064
48545
|
}
|
|
48546
|
+
init_git_status();
|
|
48065
48547
|
var DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS = 5e3;
|
|
48066
48548
|
var MIN_GIT_WORKSPACE_POLL_INTERVAL_MS = 1e3;
|
|
48067
48549
|
function defaultStatusProvider(workspace) {
|
|
@@ -48182,6 +48664,7 @@ ${lastSnapshot}`;
|
|
|
48182
48664
|
}
|
|
48183
48665
|
var path32 = __toESM2(require("path"));
|
|
48184
48666
|
init_git_executor();
|
|
48667
|
+
init_git_status();
|
|
48185
48668
|
var GIT_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
48186
48669
|
"git_status",
|
|
48187
48670
|
"git_diff_summary",
|
|
@@ -49637,409 +50120,8 @@ ${lastSnapshot}`;
|
|
|
49637
50120
|
state.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
49638
50121
|
return state;
|
|
49639
50122
|
}
|
|
49640
|
-
init_mesh_config();
|
|
49641
|
-
async function syncMeshes(transport) {
|
|
49642
|
-
const result = { pushed: 0, pulled: 0, deleted: 0, errors: [] };
|
|
49643
|
-
let remoteMeshes;
|
|
49644
|
-
try {
|
|
49645
|
-
const res = await transport.listRemoteMeshes();
|
|
49646
|
-
remoteMeshes = res.meshes;
|
|
49647
|
-
} catch (e) {
|
|
49648
|
-
result.errors.push(`Failed to list remote meshes: ${e.message}`);
|
|
49649
|
-
return result;
|
|
49650
|
-
}
|
|
49651
|
-
const localMeshes = listMeshes();
|
|
49652
|
-
const remoteByIdentity = new Map(remoteMeshes.map((m) => [m.repo_identity, m]));
|
|
49653
|
-
const localByIdentity = new Map(localMeshes.map((m) => [m.repoIdentity, m]));
|
|
49654
|
-
for (const local of localMeshes) {
|
|
49655
|
-
if (!remoteByIdentity.has(local.repoIdentity)) {
|
|
49656
|
-
try {
|
|
49657
|
-
await transport.createRemoteMesh({
|
|
49658
|
-
name: local.name,
|
|
49659
|
-
repo_identity: local.repoIdentity,
|
|
49660
|
-
repo_remote_url: local.repoRemoteUrl,
|
|
49661
|
-
default_branch: local.defaultBranch,
|
|
49662
|
-
policy: JSON.stringify(local.policy)
|
|
49663
|
-
});
|
|
49664
|
-
result.pushed++;
|
|
49665
|
-
} catch (e) {
|
|
49666
|
-
result.errors.push(`Push failed for "${local.name}": ${e.message}`);
|
|
49667
|
-
}
|
|
49668
|
-
}
|
|
49669
|
-
}
|
|
49670
|
-
for (const remote of remoteMeshes) {
|
|
49671
|
-
if (!localByIdentity.has(remote.repo_identity)) {
|
|
49672
|
-
try {
|
|
49673
|
-
let policy;
|
|
49674
|
-
try {
|
|
49675
|
-
policy = JSON.parse(remote.policy);
|
|
49676
|
-
} catch {
|
|
49677
|
-
policy = void 0;
|
|
49678
|
-
}
|
|
49679
|
-
createMesh({
|
|
49680
|
-
name: remote.name,
|
|
49681
|
-
repoIdentity: remote.repo_identity,
|
|
49682
|
-
repoRemoteUrl: remote.repo_remote_url || void 0,
|
|
49683
|
-
defaultBranch: remote.default_branch || void 0,
|
|
49684
|
-
policy
|
|
49685
|
-
});
|
|
49686
|
-
result.pulled++;
|
|
49687
|
-
} catch (e) {
|
|
49688
|
-
result.errors.push(`Pull failed for "${remote.name}": ${e.message}`);
|
|
49689
|
-
}
|
|
49690
|
-
}
|
|
49691
|
-
}
|
|
49692
|
-
return result;
|
|
49693
|
-
}
|
|
49694
50123
|
init_mesh_ledger();
|
|
49695
|
-
|
|
49696
|
-
var STATUS_OPTIONS = { refreshUpstream: true, includeSubmodules: true, timeoutMs: 15e3 };
|
|
49697
|
-
async function fastForwardMeshNode(args) {
|
|
49698
|
-
const workspace = typeof args.workspace === "string" ? args.workspace.trim() : "";
|
|
49699
|
-
const nodeId = normalizeOptionalString(args.nodeId);
|
|
49700
|
-
const meshId = normalizeOptionalString(args.meshId);
|
|
49701
|
-
const requestedBranch = normalizeOptionalString(args.branch);
|
|
49702
|
-
const updateSubmodules = args.updateSubmodules === true;
|
|
49703
|
-
const dryRun = args.dryRun === true || args.execute !== true;
|
|
49704
|
-
const plannedSteps = buildPlannedSteps(updateSubmodules);
|
|
49705
|
-
const base = {
|
|
49706
|
-
...nodeId ? { nodeId } : {},
|
|
49707
|
-
...meshId ? { meshId } : {},
|
|
49708
|
-
workspace,
|
|
49709
|
-
dryRun,
|
|
49710
|
-
updateSubmodules,
|
|
49711
|
-
plannedSteps
|
|
49712
|
-
};
|
|
49713
|
-
if (!workspace) {
|
|
49714
|
-
return block(base, "invalid_workspace", ["workspace_required"]);
|
|
49715
|
-
}
|
|
49716
|
-
const current = await getGitRepoStatus(workspace, {
|
|
49717
|
-
...STATUS_OPTIONS,
|
|
49718
|
-
submoduleIgnorePaths: args.submoduleIgnorePaths,
|
|
49719
|
-
timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
|
|
49720
|
-
});
|
|
49721
|
-
const earlyBlockers = collectPreflightBlockers(current, requestedBranch);
|
|
49722
|
-
if (earlyBlockers.length > 0) {
|
|
49723
|
-
return {
|
|
49724
|
-
...block(base, chooseBlockCode(current, earlyBlockers), earlyBlockers),
|
|
49725
|
-
current,
|
|
49726
|
-
finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(chooseBlockCode(current, earlyBlockers)))
|
|
49727
|
-
};
|
|
49728
|
-
}
|
|
49729
|
-
if (current.behind === 0) {
|
|
49730
|
-
const result2 = {
|
|
49731
|
-
...base,
|
|
49732
|
-
success: true,
|
|
49733
|
-
code: "already_up_to_date",
|
|
49734
|
-
allowed: true,
|
|
49735
|
-
willRun: false,
|
|
49736
|
-
executed: false,
|
|
49737
|
-
blockingReasons: [],
|
|
49738
|
-
current,
|
|
49739
|
-
preStatus: current,
|
|
49740
|
-
postStatus: current,
|
|
49741
|
-
finalBranchConvergenceState: buildConvergenceState(current, "up_to_date")
|
|
49742
|
-
};
|
|
49743
|
-
await appendFastForwardLedger(result2, "noop");
|
|
49744
|
-
return result2;
|
|
49745
|
-
}
|
|
49746
|
-
const ancestorCheck = await verifyHeadIsAncestorOfUpstream(workspace, current.upstream || "", args.timeoutMs);
|
|
49747
|
-
if (!ancestorCheck.ok) {
|
|
49748
|
-
const result2 = {
|
|
49749
|
-
...block(base, "non_fast_forward", ["head_is_not_ancestor_of_upstream"]),
|
|
49750
|
-
current,
|
|
49751
|
-
preStatus: current,
|
|
49752
|
-
operationError: ancestorCheck.error,
|
|
49753
|
-
finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
|
|
49754
|
-
};
|
|
49755
|
-
await appendFastForwardLedger(result2, "blocked");
|
|
49756
|
-
return result2;
|
|
49757
|
-
}
|
|
49758
|
-
if (dryRun) {
|
|
49759
|
-
const result2 = {
|
|
49760
|
-
...base,
|
|
49761
|
-
success: true,
|
|
49762
|
-
code: "fast_forward_available",
|
|
49763
|
-
allowed: true,
|
|
49764
|
-
willRun: false,
|
|
49765
|
-
executed: false,
|
|
49766
|
-
blockingReasons: [],
|
|
49767
|
-
current,
|
|
49768
|
-
preStatus: current,
|
|
49769
|
-
finalBranchConvergenceState: buildConvergenceState(current, "fast_forward_available")
|
|
49770
|
-
};
|
|
49771
|
-
return result2;
|
|
49772
|
-
}
|
|
49773
|
-
try {
|
|
49774
|
-
await runGit(workspace, ["merge", "--ff-only", current.upstream || ""], { timeoutMs: args.timeoutMs ?? 3e4 });
|
|
49775
|
-
} catch (error48) {
|
|
49776
|
-
const result2 = {
|
|
49777
|
-
...block(base, "merge_ff_only_failed", ["merge_ff_only_failed"]),
|
|
49778
|
-
current,
|
|
49779
|
-
preStatus: current,
|
|
49780
|
-
operationError: formatGitError2(error48),
|
|
49781
|
-
finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
|
|
49782
|
-
};
|
|
49783
|
-
await appendFastForwardLedger(result2, "failed");
|
|
49784
|
-
return result2;
|
|
49785
|
-
}
|
|
49786
|
-
let postStatus = await getGitRepoStatus(workspace, {
|
|
49787
|
-
...STATUS_OPTIONS,
|
|
49788
|
-
submoduleIgnorePaths: args.submoduleIgnorePaths,
|
|
49789
|
-
timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
|
|
49790
|
-
});
|
|
49791
|
-
const submoduleIssues = collectSubmoduleBlockers(postStatus, "post");
|
|
49792
|
-
let submoduleFollowUpRequired = false;
|
|
49793
|
-
let operationError;
|
|
49794
|
-
if (submoduleIssues.length > 0) {
|
|
49795
|
-
if (updateSubmodules) {
|
|
49796
|
-
try {
|
|
49797
|
-
await runGit(workspace, ["submodule", "update", "--init", "--recursive"], { timeoutMs: args.timeoutMs ?? 6e4 });
|
|
49798
|
-
postStatus = await getGitRepoStatus(workspace, {
|
|
49799
|
-
...STATUS_OPTIONS,
|
|
49800
|
-
submoduleIgnorePaths: args.submoduleIgnorePaths,
|
|
49801
|
-
timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
|
|
49802
|
-
});
|
|
49803
|
-
} catch (error48) {
|
|
49804
|
-
operationError = formatGitError2(error48);
|
|
49805
|
-
}
|
|
49806
|
-
} else {
|
|
49807
|
-
submoduleFollowUpRequired = true;
|
|
49808
|
-
}
|
|
49809
|
-
}
|
|
49810
|
-
const postBlockers = collectPostExecutionBlockers(postStatus);
|
|
49811
|
-
if (operationError) postBlockers.push("submodule_update_failed");
|
|
49812
|
-
if (submoduleFollowUpRequired) postBlockers.push("submodule_update_required");
|
|
49813
|
-
const success2 = postBlockers.length === 0 || submoduleFollowUpRequired;
|
|
49814
|
-
const code = postBlockers.length === 0 ? "fast_forward_applied" : submoduleFollowUpRequired ? "fast_forward_applied_submodule_update_required" : "post_verify_failed";
|
|
49815
|
-
const result = {
|
|
49816
|
-
...base,
|
|
49817
|
-
success: success2,
|
|
49818
|
-
code,
|
|
49819
|
-
allowed: true,
|
|
49820
|
-
willRun: true,
|
|
49821
|
-
executed: true,
|
|
49822
|
-
blockingReasons: postBlockers,
|
|
49823
|
-
current,
|
|
49824
|
-
preStatus: current,
|
|
49825
|
-
postStatus,
|
|
49826
|
-
...operationError ? { operationError } : {},
|
|
49827
|
-
finalBranchConvergenceState: buildConvergenceState(
|
|
49828
|
-
postStatus,
|
|
49829
|
-
postBlockers.length === 0 ? "fast_forwarded" : submoduleFollowUpRequired ? "follow_up_required" : "post_verify_failed"
|
|
49830
|
-
)
|
|
49831
|
-
};
|
|
49832
|
-
await appendFastForwardLedger(result, success2 ? "executed" : "failed");
|
|
49833
|
-
return result;
|
|
49834
|
-
}
|
|
49835
|
-
function buildPlannedSteps(updateSubmodules) {
|
|
49836
|
-
const steps = [
|
|
49837
|
-
{
|
|
49838
|
-
operation: "refresh_upstream",
|
|
49839
|
-
description: "Refresh the tracked upstream remote ref before trusting ahead/behind state.",
|
|
49840
|
-
safe: true,
|
|
49841
|
-
willMutateWorktree: false
|
|
49842
|
-
},
|
|
49843
|
-
{
|
|
49844
|
-
operation: "verify_clean_worktree",
|
|
49845
|
-
description: "Require clean staged/modified/untracked/deleted/renamed/conflict/stash/submodule state.",
|
|
49846
|
-
safe: true,
|
|
49847
|
-
willMutateWorktree: false
|
|
49848
|
-
},
|
|
49849
|
-
{
|
|
49850
|
-
operation: "verify_fast_forward",
|
|
49851
|
-
description: "Require ahead=0, behind>0, and HEAD to be an ancestor of the upstream ref.",
|
|
49852
|
-
safe: true,
|
|
49853
|
-
willMutateWorktree: false
|
|
49854
|
-
},
|
|
49855
|
-
{
|
|
49856
|
-
operation: "merge_ff_only",
|
|
49857
|
-
description: "Apply git merge --ff-only against the tracked upstream; no force, reset, rebase, push, or deploy.",
|
|
49858
|
-
safe: true,
|
|
49859
|
-
willMutateWorktree: true
|
|
49860
|
-
}
|
|
49861
|
-
];
|
|
49862
|
-
if (updateSubmodules) {
|
|
49863
|
-
steps.push({
|
|
49864
|
-
operation: "submodule_update",
|
|
49865
|
-
description: "If the fast-forward changes gitlinks, run git submodule update --init --recursive and re-verify submodules.",
|
|
49866
|
-
safe: true,
|
|
49867
|
-
willMutateWorktree: true
|
|
49868
|
-
});
|
|
49869
|
-
}
|
|
49870
|
-
steps.push({
|
|
49871
|
-
operation: "verify_post_status",
|
|
49872
|
-
description: "Re-read daemon-owned git status and report final branch convergence state.",
|
|
49873
|
-
safe: true,
|
|
49874
|
-
willMutateWorktree: false
|
|
49875
|
-
});
|
|
49876
|
-
return steps;
|
|
49877
|
-
}
|
|
49878
|
-
function collectPreflightBlockers(status, requestedBranch) {
|
|
49879
|
-
const blockers = [];
|
|
49880
|
-
if (!status.isGitRepo) blockers.push("not_git_repo");
|
|
49881
|
-
if (!status.branch) blockers.push("detached_head_or_unknown_branch");
|
|
49882
|
-
if (requestedBranch && status.branch !== requestedBranch) blockers.push("branch_mismatch");
|
|
49883
|
-
if (!status.upstream) blockers.push("upstream_missing");
|
|
49884
|
-
if (status.upstreamStatus !== "fresh") blockers.push("upstream_not_fresh");
|
|
49885
|
-
if (status.hasConflicts) blockers.push("conflicts_present");
|
|
49886
|
-
if (status.staged > 0) blockers.push("staged_changes_present");
|
|
49887
|
-
if (status.modified > 0) blockers.push("modified_changes_present");
|
|
49888
|
-
if (status.untracked > 0) blockers.push("untracked_changes_present");
|
|
49889
|
-
if (status.deleted > 0) blockers.push("deleted_changes_present");
|
|
49890
|
-
if (status.renamed > 0) blockers.push("renamed_changes_present");
|
|
49891
|
-
if (status.stashCount > 0) blockers.push("stash_entries_present");
|
|
49892
|
-
blockers.push(...collectSubmoduleBlockers(status, "pre"));
|
|
49893
|
-
if (status.ahead > 0 && status.behind > 0) {
|
|
49894
|
-
blockers.push("branch_diverged_from_upstream");
|
|
49895
|
-
blockers.push("branch_has_local_commits");
|
|
49896
|
-
} else if (status.ahead > 0) blockers.push("branch_has_local_commits");
|
|
49897
|
-
return blockers;
|
|
49898
|
-
}
|
|
49899
|
-
function collectPostExecutionBlockers(status) {
|
|
49900
|
-
const blockers = [];
|
|
49901
|
-
if (!status.isGitRepo) blockers.push("post_not_git_repo");
|
|
49902
|
-
if (status.hasConflicts) blockers.push("post_conflicts_present");
|
|
49903
|
-
if (status.ahead !== 0) blockers.push("post_branch_ahead");
|
|
49904
|
-
if (status.behind !== 0) blockers.push("post_branch_still_behind");
|
|
49905
|
-
if (status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0) {
|
|
49906
|
-
blockers.push("post_working_tree_not_clean");
|
|
49907
|
-
}
|
|
49908
|
-
if (status.stashCount > 0) blockers.push("post_stash_entries_present");
|
|
49909
|
-
blockers.push(...collectSubmoduleBlockers(status, "post"));
|
|
49910
|
-
return blockers;
|
|
49911
|
-
}
|
|
49912
|
-
function collectSubmoduleBlockers(status, phase) {
|
|
49913
|
-
const submodules = Array.isArray(status.submodules) ? status.submodules : [];
|
|
49914
|
-
const blockers = [];
|
|
49915
|
-
for (const submodule of submodules) {
|
|
49916
|
-
if (submodule.error) blockers.push(`${phase}_submodule_status_error:${submodule.path}`);
|
|
49917
|
-
if (submodule.dirty) blockers.push(`${phase}_submodule_dirty:${submodule.path}`);
|
|
49918
|
-
if (submodule.outOfSync) blockers.push(`${phase}_submodule_out_of_sync:${submodule.path}`);
|
|
49919
|
-
}
|
|
49920
|
-
return blockers;
|
|
49921
|
-
}
|
|
49922
|
-
function chooseBlockCode(status, blockers) {
|
|
49923
|
-
if (blockers.includes("not_git_repo")) return "not_git_repo";
|
|
49924
|
-
if (blockers.includes("branch_mismatch")) return "branch_mismatch";
|
|
49925
|
-
if (blockers.includes("upstream_missing")) return "upstream_missing";
|
|
49926
|
-
if (blockers.includes("upstream_not_fresh")) return "upstream_not_fresh";
|
|
49927
|
-
if (blockers.some((reason) => reason.includes("submodule"))) return "submodule_not_clean";
|
|
49928
|
-
if (blockers.includes("branch_diverged_from_upstream")) return "branch_diverged";
|
|
49929
|
-
if (blockers.includes("branch_has_local_commits") || status.ahead > 0) return "branch_ahead";
|
|
49930
|
-
if (blockers.some((reason) => reason.includes("changes") || reason.includes("conflicts") || reason.includes("stash"))) return "dirty_worktree";
|
|
49931
|
-
return "preflight_blocked";
|
|
49932
|
-
}
|
|
49933
|
-
function codeToConvergenceStatus(code) {
|
|
49934
|
-
if (code === "branch_diverged" || code === "branch_ahead" || code === "non_fast_forward") return "not_mergeable";
|
|
49935
|
-
if (code === "dirty_worktree" || code === "submodule_not_clean") return "blocked_review";
|
|
49936
|
-
return "blocked";
|
|
49937
|
-
}
|
|
49938
|
-
async function verifyHeadIsAncestorOfUpstream(workspace, upstream, timeoutMs) {
|
|
49939
|
-
if (!upstream) return { ok: false, error: "missing upstream" };
|
|
49940
|
-
try {
|
|
49941
|
-
await runGit(workspace, ["merge-base", "--is-ancestor", "HEAD", upstream], { timeoutMs: timeoutMs ?? 15e3 });
|
|
49942
|
-
return { ok: true };
|
|
49943
|
-
} catch (error48) {
|
|
49944
|
-
return { ok: false, error: formatGitError2(error48) };
|
|
49945
|
-
}
|
|
49946
|
-
}
|
|
49947
|
-
function block(base, code, blockingReasons) {
|
|
49948
|
-
const normalizedReasons = normalizeBlockingReasons(blockingReasons);
|
|
49949
|
-
return {
|
|
49950
|
-
...base,
|
|
49951
|
-
success: false,
|
|
49952
|
-
code,
|
|
49953
|
-
allowed: false,
|
|
49954
|
-
willRun: false,
|
|
49955
|
-
executed: false,
|
|
49956
|
-
blockingReasons: normalizedReasons
|
|
49957
|
-
};
|
|
49958
|
-
}
|
|
49959
|
-
function normalizeBlockingReasons(reasons) {
|
|
49960
|
-
const normalized = /* @__PURE__ */ new Set();
|
|
49961
|
-
for (const reason of reasons) {
|
|
49962
|
-
normalized.add(reason);
|
|
49963
|
-
}
|
|
49964
|
-
if ([
|
|
49965
|
-
"conflicts_present",
|
|
49966
|
-
"staged_changes_present",
|
|
49967
|
-
"modified_changes_present",
|
|
49968
|
-
"untracked_changes_present",
|
|
49969
|
-
"deleted_changes_present",
|
|
49970
|
-
"renamed_changes_present"
|
|
49971
|
-
].some((reason) => normalized.has(reason))) {
|
|
49972
|
-
normalized.add("working_tree_not_clean");
|
|
49973
|
-
}
|
|
49974
|
-
return Array.from(normalized);
|
|
49975
|
-
}
|
|
49976
|
-
function buildConvergenceState(status, convergenceStatus) {
|
|
49977
|
-
return {
|
|
49978
|
-
status: convergenceStatus,
|
|
49979
|
-
branch: status.branch,
|
|
49980
|
-
headCommit: status.headCommit,
|
|
49981
|
-
upstream: status.upstream,
|
|
49982
|
-
ahead: status.ahead,
|
|
49983
|
-
behind: status.behind,
|
|
49984
|
-
dirty: status.staged + status.modified + status.untracked + status.deleted + status.renamed > 0 || status.hasConflicts,
|
|
49985
|
-
stashCount: status.stashCount,
|
|
49986
|
-
submodules: summarizeSubmodules(status.submodules)
|
|
49987
|
-
};
|
|
49988
|
-
}
|
|
49989
|
-
function summarizeSubmodules(submodules) {
|
|
49990
|
-
return (submodules || []).map((submodule) => ({
|
|
49991
|
-
path: submodule.path,
|
|
49992
|
-
commit: submodule.commit,
|
|
49993
|
-
dirty: submodule.dirty,
|
|
49994
|
-
outOfSync: submodule.outOfSync,
|
|
49995
|
-
...submodule.error ? { error: submodule.error } : {}
|
|
49996
|
-
}));
|
|
49997
|
-
}
|
|
49998
|
-
function normalizeOptionalString(value) {
|
|
49999
|
-
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
50000
|
-
}
|
|
50001
|
-
function formatGitError2(error48) {
|
|
50002
|
-
if (error48 instanceof GitCommandError) {
|
|
50003
|
-
return error48.stderr || error48.stdout || error48.message;
|
|
50004
|
-
}
|
|
50005
|
-
if (error48 instanceof Error) return error48.message;
|
|
50006
|
-
return String(error48);
|
|
50007
|
-
}
|
|
50008
|
-
async function appendFastForwardLedger(result, outcome) {
|
|
50009
|
-
if (!result.meshId) return;
|
|
50010
|
-
try {
|
|
50011
|
-
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
50012
|
-
appendLedgerEntry2(result.meshId, {
|
|
50013
|
-
kind: "direct_fast_forward",
|
|
50014
|
-
...result.nodeId ? { nodeId: result.nodeId } : {},
|
|
50015
|
-
payload: {
|
|
50016
|
-
operation: "mesh_fast_forward_node",
|
|
50017
|
-
outcome,
|
|
50018
|
-
code: result.code,
|
|
50019
|
-
workspace: result.workspace,
|
|
50020
|
-
allowed: result.allowed,
|
|
50021
|
-
dryRun: result.dryRun,
|
|
50022
|
-
willRun: result.willRun,
|
|
50023
|
-
executed: result.executed,
|
|
50024
|
-
branch: result.postStatus?.branch ?? result.current?.branch,
|
|
50025
|
-
upstream: result.postStatus?.upstream ?? result.current?.upstream,
|
|
50026
|
-
before: result.current ? {
|
|
50027
|
-
headCommit: result.current.headCommit,
|
|
50028
|
-
ahead: result.current.ahead,
|
|
50029
|
-
behind: result.current.behind
|
|
50030
|
-
} : void 0,
|
|
50031
|
-
after: result.postStatus ? {
|
|
50032
|
-
headCommit: result.postStatus.headCommit,
|
|
50033
|
-
ahead: result.postStatus.ahead,
|
|
50034
|
-
behind: result.postStatus.behind
|
|
50035
|
-
} : void 0,
|
|
50036
|
-
blockingReasons: result.blockingReasons
|
|
50037
|
-
}
|
|
50038
|
-
});
|
|
50039
|
-
} catch (error48) {
|
|
50040
|
-
result.ledgerError = error48 instanceof Error ? error48.message : String(error48);
|
|
50041
|
-
}
|
|
50042
|
-
}
|
|
50124
|
+
init_mesh_fast_forward();
|
|
50043
50125
|
function lastTimestamp(slice) {
|
|
50044
50126
|
const entries = Array.isArray(slice?.entries) ? slice.entries : [];
|
|
50045
50127
|
return entries.length ? entries[entries.length - 1].timestamp : null;
|
|
@@ -69346,6 +69428,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
69346
69428
|
}
|
|
69347
69429
|
init_config();
|
|
69348
69430
|
init_cli_detector();
|
|
69431
|
+
init_git_status();
|
|
69349
69432
|
init_logger();
|
|
69350
69433
|
var fs20 = __toESM2(require("fs"));
|
|
69351
69434
|
var path33 = __toESM2(require("path"));
|
|
@@ -69494,6 +69577,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
69494
69577
|
init_mesh_coordinator();
|
|
69495
69578
|
init_mesh_events();
|
|
69496
69579
|
init_mesh_host_ownership();
|
|
69580
|
+
init_mesh_fast_forward();
|
|
69497
69581
|
var import_node_child_process4 = require("child_process");
|
|
69498
69582
|
var import_node_fs4 = require("fs");
|
|
69499
69583
|
var import_node_path2 = require("path");
|
|
@@ -72140,8 +72224,8 @@ ${e?.stderr || ""}`
|
|
|
72140
72224
|
}
|
|
72141
72225
|
}
|
|
72142
72226
|
try {
|
|
72143
|
-
const { getMesh:
|
|
72144
|
-
const mesh =
|
|
72227
|
+
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
72228
|
+
const mesh = getMesh2(meshId);
|
|
72145
72229
|
if (mesh) return { mesh, inline: false, source: "local_config" };
|
|
72146
72230
|
} catch {
|
|
72147
72231
|
}
|
|
@@ -74066,8 +74150,8 @@ ${e?.stderr || ""}`
|
|
|
74066
74150
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
74067
74151
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
74068
74152
|
try {
|
|
74069
|
-
const { deleteMesh:
|
|
74070
|
-
const deleted =
|
|
74153
|
+
const { deleteMesh: deleteMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
74154
|
+
const deleted = deleteMesh2(meshId);
|
|
74071
74155
|
return { success: true, deleted };
|
|
74072
74156
|
} catch (e) {
|
|
74073
74157
|
return { success: false, error: e.message };
|
|
@@ -74185,7 +74269,7 @@ ${e?.stderr || ""}`
|
|
|
74185
74269
|
const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node addition");
|
|
74186
74270
|
if (ownerFailure) return ownerFailure;
|
|
74187
74271
|
try {
|
|
74188
|
-
const { addNode:
|
|
74272
|
+
const { addNode: addNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
74189
74273
|
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
74190
74274
|
const readOnly = args?.readOnly === true;
|
|
74191
74275
|
const policy = {
|
|
@@ -74196,7 +74280,7 @@ ${e?.stderr || ""}`
|
|
|
74196
74280
|
const daemonId = typeof args?.daemonId === "string" && args.daemonId.trim() ? args.daemonId.trim() : void 0;
|
|
74197
74281
|
const machineId = typeof args?.machineId === "string" && args.machineId.trim() ? args.machineId.trim() : void 0;
|
|
74198
74282
|
const repoRoot = typeof args?.repoRoot === "string" && args.repoRoot.trim() ? args.repoRoot.trim() : void 0;
|
|
74199
|
-
const node =
|
|
74283
|
+
const node = addNode2(meshId, {
|
|
74200
74284
|
workspace,
|
|
74201
74285
|
...repoRoot ? { repoRoot } : {},
|
|
74202
74286
|
...daemonId ? { daemonId } : {},
|
|
@@ -74387,8 +74471,8 @@ ${e?.stderr || ""}`
|
|
|
74387
74471
|
if (meshRecord?.inline) {
|
|
74388
74472
|
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
74389
74473
|
} else {
|
|
74390
|
-
const { removeNode:
|
|
74391
|
-
removed =
|
|
74474
|
+
const { removeNode: removeNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
74475
|
+
removed = removeNode2(meshId, nodeId);
|
|
74392
74476
|
if (removed) this.invalidateAggregateMeshStatus(meshId);
|
|
74393
74477
|
}
|
|
74394
74478
|
if (removed) {
|
|
@@ -74457,8 +74541,8 @@ ${e?.stderr || ""}`
|
|
|
74457
74541
|
};
|
|
74458
74542
|
this.updateInlineMeshNode(meshId, mesh, node);
|
|
74459
74543
|
} else {
|
|
74460
|
-
const { addNode:
|
|
74461
|
-
node =
|
|
74544
|
+
const { addNode: addNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
74545
|
+
node = addNode2(meshId, {
|
|
74462
74546
|
workspace: result.worktreePath,
|
|
74463
74547
|
repoRoot: result.worktreePath,
|
|
74464
74548
|
daemonId: sourceNode.daemonId,
|
|
@@ -74613,8 +74697,8 @@ ${e?.stderr || ""}`
|
|
|
74613
74697
|
mesh = args.inlineMesh;
|
|
74614
74698
|
this.inlineMeshCache.set(meshId, mesh);
|
|
74615
74699
|
} else {
|
|
74616
|
-
const { getMesh:
|
|
74617
|
-
mesh =
|
|
74700
|
+
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
74701
|
+
mesh = getMesh2(meshId);
|
|
74618
74702
|
}
|
|
74619
74703
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
74620
74704
|
const meshHost = resolveMeshHostStatus(mesh);
|