@adhdev/daemon-core 0.9.82-rc.261 → 0.9.82-rc.263
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/build-info.d.ts +37 -0
- package/dist/commands/router.d.ts +116 -0
- package/dist/git/git-status.d.ts +7 -0
- package/dist/git/git-types.d.ts +19 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +971 -69
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +967 -69
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-active-work.d.ts +18 -0
- package/dist/mesh/mesh-fast-forward.d.ts +41 -1
- package/dist/mesh/mesh-ledger.d.ts +1 -1
- package/dist/mesh/mesh-runtime-store.d.ts +6 -0
- package/dist/mesh/mesh-work-queue.d.ts +6 -0
- package/package.json +1 -1
- package/src/build-info.ts +73 -0
- package/src/commands/router.ts +805 -9
- package/src/git/git-status.ts +73 -1
- package/src/git/git-types.ts +20 -0
- package/src/index.ts +5 -2
- package/src/mesh/mesh-active-work.ts +31 -0
- package/src/mesh/mesh-fast-forward.ts +418 -17
- package/src/mesh/mesh-ledger.ts +1 -0
- package/src/mesh/mesh-runtime-store.ts +19 -0
- package/src/mesh/mesh-work-queue.ts +13 -0
package/dist/index.mjs
CHANGED
|
@@ -251,6 +251,29 @@ var init_git_executor = __esm({
|
|
|
251
251
|
}
|
|
252
252
|
});
|
|
253
253
|
|
|
254
|
+
// src/build-info.ts
|
|
255
|
+
function readInjected(value) {
|
|
256
|
+
if (typeof value !== "string") return void 0;
|
|
257
|
+
const trimmed = value.trim();
|
|
258
|
+
if (!trimmed || trimmed === "unknown") return void 0;
|
|
259
|
+
return trimmed;
|
|
260
|
+
}
|
|
261
|
+
function getDaemonBuildInfo() {
|
|
262
|
+
if (cached) return cached;
|
|
263
|
+
const commit = readInjected(true ? "2cf602f99ce68b3d3f1af02b429f6fb7a7c8e686" : void 0) ?? "unknown";
|
|
264
|
+
const commitShort = readInjected(true ? "2cf602f" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
265
|
+
const version = readInjected(true ? "0.9.82-rc.263" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
266
|
+
const builtAt = readInjected(true ? "2026-06-14T13:48:10.699Z" : void 0);
|
|
267
|
+
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
268
|
+
return cached;
|
|
269
|
+
}
|
|
270
|
+
var cached;
|
|
271
|
+
var init_build_info = __esm({
|
|
272
|
+
"src/build-info.ts"() {
|
|
273
|
+
"use strict";
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
|
|
254
277
|
// src/git/git-status.ts
|
|
255
278
|
async function getGitRepoStatus(workspace, options = {}) {
|
|
256
279
|
const lastCheckedAt = Date.now();
|
|
@@ -273,6 +296,7 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
273
296
|
}
|
|
274
297
|
const submoduleDirty = (submodules || []).some((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error);
|
|
275
298
|
const dirty = parsed.staged + parsed.modified + parsed.untracked + parsed.deleted + parsed.renamed > 0 || parsed.conflictFiles.length > 0 || stashCount > 0 || submoduleDirty;
|
|
299
|
+
const daemonBuildBehind = await detectDaemonBuildBehind(repo, submodules, options);
|
|
276
300
|
return {
|
|
277
301
|
workspace: repo.workspace,
|
|
278
302
|
repoRoot: repo.repoRoot,
|
|
@@ -296,7 +320,8 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
296
320
|
conflictFiles: parsed.conflictFiles,
|
|
297
321
|
stashCount,
|
|
298
322
|
lastCheckedAt,
|
|
299
|
-
submodules
|
|
323
|
+
submodules,
|
|
324
|
+
...daemonBuildBehind ? { daemonBuildBehind } : {}
|
|
300
325
|
};
|
|
301
326
|
} catch (error) {
|
|
302
327
|
if (error instanceof GitCommandError) {
|
|
@@ -309,6 +334,35 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
309
334
|
);
|
|
310
335
|
}
|
|
311
336
|
}
|
|
337
|
+
async function detectDaemonBuildBehind(repo, submodules, options) {
|
|
338
|
+
const build = options.daemonBuildInfo ?? getDaemonBuildInfo();
|
|
339
|
+
if (!build.commit || build.commit === "unknown") return void 0;
|
|
340
|
+
const scopes = [
|
|
341
|
+
{ scope: "root", repoPath: repo.repoRoot || repo.workspace }
|
|
342
|
+
];
|
|
343
|
+
for (const sub of submodules || []) {
|
|
344
|
+
if (sub.repoPath && !sub.error) scopes.push({ scope: sub.path, repoPath: sub.repoPath });
|
|
345
|
+
}
|
|
346
|
+
for (const { scope, repoPath } of scopes) {
|
|
347
|
+
try {
|
|
348
|
+
await runGit(repoPath, ["cat-file", "-e", `${build.commit}^{commit}`], options);
|
|
349
|
+
const headResult = await runGit(repoPath, ["rev-parse", "HEAD"], options);
|
|
350
|
+
const head = headResult.stdout.trim();
|
|
351
|
+
if (!head || head === build.commit) continue;
|
|
352
|
+
await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
|
|
353
|
+
return {
|
|
354
|
+
buildCommit: build.commit,
|
|
355
|
+
buildCommitShort: build.commitShort,
|
|
356
|
+
head,
|
|
357
|
+
scope,
|
|
358
|
+
warning: `Live daemon was built from ${build.commitShort} which is behind ${scope === "root" ? "workspace" : scope} HEAD ${head.slice(0, 7)}. Merged code is NOT live until the daemon is rebuilt/redeployed and restarted \u2014 a local dist rebuild alone does not update a cloud daemon.`
|
|
359
|
+
};
|
|
360
|
+
} catch {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return void 0;
|
|
365
|
+
}
|
|
312
366
|
async function readPorcelainStatus(repo, options) {
|
|
313
367
|
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
314
368
|
return parsePorcelainV2Status(statusOutput.stdout);
|
|
@@ -525,6 +579,7 @@ var init_git_status = __esm({
|
|
|
525
579
|
"src/git/git-status.ts"() {
|
|
526
580
|
"use strict";
|
|
527
581
|
init_git_executor();
|
|
582
|
+
init_build_info();
|
|
528
583
|
}
|
|
529
584
|
});
|
|
530
585
|
|
|
@@ -2385,8 +2440,8 @@ function readLedgerFromStore(meshId) {
|
|
|
2385
2440
|
}
|
|
2386
2441
|
function getCachedRawEntries(meshId) {
|
|
2387
2442
|
const now = Date.now();
|
|
2388
|
-
const
|
|
2389
|
-
if (
|
|
2443
|
+
const cached2 = ledgerReadCache.get(meshId);
|
|
2444
|
+
if (cached2 && now - cached2.cachedAt < LEDGER_CACHE_TTL_MS) return cached2.entries;
|
|
2390
2445
|
let entries;
|
|
2391
2446
|
try {
|
|
2392
2447
|
entries = readLedgerFromStore(meshId);
|
|
@@ -2645,6 +2700,7 @@ __export(mesh_work_queue_exports, {
|
|
|
2645
2700
|
cancelTask: () => cancelTask,
|
|
2646
2701
|
claimNextTask: () => claimNextTask,
|
|
2647
2702
|
cleanupTerminalDirectDispatches: () => cleanupTerminalDirectDispatches,
|
|
2703
|
+
deleteDirectDispatchesByTaskId: () => deleteDirectDispatchesByTaskId,
|
|
2648
2704
|
describeTaskDependencyState: () => describeTaskDependencyState,
|
|
2649
2705
|
enqueueTask: () => enqueueTask,
|
|
2650
2706
|
getActiveDirectDispatches: () => getActiveDirectDispatches,
|
|
@@ -3054,6 +3110,13 @@ function markStaleDirectDispatches(meshId, olderThanMs = 60 * 6e4) {
|
|
|
3054
3110
|
} catch {
|
|
3055
3111
|
}
|
|
3056
3112
|
}
|
|
3113
|
+
function deleteDirectDispatchesByTaskId(meshId, taskIds) {
|
|
3114
|
+
try {
|
|
3115
|
+
return MeshRuntimeStore.getInstance().deleteDirectDispatchesByTaskId(meshId, taskIds);
|
|
3116
|
+
} catch {
|
|
3117
|
+
return 0;
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3057
3120
|
function recordMeshToolCall(opts) {
|
|
3058
3121
|
try {
|
|
3059
3122
|
return MeshRuntimeStore.getInstance().recordMeshToolCall(opts);
|
|
@@ -3685,6 +3748,24 @@ var init_mesh_runtime_store = __esm({
|
|
|
3685
3748
|
deleteDirectDispatches(meshId) {
|
|
3686
3749
|
this.db.prepare(`DELETE FROM mesh_direct_dispatches WHERE mesh_id = ?`).run(meshId);
|
|
3687
3750
|
}
|
|
3751
|
+
/**
|
|
3752
|
+
* Delete specific direct dispatch rows by taskId for a mesh. Used by the staleDirect prune
|
|
3753
|
+
* path to remove orphaned/terminal dispatch records whose node/session is no longer in the
|
|
3754
|
+
* live mesh. Returns the number of rows actually deleted. No-op for an empty taskId list.
|
|
3755
|
+
*/
|
|
3756
|
+
deleteDirectDispatchesByTaskId(meshId, taskIds) {
|
|
3757
|
+
const ids = (taskIds || []).map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean);
|
|
3758
|
+
if (!ids.length) return 0;
|
|
3759
|
+
const stmt = this.db.prepare(`DELETE FROM mesh_direct_dispatches WHERE mesh_id = ? AND task_id = ?`);
|
|
3760
|
+
let deleted = 0;
|
|
3761
|
+
const run = this.db.transaction((rows) => {
|
|
3762
|
+
for (const taskId of rows) {
|
|
3763
|
+
deleted += stmt.run(meshId, taskId).changes;
|
|
3764
|
+
}
|
|
3765
|
+
});
|
|
3766
|
+
run(ids);
|
|
3767
|
+
return deleted;
|
|
3768
|
+
}
|
|
3688
3769
|
markStaleDirectDispatches(meshId, olderThanMs) {
|
|
3689
3770
|
const cutoff = new Date(Date.now() - olderThanMs).toISOString();
|
|
3690
3771
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -5353,11 +5434,14 @@ async function fastForwardMeshNode(args) {
|
|
|
5353
5434
|
const trigger = normalizeOptionalString(args.trigger) || "manual";
|
|
5354
5435
|
const updateSubmodules = args.updateSubmodules === true;
|
|
5355
5436
|
const dryRun = args.dryRun === true || args.execute !== true;
|
|
5356
|
-
const
|
|
5437
|
+
const mode = args.mode === "push" ? "push" : "merge";
|
|
5438
|
+
const pushSubmodules = mode === "push" && args.pushSubmodules === true;
|
|
5439
|
+
const plannedSteps = buildPlannedSteps(mode, updateSubmodules, pushSubmodules);
|
|
5357
5440
|
const base = {
|
|
5358
5441
|
...nodeId ? { nodeId } : {},
|
|
5359
5442
|
...meshId ? { meshId } : {},
|
|
5360
5443
|
workspace,
|
|
5444
|
+
mode,
|
|
5361
5445
|
dryRun,
|
|
5362
5446
|
updateSubmodules,
|
|
5363
5447
|
plannedSteps,
|
|
@@ -5371,13 +5455,24 @@ async function fastForwardMeshNode(args) {
|
|
|
5371
5455
|
submoduleIgnorePaths: args.submoduleIgnorePaths,
|
|
5372
5456
|
timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
|
|
5373
5457
|
});
|
|
5458
|
+
if (mode === "push") {
|
|
5459
|
+
return pushMeshNode(base, args, current, {
|
|
5460
|
+
pushSubmodules,
|
|
5461
|
+
allowAutoPublishSubmoduleMainCommits: args.allowAutoPublishSubmoduleMainCommits === true
|
|
5462
|
+
});
|
|
5463
|
+
}
|
|
5374
5464
|
const earlyBlockers = collectPreflightBlockers(current, requestedBranch);
|
|
5375
5465
|
if (earlyBlockers.length > 0) {
|
|
5466
|
+
const blockCode = chooseBlockCode(current, earlyBlockers);
|
|
5376
5467
|
const result2 = {
|
|
5377
|
-
...block(base,
|
|
5468
|
+
...block(base, blockCode, earlyBlockers),
|
|
5378
5469
|
current,
|
|
5379
|
-
finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(
|
|
5470
|
+
finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(blockCode))
|
|
5380
5471
|
};
|
|
5472
|
+
if (blockCode === "branch_ahead" && current.ahead > 0 && current.behind === 0 && otherBlockersAreOnlyAhead(earlyBlockers)) {
|
|
5473
|
+
result2.code = "ahead_needs_push";
|
|
5474
|
+
result2.nextStep = 'Local branch is ahead of origin with nothing to merge. Re-run mesh_fast_forward_node with mode="push" (execute=true) to ff-only push the local commits to origin.';
|
|
5475
|
+
}
|
|
5381
5476
|
await appendFastForwardLedger(result2, "blocked");
|
|
5382
5477
|
return result2;
|
|
5383
5478
|
}
|
|
@@ -5488,7 +5583,246 @@ async function fastForwardMeshNode(args) {
|
|
|
5488
5583
|
await appendFastForwardLedger(result, success ? "executed" : "failed");
|
|
5489
5584
|
return result;
|
|
5490
5585
|
}
|
|
5491
|
-
function
|
|
5586
|
+
async function pushMeshNode(base, args, current, options) {
|
|
5587
|
+
const workspace = base.workspace;
|
|
5588
|
+
const requestedBranch = normalizeOptionalString(args.branch);
|
|
5589
|
+
const dryRun = base.dryRun;
|
|
5590
|
+
const blockers = collectPushPreflightBlockers(current, requestedBranch);
|
|
5591
|
+
if (blockers.length > 0) {
|
|
5592
|
+
const code2 = choosePushBlockCode(current, blockers);
|
|
5593
|
+
const result2 = {
|
|
5594
|
+
...block(base, code2, blockers),
|
|
5595
|
+
current,
|
|
5596
|
+
preStatus: current,
|
|
5597
|
+
finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(code2))
|
|
5598
|
+
};
|
|
5599
|
+
await appendFastForwardLedger(result2, "blocked");
|
|
5600
|
+
return result2;
|
|
5601
|
+
}
|
|
5602
|
+
const target = parseUpstreamTarget(current.upstream || "");
|
|
5603
|
+
if (!target) {
|
|
5604
|
+
const result2 = {
|
|
5605
|
+
...block(base, "upstream_unparseable", ["upstream_unparseable"]),
|
|
5606
|
+
current,
|
|
5607
|
+
preStatus: current,
|
|
5608
|
+
finalBranchConvergenceState: buildConvergenceState(current, "blocked")
|
|
5609
|
+
};
|
|
5610
|
+
await appendFastForwardLedger(result2, "blocked");
|
|
5611
|
+
return result2;
|
|
5612
|
+
}
|
|
5613
|
+
const refspec = `HEAD:refs/heads/${target.remoteBranch}`;
|
|
5614
|
+
const pushTarget = { remote: target.remote, remoteBranch: target.remoteBranch, refspec };
|
|
5615
|
+
if (current.ahead <= 0) {
|
|
5616
|
+
const result2 = {
|
|
5617
|
+
...base,
|
|
5618
|
+
success: true,
|
|
5619
|
+
code: "nothing_to_push",
|
|
5620
|
+
allowed: true,
|
|
5621
|
+
willRun: false,
|
|
5622
|
+
executed: false,
|
|
5623
|
+
blockingReasons: [],
|
|
5624
|
+
current,
|
|
5625
|
+
preStatus: current,
|
|
5626
|
+
postStatus: current,
|
|
5627
|
+
pushTarget,
|
|
5628
|
+
finalBranchConvergenceState: buildConvergenceState(current, "up_to_date")
|
|
5629
|
+
};
|
|
5630
|
+
await appendFastForwardLedger(result2, "noop");
|
|
5631
|
+
return result2;
|
|
5632
|
+
}
|
|
5633
|
+
const descendant = await verifyUpstreamIsAncestorOfHead(workspace, current.upstream || "", args.timeoutMs);
|
|
5634
|
+
if (!descendant.ok) {
|
|
5635
|
+
const result2 = {
|
|
5636
|
+
...block(base, "non_fast_forward_push", ["head_is_not_descendant_of_upstream"]),
|
|
5637
|
+
current,
|
|
5638
|
+
preStatus: current,
|
|
5639
|
+
pushTarget,
|
|
5640
|
+
operationError: descendant.error,
|
|
5641
|
+
nextStep: "origin/<branch> has commits not in local HEAD; a ff-only push would lose them. Converge by rebasing onto origin first, then re-run. This operation never force-pushes.",
|
|
5642
|
+
finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
|
|
5643
|
+
};
|
|
5644
|
+
await appendFastForwardLedger(result2, "blocked");
|
|
5645
|
+
return result2;
|
|
5646
|
+
}
|
|
5647
|
+
if (dryRun) {
|
|
5648
|
+
const result2 = {
|
|
5649
|
+
...base,
|
|
5650
|
+
success: true,
|
|
5651
|
+
code: "push_available",
|
|
5652
|
+
allowed: true,
|
|
5653
|
+
willRun: false,
|
|
5654
|
+
executed: false,
|
|
5655
|
+
blockingReasons: [],
|
|
5656
|
+
current,
|
|
5657
|
+
preStatus: current,
|
|
5658
|
+
pushTarget,
|
|
5659
|
+
...options.pushSubmodules ? { submodulePushes: await planSubmodulePushes(current, options, args.timeoutMs) } : {},
|
|
5660
|
+
finalBranchConvergenceState: buildConvergenceState(current, "push_available")
|
|
5661
|
+
};
|
|
5662
|
+
await appendFastForwardLedger(result2, "dry_run");
|
|
5663
|
+
return result2;
|
|
5664
|
+
}
|
|
5665
|
+
try {
|
|
5666
|
+
await runGit(workspace, ["push", target.remote, refspec], { timeoutMs: args.timeoutMs ?? 3e4 });
|
|
5667
|
+
} catch (error) {
|
|
5668
|
+
const result2 = {
|
|
5669
|
+
...block(base, "push_ff_only_failed", ["push_ff_only_failed"]),
|
|
5670
|
+
current,
|
|
5671
|
+
preStatus: current,
|
|
5672
|
+
pushTarget,
|
|
5673
|
+
operationError: formatGitError2(error),
|
|
5674
|
+
finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
|
|
5675
|
+
};
|
|
5676
|
+
await appendFastForwardLedger(result2, "failed");
|
|
5677
|
+
return result2;
|
|
5678
|
+
}
|
|
5679
|
+
let submodulePushes;
|
|
5680
|
+
if (options.pushSubmodules) {
|
|
5681
|
+
submodulePushes = await executeSubmodulePushes(current, options, args.timeoutMs);
|
|
5682
|
+
}
|
|
5683
|
+
const postStatus = await getGitRepoStatus(workspace, {
|
|
5684
|
+
...STATUS_OPTIONS,
|
|
5685
|
+
submoduleIgnorePaths: args.submoduleIgnorePaths,
|
|
5686
|
+
timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
|
|
5687
|
+
});
|
|
5688
|
+
const submodulePushFailed = (submodulePushes || []).some((entry) => !entry.pushed && !entry.skipped);
|
|
5689
|
+
const blockingReasons = [];
|
|
5690
|
+
if (postStatus.ahead !== 0) blockingReasons.push("post_branch_ahead");
|
|
5691
|
+
if (submodulePushFailed) blockingReasons.push("submodule_push_failed");
|
|
5692
|
+
const success = blockingReasons.length === 0;
|
|
5693
|
+
const code = success ? "push_applied" : submodulePushFailed && postStatus.ahead === 0 ? "push_applied_submodule_push_failed" : "post_push_verify_failed";
|
|
5694
|
+
const result = {
|
|
5695
|
+
...base,
|
|
5696
|
+
success,
|
|
5697
|
+
code,
|
|
5698
|
+
allowed: true,
|
|
5699
|
+
willRun: true,
|
|
5700
|
+
executed: true,
|
|
5701
|
+
blockingReasons,
|
|
5702
|
+
current,
|
|
5703
|
+
preStatus: current,
|
|
5704
|
+
postStatus,
|
|
5705
|
+
pushTarget,
|
|
5706
|
+
...submodulePushes ? { submodulePushes } : {},
|
|
5707
|
+
finalBranchConvergenceState: buildConvergenceState(postStatus, success ? "pushed" : "post_verify_failed")
|
|
5708
|
+
};
|
|
5709
|
+
await appendFastForwardLedger(result, success ? "executed" : "failed");
|
|
5710
|
+
return result;
|
|
5711
|
+
}
|
|
5712
|
+
function collectPushPreflightBlockers(status, requestedBranch) {
|
|
5713
|
+
const blockers = [];
|
|
5714
|
+
if (!status.isGitRepo) blockers.push("not_git_repo");
|
|
5715
|
+
if (!status.branch) blockers.push("detached_head_or_unknown_branch");
|
|
5716
|
+
if (requestedBranch && status.branch !== requestedBranch) blockers.push("branch_mismatch");
|
|
5717
|
+
if (!status.upstream) blockers.push("upstream_missing");
|
|
5718
|
+
if (status.upstreamStatus !== "fresh") blockers.push("upstream_not_fresh");
|
|
5719
|
+
if (status.hasConflicts) blockers.push("conflicts_present");
|
|
5720
|
+
if (status.staged > 0) blockers.push("staged_changes_present");
|
|
5721
|
+
if (status.modified > 0) blockers.push("modified_changes_present");
|
|
5722
|
+
if (status.untracked > 0) blockers.push("untracked_changes_present");
|
|
5723
|
+
if (status.deleted > 0) blockers.push("deleted_changes_present");
|
|
5724
|
+
if (status.renamed > 0) blockers.push("renamed_changes_present");
|
|
5725
|
+
if (status.stashCount > 0) blockers.push("stash_entries_present");
|
|
5726
|
+
if (status.ahead > 0 && status.behind > 0) blockers.push("branch_diverged_from_upstream");
|
|
5727
|
+
else if (status.behind > 0) blockers.push("branch_behind_upstream");
|
|
5728
|
+
return blockers;
|
|
5729
|
+
}
|
|
5730
|
+
function choosePushBlockCode(status, blockers) {
|
|
5731
|
+
if (blockers.includes("not_git_repo")) return "not_git_repo";
|
|
5732
|
+
if (blockers.includes("branch_mismatch")) return "branch_mismatch";
|
|
5733
|
+
if (blockers.includes("upstream_missing")) return "upstream_missing";
|
|
5734
|
+
if (blockers.includes("upstream_not_fresh")) return "upstream_not_fresh";
|
|
5735
|
+
if (blockers.includes("branch_diverged_from_upstream")) return "branch_diverged";
|
|
5736
|
+
if (blockers.includes("branch_behind_upstream")) return "non_fast_forward_push";
|
|
5737
|
+
if (blockers.some((reason) => reason.includes("changes") || reason.includes("conflicts") || reason.includes("stash"))) return "dirty_worktree";
|
|
5738
|
+
return "preflight_blocked";
|
|
5739
|
+
}
|
|
5740
|
+
function parseUpstreamTarget(upstream) {
|
|
5741
|
+
const trimmed = upstream.trim();
|
|
5742
|
+
const slash = trimmed.indexOf("/");
|
|
5743
|
+
if (slash <= 0 || slash >= trimmed.length - 1) return null;
|
|
5744
|
+
return { remote: trimmed.slice(0, slash), remoteBranch: trimmed.slice(slash + 1) };
|
|
5745
|
+
}
|
|
5746
|
+
async function verifyUpstreamIsAncestorOfHead(workspace, upstream, timeoutMs) {
|
|
5747
|
+
if (!upstream) return { ok: false, error: "missing upstream" };
|
|
5748
|
+
try {
|
|
5749
|
+
await runGit(workspace, ["merge-base", "--is-ancestor", upstream, "HEAD"], { timeoutMs: timeoutMs ?? 15e3 });
|
|
5750
|
+
return { ok: true };
|
|
5751
|
+
} catch (error) {
|
|
5752
|
+
return { ok: false, error: formatGitError2(error) };
|
|
5753
|
+
}
|
|
5754
|
+
}
|
|
5755
|
+
async function planSubmodulePushes(status, options, timeoutMs) {
|
|
5756
|
+
return resolveSubmodulePushes(status, options, false, timeoutMs);
|
|
5757
|
+
}
|
|
5758
|
+
async function executeSubmodulePushes(status, options, timeoutMs) {
|
|
5759
|
+
return resolveSubmodulePushes(status, options, true, timeoutMs);
|
|
5760
|
+
}
|
|
5761
|
+
async function resolveSubmodulePushes(status, options, execute, timeoutMs) {
|
|
5762
|
+
const submodules = Array.isArray(status.submodules) ? status.submodules : [];
|
|
5763
|
+
const results = [];
|
|
5764
|
+
for (const submodule of submodules) {
|
|
5765
|
+
const base = {
|
|
5766
|
+
path: submodule.path,
|
|
5767
|
+
commit: submodule.commit,
|
|
5768
|
+
remote: "origin",
|
|
5769
|
+
remoteBranch: "main",
|
|
5770
|
+
pushed: false,
|
|
5771
|
+
skipped: true,
|
|
5772
|
+
code: "submodule_push_skipped"
|
|
5773
|
+
};
|
|
5774
|
+
if (!options.allowAutoPublishSubmoduleMainCommits) {
|
|
5775
|
+
results.push({ ...base, code: "submodule_push_policy_disabled", error: "allowAutoPublishSubmoduleMainCommits is not enabled" });
|
|
5776
|
+
continue;
|
|
5777
|
+
}
|
|
5778
|
+
if (submodule.error || submodule.dirty) {
|
|
5779
|
+
results.push({ ...base, code: "submodule_not_clean", error: submodule.error || "submodule worktree is dirty" });
|
|
5780
|
+
continue;
|
|
5781
|
+
}
|
|
5782
|
+
const repoPath = submodule.repoPath;
|
|
5783
|
+
if (!repoPath || !submodule.commit) {
|
|
5784
|
+
results.push({ ...base, code: "submodule_status_incomplete" });
|
|
5785
|
+
continue;
|
|
5786
|
+
}
|
|
5787
|
+
try {
|
|
5788
|
+
await runGit(repoPath, ["-c", "protocol.file.allow=always", "fetch", "origin", "refs/heads/main:refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 3e4 });
|
|
5789
|
+
} catch (error) {
|
|
5790
|
+
results.push({ ...base, code: "submodule_fetch_failed", error: formatGitError2(error) });
|
|
5791
|
+
continue;
|
|
5792
|
+
}
|
|
5793
|
+
let alreadyReachable = false;
|
|
5794
|
+
try {
|
|
5795
|
+
await runGit(repoPath, ["merge-base", "--is-ancestor", submodule.commit, "refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 15e3 });
|
|
5796
|
+
alreadyReachable = true;
|
|
5797
|
+
} catch {
|
|
5798
|
+
}
|
|
5799
|
+
if (alreadyReachable) {
|
|
5800
|
+
results.push({ ...base, pushed: false, skipped: true, code: "submodule_already_reachable" });
|
|
5801
|
+
continue;
|
|
5802
|
+
}
|
|
5803
|
+
try {
|
|
5804
|
+
await runGit(repoPath, ["merge-base", "--is-ancestor", "refs/remotes/origin/main", submodule.commit], { timeoutMs: timeoutMs ?? 15e3 });
|
|
5805
|
+
} catch (error) {
|
|
5806
|
+
results.push({ ...base, pushed: false, skipped: false, code: "submodule_non_fast_forward", error: formatGitError2(error) });
|
|
5807
|
+
continue;
|
|
5808
|
+
}
|
|
5809
|
+
const refspec = `${submodule.commit}:refs/heads/main`;
|
|
5810
|
+
if (!execute) {
|
|
5811
|
+
results.push({ ...base, pushed: false, skipped: false, code: "submodule_push_available", refspec });
|
|
5812
|
+
continue;
|
|
5813
|
+
}
|
|
5814
|
+
try {
|
|
5815
|
+
await runGit(repoPath, ["push", "origin", refspec], { timeoutMs: timeoutMs ?? 3e4 });
|
|
5816
|
+
await runGit(repoPath, ["-c", "protocol.file.allow=always", "fetch", "origin", "refs/heads/main:refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 3e4 });
|
|
5817
|
+
await runGit(repoPath, ["merge-base", "--is-ancestor", submodule.commit, "refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 15e3 });
|
|
5818
|
+
results.push({ ...base, pushed: true, skipped: false, code: "submodule_pushed", refspec });
|
|
5819
|
+
} catch (error) {
|
|
5820
|
+
results.push({ ...base, pushed: false, skipped: false, code: "submodule_push_failed", refspec, error: formatGitError2(error) });
|
|
5821
|
+
}
|
|
5822
|
+
}
|
|
5823
|
+
return results;
|
|
5824
|
+
}
|
|
5825
|
+
function buildPlannedSteps(mode, updateSubmodules, pushSubmodules) {
|
|
5492
5826
|
const steps = [
|
|
5493
5827
|
{
|
|
5494
5828
|
operation: "refresh_upstream",
|
|
@@ -5501,20 +5835,49 @@ function buildPlannedSteps(updateSubmodules) {
|
|
|
5501
5835
|
description: "Require clean staged/modified/untracked/deleted/renamed/conflict/stash/submodule state.",
|
|
5502
5836
|
safe: true,
|
|
5503
5837
|
willMutateWorktree: false
|
|
5504
|
-
}
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5838
|
+
}
|
|
5839
|
+
];
|
|
5840
|
+
if (mode === "push") {
|
|
5841
|
+
steps.push({
|
|
5842
|
+
operation: "verify_push_descendant",
|
|
5843
|
+
description: "Require HEAD to be a descendant of origin/<branch> (origin/<branch> is an ancestor of HEAD); refuse any non-fast-forward push.",
|
|
5508
5844
|
safe: true,
|
|
5509
5845
|
willMutateWorktree: false
|
|
5510
|
-
}
|
|
5511
|
-
{
|
|
5512
|
-
operation: "
|
|
5513
|
-
description: "
|
|
5846
|
+
});
|
|
5847
|
+
steps.push({
|
|
5848
|
+
operation: "push_ff_only",
|
|
5849
|
+
description: "Run git push origin HEAD:<branch> as a strict ff-only push; never --force, --force-with-lease, reset, or rebase. Does not mutate the worktree.",
|
|
5514
5850
|
safe: true,
|
|
5515
|
-
willMutateWorktree:
|
|
5851
|
+
willMutateWorktree: false
|
|
5852
|
+
});
|
|
5853
|
+
if (pushSubmodules) {
|
|
5854
|
+
steps.push({
|
|
5855
|
+
operation: "push_submodules_ff_only",
|
|
5856
|
+
description: "For each submodule, if allowAutoPublishSubmoduleMainCommits is enabled and the submodule HEAD is a descendant of its origin main, ff-only push it to submodule origin main; otherwise skip.",
|
|
5857
|
+
safe: true,
|
|
5858
|
+
willMutateWorktree: false
|
|
5859
|
+
});
|
|
5516
5860
|
}
|
|
5517
|
-
|
|
5861
|
+
steps.push({
|
|
5862
|
+
operation: "verify_post_status",
|
|
5863
|
+
description: "Re-read daemon-owned git status and report final branch convergence state.",
|
|
5864
|
+
safe: true,
|
|
5865
|
+
willMutateWorktree: false
|
|
5866
|
+
});
|
|
5867
|
+
return steps;
|
|
5868
|
+
}
|
|
5869
|
+
steps.push({
|
|
5870
|
+
operation: "verify_fast_forward",
|
|
5871
|
+
description: "Require ahead=0, behind>0, and HEAD to be an ancestor of the upstream ref.",
|
|
5872
|
+
safe: true,
|
|
5873
|
+
willMutateWorktree: false
|
|
5874
|
+
});
|
|
5875
|
+
steps.push({
|
|
5876
|
+
operation: "merge_ff_only",
|
|
5877
|
+
description: "Apply git merge --ff-only against the tracked upstream; no force, reset, rebase, push, or deploy.",
|
|
5878
|
+
safe: true,
|
|
5879
|
+
willMutateWorktree: true
|
|
5880
|
+
});
|
|
5518
5881
|
if (updateSubmodules) {
|
|
5519
5882
|
steps.push({
|
|
5520
5883
|
operation: "submodule_update",
|
|
@@ -5531,6 +5894,10 @@ function buildPlannedSteps(updateSubmodules) {
|
|
|
5531
5894
|
});
|
|
5532
5895
|
return steps;
|
|
5533
5896
|
}
|
|
5897
|
+
function otherBlockersAreOnlyAhead(blockers) {
|
|
5898
|
+
const aheadOnly = /* @__PURE__ */ new Set(["branch_has_local_commits"]);
|
|
5899
|
+
return blockers.every((reason) => aheadOnly.has(reason));
|
|
5900
|
+
}
|
|
5534
5901
|
function collectPreflightBlockers(status, requestedBranch) {
|
|
5535
5902
|
const blockers = [];
|
|
5536
5903
|
if (!status.isGitRepo) blockers.push("not_git_repo");
|
|
@@ -5587,7 +5954,7 @@ function chooseBlockCode(status, blockers) {
|
|
|
5587
5954
|
return "preflight_blocked";
|
|
5588
5955
|
}
|
|
5589
5956
|
function codeToConvergenceStatus(code) {
|
|
5590
|
-
if (code === "branch_diverged" || code === "branch_ahead" || code === "non_fast_forward") return "not_mergeable";
|
|
5957
|
+
if (code === "branch_diverged" || code === "branch_ahead" || code === "non_fast_forward" || code === "non_fast_forward_push" || code === "upstream_unparseable") return "not_mergeable";
|
|
5591
5958
|
if (code === "dirty_worktree" || code === "submodule_not_clean") return "blocked_review";
|
|
5592
5959
|
return "blocked";
|
|
5593
5960
|
}
|
|
@@ -5670,6 +6037,7 @@ async function appendFastForwardLedger(result, outcome) {
|
|
|
5670
6037
|
...result.nodeId ? { nodeId: result.nodeId } : {},
|
|
5671
6038
|
payload: {
|
|
5672
6039
|
operation: "mesh_fast_forward_node",
|
|
6040
|
+
mode: result.mode,
|
|
5673
6041
|
trigger: result.trigger || "manual",
|
|
5674
6042
|
outcome,
|
|
5675
6043
|
code: result.code,
|
|
@@ -5680,6 +6048,7 @@ async function appendFastForwardLedger(result, outcome) {
|
|
|
5680
6048
|
executed: result.executed,
|
|
5681
6049
|
branch: result.postStatus?.branch ?? result.current?.branch,
|
|
5682
6050
|
upstream: result.postStatus?.upstream ?? result.current?.upstream,
|
|
6051
|
+
...result.pushTarget ? { pushTarget: result.pushTarget } : {},
|
|
5683
6052
|
before: result.current ? {
|
|
5684
6053
|
headCommit: result.current.headCommit,
|
|
5685
6054
|
ahead: result.current.ahead,
|
|
@@ -5690,6 +6059,16 @@ async function appendFastForwardLedger(result, outcome) {
|
|
|
5690
6059
|
ahead: result.postStatus.ahead,
|
|
5691
6060
|
behind: result.postStatus.behind
|
|
5692
6061
|
} : void 0,
|
|
6062
|
+
...result.submodulePushes ? {
|
|
6063
|
+
submodulePushes: result.submodulePushes.map((entry) => ({
|
|
6064
|
+
path: entry.path,
|
|
6065
|
+
commit: entry.commit,
|
|
6066
|
+
pushed: entry.pushed,
|
|
6067
|
+
skipped: entry.skipped,
|
|
6068
|
+
code: entry.code,
|
|
6069
|
+
...entry.refspec ? { refspec: entry.refspec } : {}
|
|
6070
|
+
}))
|
|
6071
|
+
} : {},
|
|
5693
6072
|
blockingReasons: result.blockingReasons
|
|
5694
6073
|
}
|
|
5695
6074
|
});
|
|
@@ -6860,8 +7239,8 @@ var init_mesh_routing = __esm({
|
|
|
6860
7239
|
import { existsSync as existsSync14 } from "fs";
|
|
6861
7240
|
function getCachedMeshByWorkspace(workspace) {
|
|
6862
7241
|
const now = Date.now();
|
|
6863
|
-
const
|
|
6864
|
-
if (
|
|
7242
|
+
const cached2 = meshByWorkspaceCache.get(workspace);
|
|
7243
|
+
if (cached2 && now - cached2.cachedAt < MESH_WORKSPACE_CACHE_TTL_MS) return cached2.mesh;
|
|
6865
7244
|
const mesh = getMeshByRepo(workspace);
|
|
6866
7245
|
meshByWorkspaceCache.set(workspace, { mesh, cachedAt: now });
|
|
6867
7246
|
return mesh;
|
|
@@ -11754,10 +12133,10 @@ ${lastSnapshot}`;
|
|
|
11754
12133
|
return this.accumulatedRawBuffer.replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
11755
12134
|
}
|
|
11756
12135
|
getFreshParsedStatusCache() {
|
|
11757
|
-
const
|
|
12136
|
+
const cached2 = this.parsedStatusCache;
|
|
11758
12137
|
const accumulatedRawBufferKey = this.getAccumulatedRawBufferCacheKey();
|
|
11759
|
-
if (
|
|
11760
|
-
return
|
|
12138
|
+
if (cached2 && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.engine.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.accumulatedRawBufferKey === accumulatedRawBufferKey && cached2.screenText === this.lastScreenText && cached2.currentStatus === this.engine.currentStatus && cached2.activeModal === this.engine.activeModal && cached2.cliName === this.cliName) {
|
|
12139
|
+
return cached2.result;
|
|
11761
12140
|
}
|
|
11762
12141
|
return null;
|
|
11763
12142
|
}
|
|
@@ -12217,10 +12596,10 @@ ${lastSnapshot}`;
|
|
|
12217
12596
|
getScriptParsedStatus() {
|
|
12218
12597
|
const screenText = this.readTerminalScreenText();
|
|
12219
12598
|
const parseScreenText = this.getParseScreenText(screenText);
|
|
12220
|
-
const
|
|
12599
|
+
const cached2 = this.parsedStatusCache;
|
|
12221
12600
|
const accumulatedRawBufferKey = this.getAccumulatedRawBufferCacheKey();
|
|
12222
|
-
if (!this.providerOwnsTranscript() &&
|
|
12223
|
-
return
|
|
12601
|
+
if (!this.providerOwnsTranscript() && cached2 && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.engine.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.accumulatedRawBufferKey === accumulatedRawBufferKey && cached2.screenText === parseScreenText && cached2.currentStatus === this.engine.currentStatus && cached2.activeModal === this.engine.activeModal && cached2.cliName === this.cliName) {
|
|
12602
|
+
return cached2.result;
|
|
12224
12603
|
}
|
|
12225
12604
|
const parsed = this.runParseSession();
|
|
12226
12605
|
if (!parsed || !Array.isArray(parsed.messages)) {
|
|
@@ -16701,6 +17080,17 @@ function buildMeshActiveWork(opts) {
|
|
|
16701
17080
|
}
|
|
16702
17081
|
return { activeWork: records, staleDirectWork, staleDirectWorkNote, terminalDirectWork, summary };
|
|
16703
17082
|
}
|
|
17083
|
+
var PRUNABLE_ORPHAN_STALE_REASONS = /* @__PURE__ */ new Set([
|
|
17084
|
+
"direct task node is no longer in the live mesh",
|
|
17085
|
+
"direct task session is not present in live session records",
|
|
17086
|
+
"direct task has no node id"
|
|
17087
|
+
]);
|
|
17088
|
+
function classifyStaleDirectForPrune(record, opts = {}) {
|
|
17089
|
+
if (record.staleDispatchUnacknowledged === true) return "preserve_unacknowledged";
|
|
17090
|
+
if (record.terminal === true) return opts.includeTerminal ? "prunable_terminal" : "preserve_active";
|
|
17091
|
+
if (record.staleReason && PRUNABLE_ORPHAN_STALE_REASONS.has(record.staleReason)) return "prunable_orphan";
|
|
17092
|
+
return "preserve_active";
|
|
17093
|
+
}
|
|
16704
17094
|
function buildCompactStaleDirectWorkSummary(staleDirectWork, opts = {}) {
|
|
16705
17095
|
const sampleLimit = Math.max(0, Math.min(10, Math.floor(opts.sampleLimit ?? 3)));
|
|
16706
17096
|
const reasonCounts = {};
|
|
@@ -19924,9 +20314,9 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
19924
20314
|
for (const file of files.slice().sort()) {
|
|
19925
20315
|
const filePath = path12.join(dir, file);
|
|
19926
20316
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
19927
|
-
const
|
|
20317
|
+
const cached2 = savedHistoryFileSummaryCache.get(filePath);
|
|
19928
20318
|
const persisted = persistedEntries.get(file);
|
|
19929
|
-
const reusableEntry =
|
|
20319
|
+
const reusableEntry = cached2?.signature === signature ? cached2 : persisted?.signature === signature ? persisted : null;
|
|
19930
20320
|
const fileSummary = reusableEntry?.summary || computeSavedHistoryFileSummary(dir, file);
|
|
19931
20321
|
const nextEntry = reusableEntry || {
|
|
19932
20322
|
signature,
|
|
@@ -20378,23 +20768,23 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
20378
20768
|
savedHistorySessionCache.delete(sanitized);
|
|
20379
20769
|
return { sessions: [], hasMore: false };
|
|
20380
20770
|
}
|
|
20381
|
-
const
|
|
20771
|
+
const cached2 = savedHistorySessionCache.get(sanitized);
|
|
20382
20772
|
const offset = Math.max(0, options.offset || 0);
|
|
20383
20773
|
const limit = Math.max(1, options.limit || 30);
|
|
20384
20774
|
const indexSignature = buildSavedHistoryIndexFileSignature(dir);
|
|
20385
20775
|
let cacheWasInvalidated = false;
|
|
20386
|
-
if (
|
|
20387
|
-
const cacheLooksPersisted =
|
|
20388
|
-
const cacheStillValid = cacheLooksPersisted ?
|
|
20776
|
+
if (cached2) {
|
|
20777
|
+
const cacheLooksPersisted = cached2.signature.startsWith("index:");
|
|
20778
|
+
const cacheStillValid = cacheLooksPersisted ? cached2.signature === indexSignature : (() => {
|
|
20389
20779
|
const files2 = listHistoryFiles(dir);
|
|
20390
20780
|
const fileSignatures2 = buildSavedHistoryFileSignatureMap(dir, files2);
|
|
20391
|
-
return
|
|
20781
|
+
return cached2.signature === buildSavedHistoryCacheSignature(files2, fileSignatures2);
|
|
20392
20782
|
})();
|
|
20393
20783
|
if (cacheStillValid) {
|
|
20394
|
-
const sliced2 =
|
|
20784
|
+
const sliced2 = cached2.summaries.slice(offset, offset + limit);
|
|
20395
20785
|
return {
|
|
20396
20786
|
sessions: sliced2,
|
|
20397
|
-
hasMore:
|
|
20787
|
+
hasMore: cached2.summaries.length > offset + limit
|
|
20398
20788
|
};
|
|
20399
20789
|
}
|
|
20400
20790
|
cacheWasInvalidated = true;
|
|
@@ -36988,8 +37378,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
36988
37378
|
return null;
|
|
36989
37379
|
}
|
|
36990
37380
|
registerProviderScriptRootSafely(path30.dirname(path30.dirname(providerDir)));
|
|
36991
|
-
const
|
|
36992
|
-
if (
|
|
37381
|
+
const cached2 = this.scriptsCache.get(dir);
|
|
37382
|
+
if (cached2) return cached2;
|
|
36993
37383
|
const scriptsJs = path30.join(dir, "scripts.js");
|
|
36994
37384
|
if (fs20.existsSync(scriptsJs)) {
|
|
36995
37385
|
try {
|
|
@@ -38987,6 +39377,9 @@ function buildStatusSnapshot(options) {
|
|
|
38987
39377
|
};
|
|
38988
39378
|
}
|
|
38989
39379
|
|
|
39380
|
+
// src/commands/router.ts
|
|
39381
|
+
init_build_info();
|
|
39382
|
+
|
|
38990
39383
|
// src/commands/upgrade-helper.ts
|
|
38991
39384
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
38992
39385
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -39772,13 +40165,13 @@ function sanitizeInlineMesh(inlineMesh) {
|
|
|
39772
40165
|
nodes
|
|
39773
40166
|
};
|
|
39774
40167
|
}
|
|
39775
|
-
function reconcileInlineMeshCache(
|
|
39776
|
-
if (!
|
|
39777
|
-
if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return
|
|
39778
|
-
const cachedNodes = Array.isArray(
|
|
40168
|
+
function reconcileInlineMeshCache(cached2, incoming) {
|
|
40169
|
+
if (!cached2 || typeof cached2 !== "object" || Array.isArray(cached2)) return incoming;
|
|
40170
|
+
if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return cached2;
|
|
40171
|
+
const cachedNodes = Array.isArray(cached2.nodes) ? cached2.nodes : [];
|
|
39779
40172
|
const incomingNodes = Array.isArray(incoming.nodes) ? incoming.nodes : [];
|
|
39780
|
-
if (!cachedNodes.length || !incomingNodes.length) return { ...
|
|
39781
|
-
const cachedUpdatedAt = Date.parse(readStringValue(
|
|
40173
|
+
if (!cachedNodes.length || !incomingNodes.length) return { ...cached2, ...incoming };
|
|
40174
|
+
const cachedUpdatedAt = Date.parse(readStringValue(cached2.updatedAt, cached2.updated_at) || "");
|
|
39782
40175
|
const incomingUpdatedAt = Date.parse(readStringValue(incoming.updatedAt, incoming.updated_at) || "");
|
|
39783
40176
|
const preserveCachedMembership = Number.isFinite(cachedUpdatedAt) && (!Number.isFinite(incomingUpdatedAt) || cachedUpdatedAt > incomingUpdatedAt);
|
|
39784
40177
|
const cachedById = /* @__PURE__ */ new Map();
|
|
@@ -39807,7 +40200,7 @@ function reconcileInlineMeshCache(cached, incoming) {
|
|
|
39807
40200
|
}
|
|
39808
40201
|
}
|
|
39809
40202
|
return {
|
|
39810
|
-
...
|
|
40203
|
+
...cached2,
|
|
39811
40204
|
...incoming,
|
|
39812
40205
|
nodes
|
|
39813
40206
|
};
|
|
@@ -40418,8 +40811,37 @@ async function runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead)
|
|
|
40418
40811
|
maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
|
|
40419
40812
|
});
|
|
40420
40813
|
const mergeBase = git(["merge-base", baseHead, branchHead]).trim();
|
|
40421
|
-
|
|
40422
|
-
|
|
40814
|
+
let mergedTree = "";
|
|
40815
|
+
let mergeTreeStdout = "";
|
|
40816
|
+
let gitlinkTrivialFastForward;
|
|
40817
|
+
try {
|
|
40818
|
+
mergeTreeStdout = git(["merge-tree", "--write-tree", baseHead, branchHead]);
|
|
40819
|
+
mergedTree = mergeTreeStdout.trim().split(/\s+/)[0] || "";
|
|
40820
|
+
} catch (mergeTreeErr) {
|
|
40821
|
+
const output = `${mergeTreeErr?.message || ""}
|
|
40822
|
+
${mergeTreeErr?.stdout || ""}
|
|
40823
|
+
${mergeTreeErr?.stderr || ""}`;
|
|
40824
|
+
const isSubmoduleConflict = /(submodule|160000)/i.test(output) || /Recursive merging with submodules/i.test(output);
|
|
40825
|
+
if (!isSubmoduleConflict) throw mergeTreeErr;
|
|
40826
|
+
const evaluation = evaluateGitlinkTrivialFastForward(repoRoot, baseHead, branchHead);
|
|
40827
|
+
if (!evaluation.trivial) {
|
|
40828
|
+
return {
|
|
40829
|
+
status: "failed",
|
|
40830
|
+
equivalent: false,
|
|
40831
|
+
baseHead,
|
|
40832
|
+
branchHead,
|
|
40833
|
+
mergeBase: mergeBase || void 0,
|
|
40834
|
+
durationMs: Date.now() - startedAt,
|
|
40835
|
+
error: mergeTreeErr?.message || String(mergeTreeErr),
|
|
40836
|
+
stdout: truncateValidationOutput(mergeTreeErr?.stdout),
|
|
40837
|
+
stderr: truncateValidationOutput(mergeTreeErr?.stderr),
|
|
40838
|
+
gitlinkTrivialFastForward: { resolved: false, gitlinks: evaluation.gitlinks, reason: evaluation.reason },
|
|
40839
|
+
actionableHint: buildPatchEquivalenceSubmoduleConflictHint(repoRoot, baseHead, branchHead, output)
|
|
40840
|
+
};
|
|
40841
|
+
}
|
|
40842
|
+
mergedTree = synthesizeTrivialFastForwardMergeTree(repoRoot, baseHead, branchHead, evaluation.gitlinks) || "";
|
|
40843
|
+
gitlinkTrivialFastForward = { resolved: true, gitlinks: evaluation.gitlinks };
|
|
40844
|
+
}
|
|
40423
40845
|
if (!mergeBase || !mergedTree) {
|
|
40424
40846
|
return {
|
|
40425
40847
|
status: "failed",
|
|
@@ -40430,7 +40852,8 @@ async function runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead)
|
|
|
40430
40852
|
mergedTree: mergedTree || void 0,
|
|
40431
40853
|
durationMs: Date.now() - startedAt,
|
|
40432
40854
|
error: "patch equivalence preflight could not resolve merge-base or synthetic merge tree",
|
|
40433
|
-
stdout: truncateValidationOutput(mergeTreeStdout)
|
|
40855
|
+
stdout: truncateValidationOutput(mergeTreeStdout),
|
|
40856
|
+
gitlinkTrivialFastForward
|
|
40434
40857
|
};
|
|
40435
40858
|
}
|
|
40436
40859
|
const expectedPatchId = await computeGitPatchId(repoRoot, mergeBase, branchHead);
|
|
@@ -40445,7 +40868,8 @@ async function runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead)
|
|
|
40445
40868
|
mergedTree,
|
|
40446
40869
|
expectedPatchId,
|
|
40447
40870
|
actualPatchId,
|
|
40448
|
-
durationMs: Date.now() - startedAt
|
|
40871
|
+
durationMs: Date.now() - startedAt,
|
|
40872
|
+
gitlinkTrivialFastForward
|
|
40449
40873
|
};
|
|
40450
40874
|
} catch (e) {
|
|
40451
40875
|
return {
|
|
@@ -40468,6 +40892,65 @@ ${e?.stderr || ""}`
|
|
|
40468
40892
|
};
|
|
40469
40893
|
}
|
|
40470
40894
|
}
|
|
40895
|
+
async function runMeshRefineEffectiveDiffGate(repoRoot, baseHead, branchHead) {
|
|
40896
|
+
const startedAt = Date.now();
|
|
40897
|
+
try {
|
|
40898
|
+
const { execFileSync: execFileSync6 } = await import("child_process");
|
|
40899
|
+
const git = (args, opts) => execFileSync6("git", args, {
|
|
40900
|
+
cwd: opts?.cwd || repoRoot,
|
|
40901
|
+
encoding: "utf8",
|
|
40902
|
+
maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
|
|
40903
|
+
});
|
|
40904
|
+
const rawDiff = git(["diff", "--raw", baseHead, branchHead]).trim();
|
|
40905
|
+
if (rawDiff) {
|
|
40906
|
+
const changedPaths = rawDiff.split("\n").map((line) => line.split(" ").slice(1).join(" ").trim()).filter(Boolean).slice(0, 50);
|
|
40907
|
+
return {
|
|
40908
|
+
status: "passed",
|
|
40909
|
+
hasEffectiveDiff: true,
|
|
40910
|
+
baseHead,
|
|
40911
|
+
branchHead,
|
|
40912
|
+
changedPaths,
|
|
40913
|
+
durationMs: Date.now() - startedAt
|
|
40914
|
+
};
|
|
40915
|
+
}
|
|
40916
|
+
const submoduleHints = [];
|
|
40917
|
+
try {
|
|
40918
|
+
const status = git(["submodule", "status"]);
|
|
40919
|
+
for (const line of status.split("\n")) {
|
|
40920
|
+
const trimmed = line.trimEnd();
|
|
40921
|
+
if (!trimmed) continue;
|
|
40922
|
+
if (trimmed.startsWith("+")) {
|
|
40923
|
+
const parts = trimmed.slice(1).trim().split(/\s+/);
|
|
40924
|
+
const path39 = parts[1] || parts[0] || "(unknown)";
|
|
40925
|
+
submoduleHints.push({
|
|
40926
|
+
path: path39,
|
|
40927
|
+
reason: "submodule checked-out commit differs from the committed gitlink (pointer bump not committed on the root branch)"
|
|
40928
|
+
});
|
|
40929
|
+
}
|
|
40930
|
+
}
|
|
40931
|
+
} catch {
|
|
40932
|
+
}
|
|
40933
|
+
return {
|
|
40934
|
+
status: "failed",
|
|
40935
|
+
hasEffectiveDiff: false,
|
|
40936
|
+
baseHead,
|
|
40937
|
+
branchHead,
|
|
40938
|
+
...submoduleHints.length ? { submoduleHints } : {},
|
|
40939
|
+
durationMs: Date.now() - startedAt
|
|
40940
|
+
};
|
|
40941
|
+
} catch (e) {
|
|
40942
|
+
return {
|
|
40943
|
+
status: "skipped",
|
|
40944
|
+
hasEffectiveDiff: true,
|
|
40945
|
+
baseHead,
|
|
40946
|
+
branchHead,
|
|
40947
|
+
durationMs: Date.now() - startedAt,
|
|
40948
|
+
error: e?.message || String(e),
|
|
40949
|
+
stdout: truncateValidationOutput(e?.stdout),
|
|
40950
|
+
stderr: truncateValidationOutput(e?.stderr)
|
|
40951
|
+
};
|
|
40952
|
+
}
|
|
40953
|
+
}
|
|
40471
40954
|
function buildPatchEquivalenceSubmoduleConflictHint(repoRoot, baseHead, branchHead, output) {
|
|
40472
40955
|
if (!/(submodule|160000)/i.test(output) || !/(conflict|failed to merge)/i.test(output)) return void 0;
|
|
40473
40956
|
const conflicts = readChangedGitlinkPaths(repoRoot, baseHead, branchHead).map((path39) => ({
|
|
@@ -40524,6 +41007,135 @@ function readTreeObject(repoRoot, ref, path39) {
|
|
|
40524
41007
|
return void 0;
|
|
40525
41008
|
}
|
|
40526
41009
|
}
|
|
41010
|
+
function resolveGitDir(repoRoot) {
|
|
41011
|
+
const out = execFileSync5("git", ["rev-parse", "--absolute-git-dir"], {
|
|
41012
|
+
cwd: repoRoot,
|
|
41013
|
+
encoding: "utf8",
|
|
41014
|
+
maxBuffer: 1024 * 1024
|
|
41015
|
+
}).trim();
|
|
41016
|
+
return out;
|
|
41017
|
+
}
|
|
41018
|
+
function isSubmoduleFastForward(submoduleRepoPath, baseCommit, branchCommit) {
|
|
41019
|
+
if (!baseCommit || !branchCommit) return false;
|
|
41020
|
+
if (baseCommit === branchCommit) return true;
|
|
41021
|
+
try {
|
|
41022
|
+
if (!fs23.existsSync(submoduleRepoPath)) return false;
|
|
41023
|
+
execFileSync5("git", ["cat-file", "-e", `${baseCommit}^{commit}`], { cwd: submoduleRepoPath, stdio: "ignore" });
|
|
41024
|
+
execFileSync5("git", ["cat-file", "-e", `${branchCommit}^{commit}`], { cwd: submoduleRepoPath, stdio: "ignore" });
|
|
41025
|
+
execFileSync5("git", ["merge-base", "--is-ancestor", baseCommit, branchCommit], { cwd: submoduleRepoPath, stdio: "ignore" });
|
|
41026
|
+
return true;
|
|
41027
|
+
} catch {
|
|
41028
|
+
return false;
|
|
41029
|
+
}
|
|
41030
|
+
}
|
|
41031
|
+
function readChangedPathKinds(repoRoot, fromRef, toRef) {
|
|
41032
|
+
try {
|
|
41033
|
+
const output = execFileSync5("git", ["diff", "--raw", "--no-abbrev", fromRef, toRef], {
|
|
41034
|
+
cwd: repoRoot,
|
|
41035
|
+
encoding: "utf8",
|
|
41036
|
+
maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
|
|
41037
|
+
});
|
|
41038
|
+
const result = [];
|
|
41039
|
+
const seen = /* @__PURE__ */ new Set();
|
|
41040
|
+
for (const line of output.split("\n")) {
|
|
41041
|
+
if (!line.trim()) continue;
|
|
41042
|
+
const metaAndPath = line.split(" ");
|
|
41043
|
+
const meta = metaAndPath[0] || "";
|
|
41044
|
+
const path39 = metaAndPath[metaAndPath.length - 1]?.trim();
|
|
41045
|
+
if (!path39 || seen.has(path39)) continue;
|
|
41046
|
+
seen.add(path39);
|
|
41047
|
+
const parts = meta.split(/\s+/);
|
|
41048
|
+
const isGitlink = !!(parts[0]?.includes("160000") || parts[1]?.includes("160000"));
|
|
41049
|
+
result.push({ path: path39, isGitlink });
|
|
41050
|
+
}
|
|
41051
|
+
return result;
|
|
41052
|
+
} catch {
|
|
41053
|
+
return [];
|
|
41054
|
+
}
|
|
41055
|
+
}
|
|
41056
|
+
function evaluateGitlinkTrivialFastForward(repoRoot, baseHead, branchHead) {
|
|
41057
|
+
const changedGitlinks = readChangedGitlinkPaths(repoRoot, baseHead, branchHead).map((path39) => {
|
|
41058
|
+
const baseCommit = readTreeObject(repoRoot, baseHead, path39);
|
|
41059
|
+
const branchCommit = readTreeObject(repoRoot, branchHead, path39);
|
|
41060
|
+
const submoduleRepoPath = pathResolve2(repoRoot, path39);
|
|
41061
|
+
const fastForward = !!baseCommit && !!branchCommit && isSubmoduleFastForward(submoduleRepoPath, baseCommit, branchCommit);
|
|
41062
|
+
return { path: path39, baseCommit, branchCommit, fastForward };
|
|
41063
|
+
});
|
|
41064
|
+
if (changedGitlinks.length === 0) {
|
|
41065
|
+
return { trivial: false, reason: "no_changed_gitlinks", gitlinks: changedGitlinks };
|
|
41066
|
+
}
|
|
41067
|
+
const nonFastForward = changedGitlinks.filter((entry) => !entry.fastForward);
|
|
41068
|
+
if (nonFastForward.length > 0) {
|
|
41069
|
+
return {
|
|
41070
|
+
trivial: false,
|
|
41071
|
+
reason: `diverged_gitlinks:${nonFastForward.map((entry) => entry.path).join(",")}`,
|
|
41072
|
+
gitlinks: changedGitlinks
|
|
41073
|
+
};
|
|
41074
|
+
}
|
|
41075
|
+
let mergeBase = "";
|
|
41076
|
+
try {
|
|
41077
|
+
mergeBase = execFileSync5("git", ["merge-base", baseHead, branchHead], {
|
|
41078
|
+
cwd: repoRoot,
|
|
41079
|
+
encoding: "utf8",
|
|
41080
|
+
maxBuffer: 1024 * 1024
|
|
41081
|
+
}).trim();
|
|
41082
|
+
} catch {
|
|
41083
|
+
return { trivial: false, reason: "merge_base_unresolved", gitlinks: changedGitlinks };
|
|
41084
|
+
}
|
|
41085
|
+
if (!mergeBase) {
|
|
41086
|
+
return { trivial: false, reason: "merge_base_unresolved", gitlinks: changedGitlinks };
|
|
41087
|
+
}
|
|
41088
|
+
const baseSideChanges = readChangedPathKinds(repoRoot, mergeBase, baseHead);
|
|
41089
|
+
const branchSideChanges = readChangedPathKinds(repoRoot, mergeBase, branchHead);
|
|
41090
|
+
const baseChangedPaths = new Map(baseSideChanges.map((entry) => [entry.path, entry]));
|
|
41091
|
+
const overlapping = branchSideChanges.filter((entry) => baseChangedPaths.has(entry.path));
|
|
41092
|
+
const nonGitlinkOverlap = overlapping.filter((entry) => {
|
|
41093
|
+
const baseEntry = baseChangedPaths.get(entry.path);
|
|
41094
|
+
return !(entry.isGitlink && baseEntry?.isGitlink);
|
|
41095
|
+
});
|
|
41096
|
+
if (nonGitlinkOverlap.length > 0) {
|
|
41097
|
+
return {
|
|
41098
|
+
trivial: false,
|
|
41099
|
+
reason: `non_gitlink_overlap:${nonGitlinkOverlap.map((entry) => entry.path).join(",")}`,
|
|
41100
|
+
gitlinks: changedGitlinks
|
|
41101
|
+
};
|
|
41102
|
+
}
|
|
41103
|
+
return { trivial: true, gitlinks: changedGitlinks };
|
|
41104
|
+
}
|
|
41105
|
+
function synthesizeTrivialFastForwardMergeTree(repoRoot, baseHead, branchHead, gitlinks) {
|
|
41106
|
+
try {
|
|
41107
|
+
const baseTree = execFileSync5("git", ["rev-parse", `${baseHead}^{tree}`], {
|
|
41108
|
+
cwd: repoRoot,
|
|
41109
|
+
encoding: "utf8",
|
|
41110
|
+
maxBuffer: 1024 * 1024
|
|
41111
|
+
}).trim();
|
|
41112
|
+
if (!baseTree) return void 0;
|
|
41113
|
+
const updates = gitlinks.filter((entry) => entry.branchCommit).map((entry) => `160000 commit ${entry.branchCommit} ${entry.path}`).join("\n");
|
|
41114
|
+
if (!updates) return baseTree;
|
|
41115
|
+
const tmpIndex = pathJoin(resolveGitDir(repoRoot), `adhdev-refine-ff-${baseHead.slice(0, 12)}-${branchHead.slice(0, 12)}.index`);
|
|
41116
|
+
const env = { ...process.env, GIT_INDEX_FILE: tmpIndex };
|
|
41117
|
+
try {
|
|
41118
|
+
execFileSync5("git", ["read-tree", baseTree], { cwd: repoRoot, env, stdio: "ignore" });
|
|
41119
|
+
execFileSync5("git", ["update-index", "--index-info"], {
|
|
41120
|
+
cwd: repoRoot,
|
|
41121
|
+
env,
|
|
41122
|
+
input: `${updates}
|
|
41123
|
+
`,
|
|
41124
|
+
encoding: "utf8",
|
|
41125
|
+
stdio: ["pipe", "ignore", "ignore"]
|
|
41126
|
+
});
|
|
41127
|
+
const newTree = execFileSync5("git", ["write-tree"], { cwd: repoRoot, env, encoding: "utf8" }).trim();
|
|
41128
|
+
return newTree || void 0;
|
|
41129
|
+
} finally {
|
|
41130
|
+
try {
|
|
41131
|
+
fs23.rmSync(tmpIndex, { force: true });
|
|
41132
|
+
} catch {
|
|
41133
|
+
}
|
|
41134
|
+
}
|
|
41135
|
+
} catch {
|
|
41136
|
+
return void 0;
|
|
41137
|
+
}
|
|
41138
|
+
}
|
|
40527
41139
|
async function alignRefinerySubmodulesAfterMerge(repoRoot, previousBaseHead, currentHead, options = {}) {
|
|
40528
41140
|
const startedAt = Date.now();
|
|
40529
41141
|
const changedGitlinkPaths = readChangedGitlinkPaths(repoRoot, previousBaseHead, currentHead).filter((path39) => !(options.submoduleIgnorePaths || []).includes(path39));
|
|
@@ -41191,6 +41803,10 @@ var DaemonCommandRouter = class {
|
|
|
41191
41803
|
runningRefineJobs = /* @__PURE__ */ new Map();
|
|
41192
41804
|
/** Terminal async Refinery jobs preserve a clear answer after the worktree node has been removed. */
|
|
41193
41805
|
terminalRefineJobs = /* @__PURE__ */ new Map();
|
|
41806
|
+
/** In-memory async batch Refinery jobs keyed by meshId (one batch convergence per mesh at a time). */
|
|
41807
|
+
runningRefineBatchJobs = /* @__PURE__ */ new Map();
|
|
41808
|
+
/** Terminal async batch Refinery jobs preserve the last batch outcome for late readers. */
|
|
41809
|
+
terminalRefineBatchJobs = /* @__PURE__ */ new Map();
|
|
41194
41810
|
constructor(deps) {
|
|
41195
41811
|
this.deps = deps;
|
|
41196
41812
|
}
|
|
@@ -41268,13 +41884,13 @@ var DaemonCommandRouter = class {
|
|
|
41268
41884
|
};
|
|
41269
41885
|
}
|
|
41270
41886
|
getCachedAggregateMeshStatus(meshId, mesh, options) {
|
|
41271
|
-
const
|
|
41272
|
-
if (!
|
|
41273
|
-
if (
|
|
41274
|
-
let snapshot = this.cloneJsonValue(
|
|
41887
|
+
const cached2 = this.aggregateMeshStatusCache.get(meshId);
|
|
41888
|
+
if (!cached2?.snapshot || cached2.snapshot.success !== true || !Array.isArray(cached2.snapshot.nodes)) return null;
|
|
41889
|
+
if (cached2.queueRevision !== getMeshQueueRevision(meshId)) return null;
|
|
41890
|
+
let snapshot = this.cloneJsonValue(cached2.snapshot);
|
|
41275
41891
|
snapshot = this.hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options);
|
|
41276
41892
|
if (shouldRefreshStalePendingAggregate(snapshot, options)) return null;
|
|
41277
|
-
const ageMs = Math.max(0, Date.now() -
|
|
41893
|
+
const ageMs = Math.max(0, Date.now() - cached2.builtAt);
|
|
41278
41894
|
const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === "object" ? snapshot.sourceOfTruth : {};
|
|
41279
41895
|
snapshot.sourceOfTruth = {
|
|
41280
41896
|
...sourceOfTruth,
|
|
@@ -41285,7 +41901,7 @@ var DaemonCommandRouter = class {
|
|
|
41285
41901
|
source: "memory",
|
|
41286
41902
|
refreshReason: "memory_cache_hit",
|
|
41287
41903
|
ageMs,
|
|
41288
|
-
cachedAt: new Date(
|
|
41904
|
+
cachedAt: new Date(cached2.builtAt).toISOString(),
|
|
41289
41905
|
returnedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
41290
41906
|
}
|
|
41291
41907
|
};
|
|
@@ -41329,9 +41945,9 @@ var DaemonCommandRouter = class {
|
|
|
41329
41945
|
warmInlineMeshCache(meshId, inlineMesh) {
|
|
41330
41946
|
if (!inlineMesh || typeof inlineMesh !== "object") return void 0;
|
|
41331
41947
|
const sanitizedInlineMesh = sanitizeInlineMesh(inlineMesh);
|
|
41332
|
-
const
|
|
41333
|
-
if (
|
|
41334
|
-
const merged = reconcileInlineMeshCache(
|
|
41948
|
+
const cached2 = this.inlineMeshCache.get(meshId);
|
|
41949
|
+
if (cached2) {
|
|
41950
|
+
const merged = reconcileInlineMeshCache(cached2, sanitizedInlineMesh);
|
|
41335
41951
|
this.inlineMeshCache.set(meshId, merged);
|
|
41336
41952
|
return merged;
|
|
41337
41953
|
}
|
|
@@ -41341,14 +41957,14 @@ var DaemonCommandRouter = class {
|
|
|
41341
41957
|
async getMeshForCommand(meshId, inlineMesh, options) {
|
|
41342
41958
|
const preferInline = options?.preferInline === true;
|
|
41343
41959
|
if (preferInline) {
|
|
41344
|
-
const
|
|
41345
|
-
if (
|
|
41960
|
+
const cached3 = this.getCachedInlineMesh(meshId);
|
|
41961
|
+
if (cached3) {
|
|
41346
41962
|
if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
|
|
41347
|
-
const merged = reconcileInlineMeshCache(
|
|
41963
|
+
const merged = reconcileInlineMeshCache(cached3, inlineMesh);
|
|
41348
41964
|
this.inlineMeshCache.set(meshId, sanitizeInlineMesh(merged));
|
|
41349
41965
|
return { mesh: merged, inline: true, source: "inline_cache" };
|
|
41350
41966
|
}
|
|
41351
|
-
return { mesh:
|
|
41967
|
+
return { mesh: cached3, inline: true, source: "inline_cache" };
|
|
41352
41968
|
}
|
|
41353
41969
|
if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
|
|
41354
41970
|
this.warmInlineMeshCache(meshId, inlineMesh);
|
|
@@ -41361,8 +41977,8 @@ var DaemonCommandRouter = class {
|
|
|
41361
41977
|
if (mesh) return { mesh, inline: false, source: "local_config" };
|
|
41362
41978
|
} catch {
|
|
41363
41979
|
}
|
|
41364
|
-
const
|
|
41365
|
-
if (
|
|
41980
|
+
const cached2 = this.getCachedInlineMesh(meshId);
|
|
41981
|
+
if (cached2) return { mesh: cached2, inline: true, source: "inline_cache" };
|
|
41366
41982
|
const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
|
|
41367
41983
|
return warmedInline ? { mesh: warmedInline, inline: true, source: "inline_bootstrap" } : null;
|
|
41368
41984
|
}
|
|
@@ -41669,6 +42285,8 @@ var DaemonCommandRouter = class {
|
|
|
41669
42285
|
const skippedSessionIds = [];
|
|
41670
42286
|
const skippedLiveSessionIds = [];
|
|
41671
42287
|
const skippedCoordinatorSessionIds = [];
|
|
42288
|
+
const skippedLiveSessionReasons = [];
|
|
42289
|
+
const actedLiveDelegateSessionIds = [];
|
|
41672
42290
|
const deleteUnsupportedSessionIds = [];
|
|
41673
42291
|
const recordsRemainSessionIds = [];
|
|
41674
42292
|
const errors = [];
|
|
@@ -41702,16 +42320,31 @@ var DaemonCommandRouter = class {
|
|
|
41702
42320
|
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
41703
42321
|
const liveRuntime = surfaceKind === "live_runtime";
|
|
41704
42322
|
const coordinatorSession = readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId;
|
|
42323
|
+
const recordNodeId = readStringValue(record?.meta?.meshNodeId);
|
|
42324
|
+
const recordMeshNodeFor = readStringValue(record?.meta?.meshNodeFor);
|
|
42325
|
+
const delegateBoundToThisNode = !!recordNodeId && recordNodeId === args.nodeId && (!recordMeshNodeFor || recordMeshNodeFor === args.meshId);
|
|
41705
42326
|
if (!hasExplicitSessionIds && coordinatorSession) {
|
|
41706
42327
|
skippedSessionIds.push(sessionId);
|
|
41707
42328
|
skippedCoordinatorSessionIds.push(sessionId);
|
|
41708
42329
|
continue;
|
|
41709
42330
|
}
|
|
41710
|
-
if (!hasExplicitSessionIds && liveRuntime) {
|
|
42331
|
+
if (!hasExplicitSessionIds && liveRuntime && !delegateBoundToThisNode) {
|
|
42332
|
+
skippedSessionIds.push(sessionId);
|
|
42333
|
+
skippedLiveSessionIds.push(sessionId);
|
|
42334
|
+
const matchedByWorkspaceOnly = !recordNodeId;
|
|
42335
|
+
const reason = recordNodeId && recordNodeId !== args.nodeId ? `live_delegate_bound_to_other_node:${recordNodeId}` : matchedByWorkspaceOnly ? "live_session_matched_by_workspace_only_no_node_binding" : "live_session_not_bound_to_this_node";
|
|
42336
|
+
skippedLiveSessionReasons.push({ sessionId, reason });
|
|
42337
|
+
continue;
|
|
42338
|
+
}
|
|
42339
|
+
if (!hasExplicitSessionIds && liveRuntime && delegateBoundToThisNode && args.mode === "delete_stopped") {
|
|
41711
42340
|
skippedSessionIds.push(sessionId);
|
|
41712
42341
|
skippedLiveSessionIds.push(sessionId);
|
|
42342
|
+
skippedLiveSessionReasons.push({ sessionId, reason: "live_delegate_preserved_by_delete_stopped_mode_use_stop_or_stop_and_delete" });
|
|
41713
42343
|
continue;
|
|
41714
42344
|
}
|
|
42345
|
+
if (!hasExplicitSessionIds && liveRuntime && delegateBoundToThisNode) {
|
|
42346
|
+
actedLiveDelegateSessionIds.push(sessionId);
|
|
42347
|
+
}
|
|
41715
42348
|
try {
|
|
41716
42349
|
if (args.mode === "stop") {
|
|
41717
42350
|
if (!completed) {
|
|
@@ -41773,6 +42406,8 @@ var DaemonCommandRouter = class {
|
|
|
41773
42406
|
skippedSessionIds,
|
|
41774
42407
|
skippedLiveSessionIds,
|
|
41775
42408
|
skippedCoordinatorSessionIds,
|
|
42409
|
+
...actedLiveDelegateSessionIds.length ? { actedLiveDelegateSessionIds } : {},
|
|
42410
|
+
...skippedLiveSessionReasons.length ? { skippedLiveSessionReasons } : {},
|
|
41776
42411
|
...deleteUnsupported ? {
|
|
41777
42412
|
deleteUnsupported: true,
|
|
41778
42413
|
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
@@ -42420,6 +43055,48 @@ ${tail}` : ""
|
|
|
42420
43055
|
}
|
|
42421
43056
|
};
|
|
42422
43057
|
}
|
|
43058
|
+
const effectiveDiffStarted = Date.now();
|
|
43059
|
+
const effectiveDiff = await runMeshRefineEffectiveDiffGate(repoRoot, baseHead, branchHead);
|
|
43060
|
+
recordMeshRefineStage(refineStages, "effective_diff", effectiveDiff.status, effectiveDiffStarted, {
|
|
43061
|
+
hasEffectiveDiff: effectiveDiff.hasEffectiveDiff,
|
|
43062
|
+
changedPaths: effectiveDiff.changedPaths,
|
|
43063
|
+
submoduleHints: effectiveDiff.submoduleHints,
|
|
43064
|
+
...effectiveDiff.error ? { error: effectiveDiff.error } : {}
|
|
43065
|
+
});
|
|
43066
|
+
if (effectiveDiff.status === "failed" && !effectiveDiff.hasEffectiveDiff) {
|
|
43067
|
+
const hintLines = (effectiveDiff.submoduleHints || []).map((h) => ` - ${h.path}: ${h.reason}`);
|
|
43068
|
+
const message = [
|
|
43069
|
+
`Refinery no-op guard: branch '${branch}' has no effective root-tree diff against '${baseBranch}' (${baseHead.slice(0, 12)}); nothing would merge.`,
|
|
43070
|
+
"This usually means a submodule (e.g. oss) has commits but the root branch never committed the gitlink (pointer) bump, so the merge would be a silent no-op while the real change never reaches main.",
|
|
43071
|
+
hintLines.length ? `Submodules with uncommitted pointer bumps:
|
|
43072
|
+
${hintLines.join("\n")}` : "",
|
|
43073
|
+
`Fix: commit the submodule pointer bump on '${branch}' (git add <submodule-path> && git commit), then re-run refine.`
|
|
43074
|
+
].filter(Boolean).join("\n");
|
|
43075
|
+
return {
|
|
43076
|
+
success: false,
|
|
43077
|
+
code: "no_effective_diff",
|
|
43078
|
+
convergenceStatus: "blocked_review",
|
|
43079
|
+
error: message,
|
|
43080
|
+
branch,
|
|
43081
|
+
into: baseBranch,
|
|
43082
|
+
validationSummary,
|
|
43083
|
+
patchEquivalence,
|
|
43084
|
+
effectiveDiff,
|
|
43085
|
+
refineStages,
|
|
43086
|
+
finalBranchConvergenceState: {
|
|
43087
|
+
branch,
|
|
43088
|
+
baseBranch,
|
|
43089
|
+
merged: false,
|
|
43090
|
+
removed: false,
|
|
43091
|
+
validation: "passed",
|
|
43092
|
+
patchEquivalence: "passed",
|
|
43093
|
+
effectiveDiff: "no_effective_diff",
|
|
43094
|
+
status: "blocked_review",
|
|
43095
|
+
reason: "no_effective_diff",
|
|
43096
|
+
...effectiveDiff.submoduleHints?.length ? { submoduleHints: effectiveDiff.submoduleHints } : {}
|
|
43097
|
+
}
|
|
43098
|
+
};
|
|
43099
|
+
}
|
|
42423
43100
|
let mergeResult;
|
|
42424
43101
|
const mergeStarted = Date.now();
|
|
42425
43102
|
try {
|
|
@@ -42658,8 +43335,8 @@ ${tail}` : ""
|
|
|
42658
43335
|
const repoRootBaseRef = /* @__PURE__ */ new Map();
|
|
42659
43336
|
const submodulePathsByRepoRoot = /* @__PURE__ */ new Map();
|
|
42660
43337
|
const resolveBaseRef = async (repoRoot) => {
|
|
42661
|
-
const
|
|
42662
|
-
if (
|
|
43338
|
+
const cached2 = repoRootBaseRef.get(repoRoot);
|
|
43339
|
+
if (cached2) return cached2;
|
|
42663
43340
|
let baseBranch = "main";
|
|
42664
43341
|
try {
|
|
42665
43342
|
const { stdout } = await execFileAsync4("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
|
|
@@ -42761,6 +43438,17 @@ ${tail}` : ""
|
|
|
42761
43438
|
note: "Dry-run: no validation, rebase, or merge was executed. Re-run with execute=true to converge nodes in this order."
|
|
42762
43439
|
};
|
|
42763
43440
|
}
|
|
43441
|
+
return this.runMeshRefineBatchConvergence(meshId, orderedNodes, ordering, args);
|
|
43442
|
+
}
|
|
43443
|
+
/**
|
|
43444
|
+
* Convergence core shared by the synchronous batch entry and the async batch job.
|
|
43445
|
+
* Refines each node in order: the per-node refine pipeline fetches origin/<base>
|
|
43446
|
+
* fresh, so each merged sibling advances the base before the next node's auto-rebase
|
|
43447
|
+
* + patch-equivalence re-check. A blocked/failed node is isolated; the batch
|
|
43448
|
+
* continues with the remaining nodes. Does NOT touch the per-node merge logic — it
|
|
43449
|
+
* only sequences calls to executeMeshRefineNodeSynchronously and aggregates outcomes.
|
|
43450
|
+
*/
|
|
43451
|
+
async runMeshRefineBatchConvergence(meshId, orderedNodes, ordering, args) {
|
|
42764
43452
|
const results = [];
|
|
42765
43453
|
for (const node of orderedNodes) {
|
|
42766
43454
|
let result;
|
|
@@ -42815,6 +43503,204 @@ ${tail}` : ""
|
|
|
42815
43503
|
}
|
|
42816
43504
|
};
|
|
42817
43505
|
}
|
|
43506
|
+
buildRefineBatchJobKey(meshId) {
|
|
43507
|
+
return `${meshId}::batch`;
|
|
43508
|
+
}
|
|
43509
|
+
buildRefineBatchJobHandle(args) {
|
|
43510
|
+
return {
|
|
43511
|
+
success: true,
|
|
43512
|
+
async: true,
|
|
43513
|
+
batch: true,
|
|
43514
|
+
status: args.status || "accepted",
|
|
43515
|
+
jobId: args.jobId || `refine_batch_${createInteractionId()}`,
|
|
43516
|
+
interactionId: args.interactionId || createInteractionId(),
|
|
43517
|
+
meshId: args.meshId,
|
|
43518
|
+
batchLabel: `batch:${args.nodeIds.length} node${args.nodeIds.length === 1 ? "" : "s"}`,
|
|
43519
|
+
nodeIds: args.nodeIds,
|
|
43520
|
+
nodeCount: args.nodeIds.length,
|
|
43521
|
+
order: args.order,
|
|
43522
|
+
startedAt: args.startedAt || (/* @__PURE__ */ new Date()).toISOString(),
|
|
43523
|
+
...args.completedAt ? { completedAt: args.completedAt } : {},
|
|
43524
|
+
...args.coordinatorDaemonId ? { targetCoordinatorDaemonId: args.coordinatorDaemonId } : {},
|
|
43525
|
+
eventDelivery: { pendingEvents: true, ledger: true },
|
|
43526
|
+
evidence: {
|
|
43527
|
+
pendingEventsCommand: "get_pending_mesh_events",
|
|
43528
|
+
ledgerCommand: "get_mesh_ledger_slice",
|
|
43529
|
+
taskHistoryKind: args.status === "completed" ? "task_completed" : args.status === "failed" ? "task_failed" : "task_dispatched"
|
|
43530
|
+
}
|
|
43531
|
+
};
|
|
43532
|
+
}
|
|
43533
|
+
/**
|
|
43534
|
+
* Emit a batch Refinery terminal/accepted event through the SAME pending-event +
|
|
43535
|
+
* forward mechanism single-node refine uses (queueRefineJobEvent), so the
|
|
43536
|
+
* coordinator's existing refine:accepted/completed/failed handling and message
|
|
43537
|
+
* renderer apply unchanged. The aggregate per-node results ride along in `result`.
|
|
43538
|
+
*/
|
|
43539
|
+
queueRefineBatchJobEvent(event, handle, result) {
|
|
43540
|
+
const metadataEvent = {
|
|
43541
|
+
source: "refine_mesh_node_async_job",
|
|
43542
|
+
batch: true,
|
|
43543
|
+
jobId: handle.jobId,
|
|
43544
|
+
interactionId: handle.interactionId,
|
|
43545
|
+
meshId: handle.meshId,
|
|
43546
|
+
nodeId: handle.batchLabel,
|
|
43547
|
+
nodeIds: handle.nodeIds,
|
|
43548
|
+
workspace: void 0,
|
|
43549
|
+
status: handle.status,
|
|
43550
|
+
startedAt: handle.startedAt,
|
|
43551
|
+
completedAt: handle.completedAt,
|
|
43552
|
+
order: handle.order,
|
|
43553
|
+
...result ? { result } : {}
|
|
43554
|
+
};
|
|
43555
|
+
const eventPayload = {
|
|
43556
|
+
event,
|
|
43557
|
+
meshId: handle.meshId,
|
|
43558
|
+
nodeLabel: handle.batchLabel,
|
|
43559
|
+
nodeId: handle.batchLabel,
|
|
43560
|
+
metadataEvent,
|
|
43561
|
+
queuedAt: Date.now(),
|
|
43562
|
+
...handle.targetCoordinatorDaemonId ? { targetCoordinatorDaemonId: handle.targetCoordinatorDaemonId } : {}
|
|
43563
|
+
};
|
|
43564
|
+
if (typeof this.deps.instanceManager?.getByCategory === "function") {
|
|
43565
|
+
const forwarded = handleMeshForwardEvent(
|
|
43566
|
+
{ instanceManager: this.deps.instanceManager },
|
|
43567
|
+
{
|
|
43568
|
+
event,
|
|
43569
|
+
meshId: handle.meshId,
|
|
43570
|
+
nodeId: handle.batchLabel,
|
|
43571
|
+
jobId: handle.jobId,
|
|
43572
|
+
interactionId: handle.interactionId,
|
|
43573
|
+
status: handle.status,
|
|
43574
|
+
startedAt: handle.startedAt,
|
|
43575
|
+
completedAt: handle.completedAt,
|
|
43576
|
+
...result ? { result } : {}
|
|
43577
|
+
}
|
|
43578
|
+
);
|
|
43579
|
+
if (forwarded?.success === true) return;
|
|
43580
|
+
LOG.warn("Mesh", `[Refinery] Failed to forward async refine batch event ${event}: ${forwarded?.error || "unknown error"}`);
|
|
43581
|
+
}
|
|
43582
|
+
queuePendingMeshCoordinatorEvent(eventPayload);
|
|
43583
|
+
}
|
|
43584
|
+
async appendRefineBatchJobLedger(kind, handle, result) {
|
|
43585
|
+
try {
|
|
43586
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
43587
|
+
appendLedgerEntry2(handle.meshId, {
|
|
43588
|
+
kind,
|
|
43589
|
+
nodeId: handle.batchLabel,
|
|
43590
|
+
payload: {
|
|
43591
|
+
source: "refine_mesh_node_async_job",
|
|
43592
|
+
refineJob: {
|
|
43593
|
+
batch: true,
|
|
43594
|
+
jobId: handle.jobId,
|
|
43595
|
+
interactionId: handle.interactionId,
|
|
43596
|
+
status: handle.status,
|
|
43597
|
+
meshId: handle.meshId,
|
|
43598
|
+
nodeIds: handle.nodeIds,
|
|
43599
|
+
order: handle.order,
|
|
43600
|
+
targetCoordinatorDaemonId: handle.targetCoordinatorDaemonId,
|
|
43601
|
+
startedAt: handle.startedAt,
|
|
43602
|
+
completedAt: handle.completedAt
|
|
43603
|
+
},
|
|
43604
|
+
async: true,
|
|
43605
|
+
batch: true,
|
|
43606
|
+
...result ? {
|
|
43607
|
+
success: result.success === true,
|
|
43608
|
+
result
|
|
43609
|
+
} : {}
|
|
43610
|
+
}
|
|
43611
|
+
});
|
|
43612
|
+
} catch (e) {
|
|
43613
|
+
LOG.warn("Mesh", `[Refinery] Failed to append async refine batch ledger entry: ${e?.message || e}`);
|
|
43614
|
+
}
|
|
43615
|
+
}
|
|
43616
|
+
async finishMeshRefineBatchJob(handle, orderedNodes, ordering, args) {
|
|
43617
|
+
const key = this.buildRefineBatchJobKey(handle.meshId);
|
|
43618
|
+
let result;
|
|
43619
|
+
try {
|
|
43620
|
+
result = await this.runMeshRefineBatchConvergence(handle.meshId, orderedNodes, ordering, args);
|
|
43621
|
+
} catch (e) {
|
|
43622
|
+
result = { success: false, error: e?.message || String(e), batch: true };
|
|
43623
|
+
}
|
|
43624
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
43625
|
+
const summary = result.summary && typeof result.summary === "object" ? result.summary : void 0;
|
|
43626
|
+
const allConverged = result.allConverged === true;
|
|
43627
|
+
const isTerminalSuccess = result.success === true && allConverged;
|
|
43628
|
+
const nextStep = typeof result.nextStep === "string" && result.nextStep ? result.nextStep : isTerminalSuccess ? "All batched nodes converged onto base. Continue from the updated mesh state." : "Resolve blocked_review / not_mergeable nodes (see per-node code/stage/error in result.results), then re-run mesh_refine_batch for the remaining nodes.";
|
|
43629
|
+
const normalizedResult = {
|
|
43630
|
+
...result,
|
|
43631
|
+
batch: true,
|
|
43632
|
+
nextStep,
|
|
43633
|
+
...summary ? {
|
|
43634
|
+
convergenceStatus: allConverged ? "all_converged" : "partial"
|
|
43635
|
+
} : {}
|
|
43636
|
+
};
|
|
43637
|
+
const terminalHandle = this.buildRefineBatchJobHandle({
|
|
43638
|
+
meshId: handle.meshId,
|
|
43639
|
+
nodeIds: handle.nodeIds,
|
|
43640
|
+
order: handle.order,
|
|
43641
|
+
status: isTerminalSuccess ? "completed" : "failed",
|
|
43642
|
+
startedAt: handle.startedAt,
|
|
43643
|
+
completedAt,
|
|
43644
|
+
jobId: handle.jobId,
|
|
43645
|
+
interactionId: handle.interactionId,
|
|
43646
|
+
coordinatorDaemonId: handle.targetCoordinatorDaemonId
|
|
43647
|
+
});
|
|
43648
|
+
const terminal = { ...terminalHandle, result: normalizedResult };
|
|
43649
|
+
this.terminalRefineBatchJobs.set(key, terminal);
|
|
43650
|
+
this.runningRefineBatchJobs.delete(key);
|
|
43651
|
+
this.invalidateAggregateMeshStatus(handle.meshId);
|
|
43652
|
+
await this.appendRefineBatchJobLedger(isTerminalSuccess ? "task_completed" : "task_failed", terminalHandle, normalizedResult);
|
|
43653
|
+
this.queueRefineBatchJobEvent(isTerminalSuccess ? "refine:completed" : "refine:failed", terminalHandle, normalizedResult);
|
|
43654
|
+
}
|
|
43655
|
+
/**
|
|
43656
|
+
* Async entry for the batch Refinery execute path. Mirrors startMeshRefineJob:
|
|
43657
|
+
* resolves the plan synchronously (so target/ordering errors and the dry-run shape
|
|
43658
|
+
* stay synchronous), then for execute=true registers an in-flight batch job, returns
|
|
43659
|
+
* {async:true, status:'accepted', batch:true, ...plan} immediately, and runs the
|
|
43660
|
+
* convergence loop in the background — emitting the same terminal refine event.
|
|
43661
|
+
* Idempotent: a batch already in flight for this mesh returns the running handle
|
|
43662
|
+
* with duplicate:true rather than spawning a second background job.
|
|
43663
|
+
*/
|
|
43664
|
+
async startMeshRefineBatchJob(meshId, requestedNodeIds, args) {
|
|
43665
|
+
const plan = await this.batchRefineMeshNodes(meshId, requestedNodeIds, { ...args, dryRun: true, execute: false });
|
|
43666
|
+
const planRecord = plan;
|
|
43667
|
+
if (planRecord.success !== true) return plan;
|
|
43668
|
+
if (args?.dryRun === true && args?.execute !== true) return plan;
|
|
43669
|
+
const order = Array.isArray(planRecord.order) ? planRecord.order.filter((v) => typeof v === "string") : [];
|
|
43670
|
+
const nodeIds = order.slice();
|
|
43671
|
+
if (nodeIds.length === 0) {
|
|
43672
|
+
return { ...planRecord, success: true, batch: true, dryRun: false, async: false };
|
|
43673
|
+
}
|
|
43674
|
+
const key = this.buildRefineBatchJobKey(meshId);
|
|
43675
|
+
const running = this.runningRefineBatchJobs.get(key);
|
|
43676
|
+
if (running) return { ...running, duplicate: true };
|
|
43677
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
43678
|
+
const mesh = meshRecord?.mesh;
|
|
43679
|
+
const allNodes = Array.isArray(mesh?.nodes) ? mesh.nodes : [];
|
|
43680
|
+
const orderedNodes = nodeIds.map((id) => allNodes.find((n) => n.id === id || n.nodeId === id)).filter((n) => !!n);
|
|
43681
|
+
if (orderedNodes.length === 0) {
|
|
43682
|
+
return { success: false, error: "Batch nodes no longer resolvable in mesh", batch: true };
|
|
43683
|
+
}
|
|
43684
|
+
const ordering = {
|
|
43685
|
+
order,
|
|
43686
|
+
rationale: planRecord.orderingRationale
|
|
43687
|
+
};
|
|
43688
|
+
const coordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : this.deps.statusInstanceId || void 0;
|
|
43689
|
+
const handle = this.buildRefineBatchJobHandle({ meshId, nodeIds, order, coordinatorDaemonId });
|
|
43690
|
+
this.runningRefineBatchJobs.set(key, handle);
|
|
43691
|
+
await this.appendRefineBatchJobLedger("task_dispatched", handle);
|
|
43692
|
+
this.queueRefineBatchJobEvent("refine:accepted", handle);
|
|
43693
|
+
setImmediate(() => {
|
|
43694
|
+
void this.finishMeshRefineBatchJob(handle, orderedNodes, ordering, args);
|
|
43695
|
+
});
|
|
43696
|
+
return {
|
|
43697
|
+
...handle,
|
|
43698
|
+
order,
|
|
43699
|
+
orderingRationale: planRecord.orderingRationale,
|
|
43700
|
+
plan: planRecord.plan,
|
|
43701
|
+
note: "Batch convergence accepted and running in the background. Completion/failure (with per-node results) will be delivered as a terminal refine event; do not poll repeatedly."
|
|
43702
|
+
};
|
|
43703
|
+
}
|
|
42818
43704
|
async finishMeshRefineJob(handle, args) {
|
|
42819
43705
|
const key = this.buildRefineJobKey(handle.meshId, handle.targetNodeId);
|
|
42820
43706
|
let result;
|
|
@@ -43348,7 +44234,7 @@ ${tail}` : ""
|
|
|
43348
44234
|
version: this.deps.statusVersion || "unknown",
|
|
43349
44235
|
profile: "metadata"
|
|
43350
44236
|
});
|
|
43351
|
-
return { success: true, status: snapshot };
|
|
44237
|
+
return { success: true, status: snapshot, daemonBuild: getDaemonBuildInfo() };
|
|
43352
44238
|
}
|
|
43353
44239
|
case "get_machine_runtime_stats": {
|
|
43354
44240
|
return {
|
|
@@ -44318,6 +45204,7 @@ ${tail}` : ""
|
|
|
44318
45204
|
let workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
44319
45205
|
let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
|
|
44320
45206
|
let nodeDaemonId;
|
|
45207
|
+
let allowAutoPublishSubmoduleMainCommits = false;
|
|
44321
45208
|
if (meshId && nodeId) {
|
|
44322
45209
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
44323
45210
|
const mesh = meshRecord?.mesh;
|
|
@@ -44328,6 +45215,7 @@ ${tail}` : ""
|
|
|
44328
45215
|
if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
|
|
44329
45216
|
submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
|
|
44330
45217
|
}
|
|
45218
|
+
allowAutoPublishSubmoduleMainCommits = mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true;
|
|
44331
45219
|
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
44332
45220
|
}
|
|
44333
45221
|
const selfDaemonId = this.deps.statusInstanceId;
|
|
@@ -44348,7 +45236,10 @@ ${tail}` : ""
|
|
|
44348
45236
|
execute: args?.execute === true,
|
|
44349
45237
|
dryRun: args?.dryRun === true,
|
|
44350
45238
|
updateSubmodules: args?.updateSubmodules === true,
|
|
44351
|
-
submoduleIgnorePaths
|
|
45239
|
+
submoduleIgnorePaths,
|
|
45240
|
+
mode: args?.mode === "push" ? "push" : "merge",
|
|
45241
|
+
pushSubmodules: args?.pushSubmodules === true,
|
|
45242
|
+
allowAutoPublishSubmoduleMainCommits
|
|
44352
45243
|
});
|
|
44353
45244
|
return result;
|
|
44354
45245
|
}
|
|
@@ -44362,7 +45253,9 @@ ${tail}` : ""
|
|
|
44362
45253
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
44363
45254
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
44364
45255
|
const requestedNodeIds = Array.isArray(args?.nodeIds) ? args.nodeIds.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim()) : void 0;
|
|
44365
|
-
|
|
45256
|
+
const isDryRun = args?.dryRun !== false && args?.execute !== true;
|
|
45257
|
+
if (isDryRun) return this.batchRefineMeshNodes(meshId, requestedNodeIds, args);
|
|
45258
|
+
return this.startMeshRefineBatchJob(meshId, requestedNodeIds, args);
|
|
44366
45259
|
}
|
|
44367
45260
|
case "remove_mesh_node": {
|
|
44368
45261
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
@@ -46046,6 +46939,7 @@ var DaemonStatusReporter = class {
|
|
|
46046
46939
|
};
|
|
46047
46940
|
|
|
46048
46941
|
// src/index.ts
|
|
46942
|
+
init_build_info();
|
|
46049
46943
|
init_logger();
|
|
46050
46944
|
init_debug_config();
|
|
46051
46945
|
|
|
@@ -54323,6 +55217,7 @@ export {
|
|
|
54323
55217
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
54324
55218
|
NodePtyTransportFactory,
|
|
54325
55219
|
P2pRelayFailureError,
|
|
55220
|
+
PRUNABLE_ORPHAN_STALE_REASONS,
|
|
54326
55221
|
ProviderCliAdapter,
|
|
54327
55222
|
ProviderInstanceManager,
|
|
54328
55223
|
ProviderLoader,
|
|
@@ -54376,6 +55271,7 @@ export {
|
|
|
54376
55271
|
classifyChatMessageVisibility,
|
|
54377
55272
|
classifyHotChatSessionsForSubscriptionFlush,
|
|
54378
55273
|
classifyP2pRelayFailure,
|
|
55274
|
+
classifyStaleDirectForPrune,
|
|
54379
55275
|
cleanupTerminalDirectDispatches,
|
|
54380
55276
|
clearDebugTrace,
|
|
54381
55277
|
clearPendingMeshCoordinatorEvents,
|
|
@@ -54395,6 +55291,7 @@ export {
|
|
|
54395
55291
|
createNativeHistoryDispatcher,
|
|
54396
55292
|
createSessionDelivery,
|
|
54397
55293
|
createWorktree,
|
|
55294
|
+
deleteDirectDispatchesByTaskId,
|
|
54398
55295
|
deleteMesh,
|
|
54399
55296
|
deriveMeshReviewInboxItems,
|
|
54400
55297
|
describeTaskDependencyState,
|
|
@@ -54423,6 +55320,7 @@ export {
|
|
|
54423
55320
|
getAvailableIdeIds,
|
|
54424
55321
|
getCoordinatorForSession,
|
|
54425
55322
|
getCurrentDaemonLogPath,
|
|
55323
|
+
getDaemonBuildInfo,
|
|
54426
55324
|
getDaemonDataDir,
|
|
54427
55325
|
getDaemonLogDir,
|
|
54428
55326
|
getDebugRuntimeConfig,
|