@adhdev/daemon-standalone 0.9.82-rc.262 → 0.9.82-rc.264

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 CHANGED
@@ -29965,6 +29965,27 @@ var require_dist3 = __commonJS({
29965
29965
  };
29966
29966
  }
29967
29967
  });
29968
+ function readInjected(value) {
29969
+ if (typeof value !== "string") return void 0;
29970
+ const trimmed = value.trim();
29971
+ if (!trimmed || trimmed === "unknown") return void 0;
29972
+ return trimmed;
29973
+ }
29974
+ function getDaemonBuildInfo() {
29975
+ if (cached2) return cached2;
29976
+ const commit = readInjected(true ? "751232919b0935654ee3d75d7cee4607594d6836" : void 0) ?? "unknown";
29977
+ const commitShort = readInjected(true ? "7512329" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
29978
+ const version2 = readInjected(true ? "0.9.82-rc.264" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
29979
+ const builtAt = readInjected(true ? "2026-06-14T15:25:15.217Z" : void 0);
29980
+ cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
29981
+ return cached2;
29982
+ }
29983
+ var cached2;
29984
+ var init_build_info = __esm2({
29985
+ "src/build-info.ts"() {
29986
+ "use strict";
29987
+ }
29988
+ });
29968
29989
  async function getGitRepoStatus(workspace, options = {}) {
29969
29990
  const lastCheckedAt = Date.now();
29970
29991
  const includeSubmodules = options.includeSubmodules !== false;
@@ -29986,6 +30007,7 @@ var require_dist3 = __commonJS({
29986
30007
  }
29987
30008
  const submoduleDirty = (submodules || []).some((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error);
29988
30009
  const dirty = parsed.staged + parsed.modified + parsed.untracked + parsed.deleted + parsed.renamed > 0 || parsed.conflictFiles.length > 0 || stashCount > 0 || submoduleDirty;
30010
+ const daemonBuildBehind = await detectDaemonBuildBehind(repo, submodules, options);
29989
30011
  return {
29990
30012
  workspace: repo.workspace,
29991
30013
  repoRoot: repo.repoRoot,
@@ -30009,7 +30031,8 @@ var require_dist3 = __commonJS({
30009
30031
  conflictFiles: parsed.conflictFiles,
30010
30032
  stashCount,
30011
30033
  lastCheckedAt,
30012
- submodules
30034
+ submodules,
30035
+ ...daemonBuildBehind ? { daemonBuildBehind } : {}
30013
30036
  };
30014
30037
  } catch (error48) {
30015
30038
  if (error48 instanceof GitCommandError) {
@@ -30022,6 +30045,68 @@ var require_dist3 = __commonJS({
30022
30045
  );
30023
30046
  }
30024
30047
  }
30048
+ async function classifyDaemonBuildChange(repoPath, buildCommit, options) {
30049
+ try {
30050
+ const diff = await runGit(repoPath, ["diff", "--name-only", `${buildCommit}..HEAD`], options);
30051
+ const files = diff.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
30052
+ if (files.length === 0) {
30053
+ return { isDaemonAffecting: true, affectedPackages: [] };
30054
+ }
30055
+ const pkgs = /* @__PURE__ */ new Set();
30056
+ let sawNonPackageOrUnknown = false;
30057
+ for (const file2 of files) {
30058
+ const match = file2.match(/(?:^|\/)packages\/([^/]+)\//);
30059
+ if (!match) {
30060
+ sawNonPackageOrUnknown = true;
30061
+ continue;
30062
+ }
30063
+ pkgs.add(match[1]);
30064
+ }
30065
+ const affectedPackages = [...pkgs].sort();
30066
+ const allWebOnly = !sawNonPackageOrUnknown && affectedPackages.length > 0 && affectedPackages.every((p) => WEB_ONLY_PACKAGES.has(p) && !DAEMON_RUNTIME_PACKAGES.has(p));
30067
+ return { isDaemonAffecting: !allWebOnly, affectedPackages };
30068
+ } catch {
30069
+ return { isDaemonAffecting: true, affectedPackages: [] };
30070
+ }
30071
+ }
30072
+ async function detectDaemonBuildBehind(repo, submodules, options) {
30073
+ const build = options.daemonBuildInfo ?? getDaemonBuildInfo();
30074
+ if (!build.commit || build.commit === "unknown") return void 0;
30075
+ const scopes = [
30076
+ { scope: "root", repoPath: repo.repoRoot || repo.workspace }
30077
+ ];
30078
+ for (const sub of submodules || []) {
30079
+ if (sub.repoPath && !sub.error) scopes.push({ scope: sub.path, repoPath: sub.repoPath });
30080
+ }
30081
+ for (const { scope, repoPath } of scopes) {
30082
+ try {
30083
+ await runGit(repoPath, ["cat-file", "-e", `${build.commit}^{commit}`], options);
30084
+ const headResult = await runGit(repoPath, ["rev-parse", "HEAD"], options);
30085
+ const head = headResult.stdout.trim();
30086
+ if (!head || head === build.commit) continue;
30087
+ await runGit(repoPath, ["merge-base", "--is-ancestor", build.commit, "HEAD"], options);
30088
+ const { isDaemonAffecting, affectedPackages } = await classifyDaemonBuildChange(
30089
+ repoPath,
30090
+ build.commit,
30091
+ options
30092
+ );
30093
+ const scopeLabel = scope === "root" ? "workspace" : scope;
30094
+ const warning = isDaemonAffecting ? `Live daemon was built from ${build.commitShort} which is behind ${scopeLabel} 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.` : `Live daemon was built from ${build.commitShort} which is behind ${scopeLabel} HEAD ${head.slice(0, 7)}, but only web packages changed (${(affectedPackages || []).join(", ") || "web"}). Daemon restart NOT required \u2014 redeploy the web app to reflect the change.`;
30095
+ return {
30096
+ buildCommit: build.commit,
30097
+ buildCommitShort: build.commitShort,
30098
+ head,
30099
+ scope,
30100
+ isDaemonAffecting,
30101
+ ...affectedPackages && affectedPackages.length > 0 ? { affectedPackages } : {},
30102
+ warning
30103
+ };
30104
+ } catch {
30105
+ continue;
30106
+ }
30107
+ }
30108
+ return void 0;
30109
+ }
30025
30110
  async function readPorcelainStatus(repo, options) {
30026
30111
  const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
30027
30112
  return parsePorcelainV2Status(statusOutput.stdout);
@@ -30234,10 +30319,30 @@ var require_dist3 = __commonJS({
30234
30319
  }
30235
30320
  return submodules;
30236
30321
  }
30322
+ var DAEMON_RUNTIME_PACKAGES;
30323
+ var WEB_ONLY_PACKAGES;
30237
30324
  var init_git_status = __esm2({
30238
30325
  "src/git/git-status.ts"() {
30239
30326
  "use strict";
30240
30327
  init_git_executor();
30328
+ init_build_info();
30329
+ DAEMON_RUNTIME_PACKAGES = /* @__PURE__ */ new Set([
30330
+ "daemon-core",
30331
+ "daemon-standalone",
30332
+ "session-host-core",
30333
+ "session-host-daemon",
30334
+ "terminal-mux-core",
30335
+ "terminal-mux-control",
30336
+ "terminal-mux-cli",
30337
+ "ghostty-vt-node",
30338
+ "mcp-server"
30339
+ ]);
30340
+ WEB_ONLY_PACKAGES = /* @__PURE__ */ new Set([
30341
+ "web-core",
30342
+ "web-standalone",
30343
+ "web-devconsole",
30344
+ "terminal-render-web"
30345
+ ]);
30241
30346
  }
30242
30347
  });
30243
30348
  var git_diff_exports = {};
@@ -32106,8 +32211,8 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
32106
32211
  }
32107
32212
  function getCachedRawEntries(meshId) {
32108
32213
  const now = Date.now();
32109
- const cached2 = ledgerReadCache.get(meshId);
32110
- if (cached2 && now - cached2.cachedAt < LEDGER_CACHE_TTL_MS) return cached2.entries;
32214
+ const cached22 = ledgerReadCache.get(meshId);
32215
+ if (cached22 && now - cached22.cachedAt < LEDGER_CACHE_TTL_MS) return cached22.entries;
32111
32216
  let entries;
32112
32217
  try {
32113
32218
  entries = readLedgerFromStore(meshId);
@@ -32384,6 +32489,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
32384
32489
  cancelTask: () => cancelTask,
32385
32490
  claimNextTask: () => claimNextTask,
32386
32491
  cleanupTerminalDirectDispatches: () => cleanupTerminalDirectDispatches,
32492
+ deleteDirectDispatchesByTaskId: () => deleteDirectDispatchesByTaskId,
32387
32493
  describeTaskDependencyState: () => describeTaskDependencyState,
32388
32494
  enqueueTask: () => enqueueTask,
32389
32495
  getActiveDirectDispatches: () => getActiveDirectDispatches,
@@ -32792,6 +32898,13 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
32792
32898
  } catch {
32793
32899
  }
32794
32900
  }
32901
+ function deleteDirectDispatchesByTaskId(meshId, taskIds) {
32902
+ try {
32903
+ return MeshRuntimeStore.getInstance().deleteDirectDispatchesByTaskId(meshId, taskIds);
32904
+ } catch {
32905
+ return 0;
32906
+ }
32907
+ }
32795
32908
  function recordMeshToolCall(opts) {
32796
32909
  try {
32797
32910
  return MeshRuntimeStore.getInstance().recordMeshToolCall(opts);
@@ -33435,6 +33548,24 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
33435
33548
  deleteDirectDispatches(meshId) {
33436
33549
  this.db.prepare(`DELETE FROM mesh_direct_dispatches WHERE mesh_id = ?`).run(meshId);
33437
33550
  }
33551
+ /**
33552
+ * Delete specific direct dispatch rows by taskId for a mesh. Used by the staleDirect prune
33553
+ * path to remove orphaned/terminal dispatch records whose node/session is no longer in the
33554
+ * live mesh. Returns the number of rows actually deleted. No-op for an empty taskId list.
33555
+ */
33556
+ deleteDirectDispatchesByTaskId(meshId, taskIds) {
33557
+ const ids = (taskIds || []).map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean);
33558
+ if (!ids.length) return 0;
33559
+ const stmt = this.db.prepare(`DELETE FROM mesh_direct_dispatches WHERE mesh_id = ? AND task_id = ?`);
33560
+ let deleted = 0;
33561
+ const run = this.db.transaction((rows) => {
33562
+ for (const taskId of rows) {
33563
+ deleted += stmt.run(meshId, taskId).changes;
33564
+ }
33565
+ });
33566
+ run(ids);
33567
+ return deleted;
33568
+ }
33438
33569
  markStaleDirectDispatches(meshId, olderThanMs) {
33439
33570
  const cutoff = new Date(Date.now() - olderThanMs).toISOString();
33440
33571
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -35121,11 +35252,14 @@ ${rendered}`, "utf-8");
35121
35252
  const trigger = normalizeOptionalString(args.trigger) || "manual";
35122
35253
  const updateSubmodules = args.updateSubmodules === true;
35123
35254
  const dryRun = args.dryRun === true || args.execute !== true;
35124
- const plannedSteps = buildPlannedSteps(updateSubmodules);
35255
+ const mode = args.mode === "push" ? "push" : "merge";
35256
+ const pushSubmodules = mode === "push" && args.pushSubmodules === true;
35257
+ const plannedSteps = buildPlannedSteps(mode, updateSubmodules, pushSubmodules);
35125
35258
  const base = {
35126
35259
  ...nodeId ? { nodeId } : {},
35127
35260
  ...meshId ? { meshId } : {},
35128
35261
  workspace,
35262
+ mode,
35129
35263
  dryRun,
35130
35264
  updateSubmodules,
35131
35265
  plannedSteps,
@@ -35139,13 +35273,24 @@ ${rendered}`, "utf-8");
35139
35273
  submoduleIgnorePaths: args.submoduleIgnorePaths,
35140
35274
  timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
35141
35275
  });
35276
+ if (mode === "push") {
35277
+ return pushMeshNode(base, args, current, {
35278
+ pushSubmodules,
35279
+ allowAutoPublishSubmoduleMainCommits: args.allowAutoPublishSubmoduleMainCommits === true
35280
+ });
35281
+ }
35142
35282
  const earlyBlockers = collectPreflightBlockers(current, requestedBranch);
35143
35283
  if (earlyBlockers.length > 0) {
35284
+ const blockCode = chooseBlockCode(current, earlyBlockers);
35144
35285
  const result2 = {
35145
- ...block(base, chooseBlockCode(current, earlyBlockers), earlyBlockers),
35286
+ ...block(base, blockCode, earlyBlockers),
35146
35287
  current,
35147
- finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(chooseBlockCode(current, earlyBlockers)))
35288
+ finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(blockCode))
35148
35289
  };
35290
+ if (blockCode === "branch_ahead" && current.ahead > 0 && current.behind === 0 && otherBlockersAreOnlyAhead(earlyBlockers)) {
35291
+ result2.code = "ahead_needs_push";
35292
+ 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.';
35293
+ }
35149
35294
  await appendFastForwardLedger(result2, "blocked");
35150
35295
  return result2;
35151
35296
  }
@@ -35256,7 +35401,246 @@ ${rendered}`, "utf-8");
35256
35401
  await appendFastForwardLedger(result, success2 ? "executed" : "failed");
35257
35402
  return result;
35258
35403
  }
35259
- function buildPlannedSteps(updateSubmodules) {
35404
+ async function pushMeshNode(base, args, current, options) {
35405
+ const workspace = base.workspace;
35406
+ const requestedBranch = normalizeOptionalString(args.branch);
35407
+ const dryRun = base.dryRun;
35408
+ const blockers = collectPushPreflightBlockers(current, requestedBranch);
35409
+ if (blockers.length > 0) {
35410
+ const code2 = choosePushBlockCode(current, blockers);
35411
+ const result2 = {
35412
+ ...block(base, code2, blockers),
35413
+ current,
35414
+ preStatus: current,
35415
+ finalBranchConvergenceState: buildConvergenceState(current, codeToConvergenceStatus(code2))
35416
+ };
35417
+ await appendFastForwardLedger(result2, "blocked");
35418
+ return result2;
35419
+ }
35420
+ const target = parseUpstreamTarget(current.upstream || "");
35421
+ if (!target) {
35422
+ const result2 = {
35423
+ ...block(base, "upstream_unparseable", ["upstream_unparseable"]),
35424
+ current,
35425
+ preStatus: current,
35426
+ finalBranchConvergenceState: buildConvergenceState(current, "blocked")
35427
+ };
35428
+ await appendFastForwardLedger(result2, "blocked");
35429
+ return result2;
35430
+ }
35431
+ const refspec = `HEAD:refs/heads/${target.remoteBranch}`;
35432
+ const pushTarget = { remote: target.remote, remoteBranch: target.remoteBranch, refspec };
35433
+ if (current.ahead <= 0) {
35434
+ const result2 = {
35435
+ ...base,
35436
+ success: true,
35437
+ code: "nothing_to_push",
35438
+ allowed: true,
35439
+ willRun: false,
35440
+ executed: false,
35441
+ blockingReasons: [],
35442
+ current,
35443
+ preStatus: current,
35444
+ postStatus: current,
35445
+ pushTarget,
35446
+ finalBranchConvergenceState: buildConvergenceState(current, "up_to_date")
35447
+ };
35448
+ await appendFastForwardLedger(result2, "noop");
35449
+ return result2;
35450
+ }
35451
+ const descendant = await verifyUpstreamIsAncestorOfHead(workspace, current.upstream || "", args.timeoutMs);
35452
+ if (!descendant.ok) {
35453
+ const result2 = {
35454
+ ...block(base, "non_fast_forward_push", ["head_is_not_descendant_of_upstream"]),
35455
+ current,
35456
+ preStatus: current,
35457
+ pushTarget,
35458
+ operationError: descendant.error,
35459
+ 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.",
35460
+ finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
35461
+ };
35462
+ await appendFastForwardLedger(result2, "blocked");
35463
+ return result2;
35464
+ }
35465
+ if (dryRun) {
35466
+ const result2 = {
35467
+ ...base,
35468
+ success: true,
35469
+ code: "push_available",
35470
+ allowed: true,
35471
+ willRun: false,
35472
+ executed: false,
35473
+ blockingReasons: [],
35474
+ current,
35475
+ preStatus: current,
35476
+ pushTarget,
35477
+ ...options.pushSubmodules ? { submodulePushes: await planSubmodulePushes(current, options, args.timeoutMs) } : {},
35478
+ finalBranchConvergenceState: buildConvergenceState(current, "push_available")
35479
+ };
35480
+ await appendFastForwardLedger(result2, "dry_run");
35481
+ return result2;
35482
+ }
35483
+ try {
35484
+ await runGit(workspace, ["push", target.remote, refspec], { timeoutMs: args.timeoutMs ?? 3e4 });
35485
+ } catch (error48) {
35486
+ const result2 = {
35487
+ ...block(base, "push_ff_only_failed", ["push_ff_only_failed"]),
35488
+ current,
35489
+ preStatus: current,
35490
+ pushTarget,
35491
+ operationError: formatGitError2(error48),
35492
+ finalBranchConvergenceState: buildConvergenceState(current, "not_mergeable")
35493
+ };
35494
+ await appendFastForwardLedger(result2, "failed");
35495
+ return result2;
35496
+ }
35497
+ let submodulePushes;
35498
+ if (options.pushSubmodules) {
35499
+ submodulePushes = await executeSubmodulePushes(current, options, args.timeoutMs);
35500
+ }
35501
+ const postStatus = await getGitRepoStatus(workspace, {
35502
+ ...STATUS_OPTIONS,
35503
+ submoduleIgnorePaths: args.submoduleIgnorePaths,
35504
+ timeoutMs: args.timeoutMs ?? STATUS_OPTIONS.timeoutMs
35505
+ });
35506
+ const submodulePushFailed = (submodulePushes || []).some((entry) => !entry.pushed && !entry.skipped);
35507
+ const blockingReasons = [];
35508
+ if (postStatus.ahead !== 0) blockingReasons.push("post_branch_ahead");
35509
+ if (submodulePushFailed) blockingReasons.push("submodule_push_failed");
35510
+ const success2 = blockingReasons.length === 0;
35511
+ const code = success2 ? "push_applied" : submodulePushFailed && postStatus.ahead === 0 ? "push_applied_submodule_push_failed" : "post_push_verify_failed";
35512
+ const result = {
35513
+ ...base,
35514
+ success: success2,
35515
+ code,
35516
+ allowed: true,
35517
+ willRun: true,
35518
+ executed: true,
35519
+ blockingReasons,
35520
+ current,
35521
+ preStatus: current,
35522
+ postStatus,
35523
+ pushTarget,
35524
+ ...submodulePushes ? { submodulePushes } : {},
35525
+ finalBranchConvergenceState: buildConvergenceState(postStatus, success2 ? "pushed" : "post_verify_failed")
35526
+ };
35527
+ await appendFastForwardLedger(result, success2 ? "executed" : "failed");
35528
+ return result;
35529
+ }
35530
+ function collectPushPreflightBlockers(status, requestedBranch) {
35531
+ const blockers = [];
35532
+ if (!status.isGitRepo) blockers.push("not_git_repo");
35533
+ if (!status.branch) blockers.push("detached_head_or_unknown_branch");
35534
+ if (requestedBranch && status.branch !== requestedBranch) blockers.push("branch_mismatch");
35535
+ if (!status.upstream) blockers.push("upstream_missing");
35536
+ if (status.upstreamStatus !== "fresh") blockers.push("upstream_not_fresh");
35537
+ if (status.hasConflicts) blockers.push("conflicts_present");
35538
+ if (status.staged > 0) blockers.push("staged_changes_present");
35539
+ if (status.modified > 0) blockers.push("modified_changes_present");
35540
+ if (status.untracked > 0) blockers.push("untracked_changes_present");
35541
+ if (status.deleted > 0) blockers.push("deleted_changes_present");
35542
+ if (status.renamed > 0) blockers.push("renamed_changes_present");
35543
+ if (status.stashCount > 0) blockers.push("stash_entries_present");
35544
+ if (status.ahead > 0 && status.behind > 0) blockers.push("branch_diverged_from_upstream");
35545
+ else if (status.behind > 0) blockers.push("branch_behind_upstream");
35546
+ return blockers;
35547
+ }
35548
+ function choosePushBlockCode(status, blockers) {
35549
+ if (blockers.includes("not_git_repo")) return "not_git_repo";
35550
+ if (blockers.includes("branch_mismatch")) return "branch_mismatch";
35551
+ if (blockers.includes("upstream_missing")) return "upstream_missing";
35552
+ if (blockers.includes("upstream_not_fresh")) return "upstream_not_fresh";
35553
+ if (blockers.includes("branch_diverged_from_upstream")) return "branch_diverged";
35554
+ if (blockers.includes("branch_behind_upstream")) return "non_fast_forward_push";
35555
+ if (blockers.some((reason) => reason.includes("changes") || reason.includes("conflicts") || reason.includes("stash"))) return "dirty_worktree";
35556
+ return "preflight_blocked";
35557
+ }
35558
+ function parseUpstreamTarget(upstream) {
35559
+ const trimmed = upstream.trim();
35560
+ const slash = trimmed.indexOf("/");
35561
+ if (slash <= 0 || slash >= trimmed.length - 1) return null;
35562
+ return { remote: trimmed.slice(0, slash), remoteBranch: trimmed.slice(slash + 1) };
35563
+ }
35564
+ async function verifyUpstreamIsAncestorOfHead(workspace, upstream, timeoutMs) {
35565
+ if (!upstream) return { ok: false, error: "missing upstream" };
35566
+ try {
35567
+ await runGit(workspace, ["merge-base", "--is-ancestor", upstream, "HEAD"], { timeoutMs: timeoutMs ?? 15e3 });
35568
+ return { ok: true };
35569
+ } catch (error48) {
35570
+ return { ok: false, error: formatGitError2(error48) };
35571
+ }
35572
+ }
35573
+ async function planSubmodulePushes(status, options, timeoutMs) {
35574
+ return resolveSubmodulePushes(status, options, false, timeoutMs);
35575
+ }
35576
+ async function executeSubmodulePushes(status, options, timeoutMs) {
35577
+ return resolveSubmodulePushes(status, options, true, timeoutMs);
35578
+ }
35579
+ async function resolveSubmodulePushes(status, options, execute, timeoutMs) {
35580
+ const submodules = Array.isArray(status.submodules) ? status.submodules : [];
35581
+ const results = [];
35582
+ for (const submodule of submodules) {
35583
+ const base = {
35584
+ path: submodule.path,
35585
+ commit: submodule.commit,
35586
+ remote: "origin",
35587
+ remoteBranch: "main",
35588
+ pushed: false,
35589
+ skipped: true,
35590
+ code: "submodule_push_skipped"
35591
+ };
35592
+ if (!options.allowAutoPublishSubmoduleMainCommits) {
35593
+ results.push({ ...base, code: "submodule_push_policy_disabled", error: "allowAutoPublishSubmoduleMainCommits is not enabled" });
35594
+ continue;
35595
+ }
35596
+ if (submodule.error || submodule.dirty) {
35597
+ results.push({ ...base, code: "submodule_not_clean", error: submodule.error || "submodule worktree is dirty" });
35598
+ continue;
35599
+ }
35600
+ const repoPath = submodule.repoPath;
35601
+ if (!repoPath || !submodule.commit) {
35602
+ results.push({ ...base, code: "submodule_status_incomplete" });
35603
+ continue;
35604
+ }
35605
+ try {
35606
+ await runGit(repoPath, ["-c", "protocol.file.allow=always", "fetch", "origin", "refs/heads/main:refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 3e4 });
35607
+ } catch (error48) {
35608
+ results.push({ ...base, code: "submodule_fetch_failed", error: formatGitError2(error48) });
35609
+ continue;
35610
+ }
35611
+ let alreadyReachable = false;
35612
+ try {
35613
+ await runGit(repoPath, ["merge-base", "--is-ancestor", submodule.commit, "refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 15e3 });
35614
+ alreadyReachable = true;
35615
+ } catch {
35616
+ }
35617
+ if (alreadyReachable) {
35618
+ results.push({ ...base, pushed: false, skipped: true, code: "submodule_already_reachable" });
35619
+ continue;
35620
+ }
35621
+ try {
35622
+ await runGit(repoPath, ["merge-base", "--is-ancestor", "refs/remotes/origin/main", submodule.commit], { timeoutMs: timeoutMs ?? 15e3 });
35623
+ } catch (error48) {
35624
+ results.push({ ...base, pushed: false, skipped: false, code: "submodule_non_fast_forward", error: formatGitError2(error48) });
35625
+ continue;
35626
+ }
35627
+ const refspec = `${submodule.commit}:refs/heads/main`;
35628
+ if (!execute) {
35629
+ results.push({ ...base, pushed: false, skipped: false, code: "submodule_push_available", refspec });
35630
+ continue;
35631
+ }
35632
+ try {
35633
+ await runGit(repoPath, ["push", "origin", refspec], { timeoutMs: timeoutMs ?? 3e4 });
35634
+ await runGit(repoPath, ["-c", "protocol.file.allow=always", "fetch", "origin", "refs/heads/main:refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 3e4 });
35635
+ await runGit(repoPath, ["merge-base", "--is-ancestor", submodule.commit, "refs/remotes/origin/main"], { timeoutMs: timeoutMs ?? 15e3 });
35636
+ results.push({ ...base, pushed: true, skipped: false, code: "submodule_pushed", refspec });
35637
+ } catch (error48) {
35638
+ results.push({ ...base, pushed: false, skipped: false, code: "submodule_push_failed", refspec, error: formatGitError2(error48) });
35639
+ }
35640
+ }
35641
+ return results;
35642
+ }
35643
+ function buildPlannedSteps(mode, updateSubmodules, pushSubmodules) {
35260
35644
  const steps = [
35261
35645
  {
35262
35646
  operation: "refresh_upstream",
@@ -35269,20 +35653,49 @@ ${rendered}`, "utf-8");
35269
35653
  description: "Require clean staged/modified/untracked/deleted/renamed/conflict/stash/submodule state.",
35270
35654
  safe: true,
35271
35655
  willMutateWorktree: false
35272
- },
35273
- {
35274
- operation: "verify_fast_forward",
35275
- description: "Require ahead=0, behind>0, and HEAD to be an ancestor of the upstream ref.",
35656
+ }
35657
+ ];
35658
+ if (mode === "push") {
35659
+ steps.push({
35660
+ operation: "verify_push_descendant",
35661
+ description: "Require HEAD to be a descendant of origin/<branch> (origin/<branch> is an ancestor of HEAD); refuse any non-fast-forward push.",
35276
35662
  safe: true,
35277
35663
  willMutateWorktree: false
35278
- },
35279
- {
35280
- operation: "merge_ff_only",
35281
- description: "Apply git merge --ff-only against the tracked upstream; no force, reset, rebase, push, or deploy.",
35664
+ });
35665
+ steps.push({
35666
+ operation: "push_ff_only",
35667
+ 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.",
35282
35668
  safe: true,
35283
- willMutateWorktree: true
35669
+ willMutateWorktree: false
35670
+ });
35671
+ if (pushSubmodules) {
35672
+ steps.push({
35673
+ operation: "push_submodules_ff_only",
35674
+ 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.",
35675
+ safe: true,
35676
+ willMutateWorktree: false
35677
+ });
35284
35678
  }
35285
- ];
35679
+ steps.push({
35680
+ operation: "verify_post_status",
35681
+ description: "Re-read daemon-owned git status and report final branch convergence state.",
35682
+ safe: true,
35683
+ willMutateWorktree: false
35684
+ });
35685
+ return steps;
35686
+ }
35687
+ steps.push({
35688
+ operation: "verify_fast_forward",
35689
+ description: "Require ahead=0, behind>0, and HEAD to be an ancestor of the upstream ref.",
35690
+ safe: true,
35691
+ willMutateWorktree: false
35692
+ });
35693
+ steps.push({
35694
+ operation: "merge_ff_only",
35695
+ description: "Apply git merge --ff-only against the tracked upstream; no force, reset, rebase, push, or deploy.",
35696
+ safe: true,
35697
+ willMutateWorktree: true
35698
+ });
35286
35699
  if (updateSubmodules) {
35287
35700
  steps.push({
35288
35701
  operation: "submodule_update",
@@ -35299,6 +35712,10 @@ ${rendered}`, "utf-8");
35299
35712
  });
35300
35713
  return steps;
35301
35714
  }
35715
+ function otherBlockersAreOnlyAhead(blockers) {
35716
+ const aheadOnly = /* @__PURE__ */ new Set(["branch_has_local_commits"]);
35717
+ return blockers.every((reason) => aheadOnly.has(reason));
35718
+ }
35302
35719
  function collectPreflightBlockers(status, requestedBranch) {
35303
35720
  const blockers = [];
35304
35721
  if (!status.isGitRepo) blockers.push("not_git_repo");
@@ -35355,7 +35772,7 @@ ${rendered}`, "utf-8");
35355
35772
  return "preflight_blocked";
35356
35773
  }
35357
35774
  function codeToConvergenceStatus(code) {
35358
- if (code === "branch_diverged" || code === "branch_ahead" || code === "non_fast_forward") return "not_mergeable";
35775
+ if (code === "branch_diverged" || code === "branch_ahead" || code === "non_fast_forward" || code === "non_fast_forward_push" || code === "upstream_unparseable") return "not_mergeable";
35359
35776
  if (code === "dirty_worktree" || code === "submodule_not_clean") return "blocked_review";
35360
35777
  return "blocked";
35361
35778
  }
@@ -35438,6 +35855,7 @@ ${rendered}`, "utf-8");
35438
35855
  ...result.nodeId ? { nodeId: result.nodeId } : {},
35439
35856
  payload: {
35440
35857
  operation: "mesh_fast_forward_node",
35858
+ mode: result.mode,
35441
35859
  trigger: result.trigger || "manual",
35442
35860
  outcome,
35443
35861
  code: result.code,
@@ -35448,6 +35866,7 @@ ${rendered}`, "utf-8");
35448
35866
  executed: result.executed,
35449
35867
  branch: result.postStatus?.branch ?? result.current?.branch,
35450
35868
  upstream: result.postStatus?.upstream ?? result.current?.upstream,
35869
+ ...result.pushTarget ? { pushTarget: result.pushTarget } : {},
35451
35870
  before: result.current ? {
35452
35871
  headCommit: result.current.headCommit,
35453
35872
  ahead: result.current.ahead,
@@ -35458,6 +35877,16 @@ ${rendered}`, "utf-8");
35458
35877
  ahead: result.postStatus.ahead,
35459
35878
  behind: result.postStatus.behind
35460
35879
  } : void 0,
35880
+ ...result.submodulePushes ? {
35881
+ submodulePushes: result.submodulePushes.map((entry) => ({
35882
+ path: entry.path,
35883
+ commit: entry.commit,
35884
+ pushed: entry.pushed,
35885
+ skipped: entry.skipped,
35886
+ code: entry.code,
35887
+ ...entry.refspec ? { refspec: entry.refspec } : {}
35888
+ }))
35889
+ } : {},
35461
35890
  blockingReasons: result.blockingReasons
35462
35891
  }
35463
35892
  });
@@ -36628,8 +37057,8 @@ Next step: ${nextStep}`;
36628
37057
  });
36629
37058
  function getCachedMeshByWorkspace(workspace) {
36630
37059
  const now = Date.now();
36631
- const cached2 = meshByWorkspaceCache.get(workspace);
36632
- if (cached2 && now - cached2.cachedAt < MESH_WORKSPACE_CACHE_TTL_MS) return cached2.mesh;
37060
+ const cached22 = meshByWorkspaceCache.get(workspace);
37061
+ if (cached22 && now - cached22.cachedAt < MESH_WORKSPACE_CACHE_TTL_MS) return cached22.mesh;
36633
37062
  const mesh = getMeshByRepo(workspace);
36634
37063
  meshByWorkspaceCache.set(workspace, { mesh, cachedAt: now });
36635
37064
  return mesh;
@@ -41528,10 +41957,10 @@ ${lastSnapshot}`;
41528
41957
  return this.accumulatedRawBuffer.replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
41529
41958
  }
41530
41959
  getFreshParsedStatusCache() {
41531
- const cached2 = this.parsedStatusCache;
41960
+ const cached22 = this.parsedStatusCache;
41532
41961
  const accumulatedRawBufferKey = this.getAccumulatedRawBufferCacheKey();
41533
- 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) {
41534
- return cached2.result;
41962
+ if (cached22 && cached22.responseBuffer === this.responseBuffer && cached22.currentTurnScope === this.engine.currentTurnScope && cached22.recentOutputBuffer === this.recentOutputBuffer && cached22.accumulatedBuffer === this.accumulatedBuffer && cached22.accumulatedRawBufferKey === accumulatedRawBufferKey && cached22.screenText === this.lastScreenText && cached22.currentStatus === this.engine.currentStatus && cached22.activeModal === this.engine.activeModal && cached22.cliName === this.cliName) {
41963
+ return cached22.result;
41535
41964
  }
41536
41965
  return null;
41537
41966
  }
@@ -41991,10 +42420,10 @@ ${lastSnapshot}`;
41991
42420
  getScriptParsedStatus() {
41992
42421
  const screenText = this.readTerminalScreenText();
41993
42422
  const parseScreenText = this.getParseScreenText(screenText);
41994
- const cached2 = this.parsedStatusCache;
42423
+ const cached22 = this.parsedStatusCache;
41995
42424
  const accumulatedRawBufferKey = this.getAccumulatedRawBufferCacheKey();
41996
- 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) {
41997
- return cached2.result;
42425
+ if (!this.providerOwnsTranscript() && cached22 && cached22.responseBuffer === this.responseBuffer && cached22.currentTurnScope === this.engine.currentTurnScope && cached22.recentOutputBuffer === this.recentOutputBuffer && cached22.accumulatedBuffer === this.accumulatedBuffer && cached22.accumulatedRawBufferKey === accumulatedRawBufferKey && cached22.screenText === parseScreenText && cached22.currentStatus === this.engine.currentStatus && cached22.activeModal === this.engine.activeModal && cached22.cliName === this.cliName) {
42426
+ return cached22.result;
41998
42427
  }
41999
42428
  const parsed = this.runParseSession();
42000
42429
  if (!parsed || !Array.isArray(parsed.messages)) {
@@ -43865,6 +44294,7 @@ ${lastSnapshot}`;
43865
44294
  MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS2,
43866
44295
  NodePtyTransportFactory: () => NodePtyTransportFactory,
43867
44296
  P2pRelayFailureError: () => P2pRelayFailureError,
44297
+ PRUNABLE_ORPHAN_STALE_REASONS: () => PRUNABLE_ORPHAN_STALE_REASONS,
43868
44298
  ProviderCliAdapter: () => ProviderCliAdapter,
43869
44299
  ProviderInstanceManager: () => ProviderInstanceManager,
43870
44300
  ProviderLoader: () => ProviderLoader,
@@ -43918,6 +44348,7 @@ ${lastSnapshot}`;
43918
44348
  classifyChatMessageVisibility: () => classifyChatMessageVisibility,
43919
44349
  classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush2,
43920
44350
  classifyP2pRelayFailure: () => classifyP2pRelayFailure,
44351
+ classifyStaleDirectForPrune: () => classifyStaleDirectForPrune,
43921
44352
  cleanupTerminalDirectDispatches: () => cleanupTerminalDirectDispatches,
43922
44353
  clearDebugTrace: () => clearDebugTrace,
43923
44354
  clearPendingMeshCoordinatorEvents: () => clearPendingMeshCoordinatorEvents,
@@ -43937,6 +44368,7 @@ ${lastSnapshot}`;
43937
44368
  createNativeHistoryDispatcher: () => createNativeHistoryDispatcher,
43938
44369
  createSessionDelivery: () => createSessionDelivery,
43939
44370
  createWorktree: () => createWorktree,
44371
+ deleteDirectDispatchesByTaskId: () => deleteDirectDispatchesByTaskId,
43940
44372
  deleteMesh: () => deleteMesh,
43941
44373
  deriveMeshReviewInboxItems: () => deriveMeshReviewInboxItems,
43942
44374
  describeTaskDependencyState: () => describeTaskDependencyState,
@@ -43965,6 +44397,7 @@ ${lastSnapshot}`;
43965
44397
  getAvailableIdeIds: () => getAvailableIdeIds,
43966
44398
  getCoordinatorForSession: () => getCoordinatorForSession,
43967
44399
  getCurrentDaemonLogPath: () => getCurrentDaemonLogPath,
44400
+ getDaemonBuildInfo: () => getDaemonBuildInfo,
43968
44401
  getDaemonDataDir: () => getDaemonDataDir,
43969
44402
  getDaemonLogDir: () => getDaemonLogDir,
43970
44403
  getDebugRuntimeConfig: () => getDebugRuntimeConfig,
@@ -46761,6 +47194,17 @@ ${lastSnapshot}`;
46761
47194
  }
46762
47195
  return { activeWork: records, staleDirectWork, staleDirectWorkNote, terminalDirectWork, summary };
46763
47196
  }
47197
+ var PRUNABLE_ORPHAN_STALE_REASONS = /* @__PURE__ */ new Set([
47198
+ "direct task node is no longer in the live mesh",
47199
+ "direct task session is not present in live session records",
47200
+ "direct task has no node id"
47201
+ ]);
47202
+ function classifyStaleDirectForPrune(record2, opts = {}) {
47203
+ if (record2.staleDispatchUnacknowledged === true) return "preserve_unacknowledged";
47204
+ if (record2.terminal === true) return opts.includeTerminal ? "prunable_terminal" : "preserve_active";
47205
+ if (record2.staleReason && PRUNABLE_ORPHAN_STALE_REASONS.has(record2.staleReason)) return "prunable_orphan";
47206
+ return "preserve_active";
47207
+ }
46764
47208
  function buildCompactStaleDirectWorkSummary(staleDirectWork, opts = {}) {
46765
47209
  const sampleLimit = Math.max(0, Math.min(10, Math.floor(opts.sampleLimit ?? 3)));
46766
47210
  const reasonCounts = {};
@@ -49950,9 +50394,9 @@ ${cleanBody}`;
49950
50394
  for (const file2 of files.slice().sort()) {
49951
50395
  const filePath = path12.join(dir, file2);
49952
50396
  const signature = fileSignatures.get(file2) || `${file2}:missing`;
49953
- const cached2 = savedHistoryFileSummaryCache.get(filePath);
50397
+ const cached22 = savedHistoryFileSummaryCache.get(filePath);
49954
50398
  const persisted = persistedEntries.get(file2);
49955
- const reusableEntry = cached2?.signature === signature ? cached2 : persisted?.signature === signature ? persisted : null;
50399
+ const reusableEntry = cached22?.signature === signature ? cached22 : persisted?.signature === signature ? persisted : null;
49956
50400
  const fileSummary = reusableEntry?.summary || computeSavedHistoryFileSummary(dir, file2);
49957
50401
  const nextEntry = reusableEntry || {
49958
50402
  signature,
@@ -50404,23 +50848,23 @@ ${cleanBody}`;
50404
50848
  savedHistorySessionCache.delete(sanitized);
50405
50849
  return { sessions: [], hasMore: false };
50406
50850
  }
50407
- const cached2 = savedHistorySessionCache.get(sanitized);
50851
+ const cached22 = savedHistorySessionCache.get(sanitized);
50408
50852
  const offset = Math.max(0, options.offset || 0);
50409
50853
  const limit = Math.max(1, options.limit || 30);
50410
50854
  const indexSignature = buildSavedHistoryIndexFileSignature(dir);
50411
50855
  let cacheWasInvalidated = false;
50412
- if (cached2) {
50413
- const cacheLooksPersisted = cached2.signature.startsWith("index:");
50414
- const cacheStillValid = cacheLooksPersisted ? cached2.signature === indexSignature : (() => {
50856
+ if (cached22) {
50857
+ const cacheLooksPersisted = cached22.signature.startsWith("index:");
50858
+ const cacheStillValid = cacheLooksPersisted ? cached22.signature === indexSignature : (() => {
50415
50859
  const files2 = listHistoryFiles(dir);
50416
50860
  const fileSignatures2 = buildSavedHistoryFileSignatureMap(dir, files2);
50417
- return cached2.signature === buildSavedHistoryCacheSignature(files2, fileSignatures2);
50861
+ return cached22.signature === buildSavedHistoryCacheSignature(files2, fileSignatures2);
50418
50862
  })();
50419
50863
  if (cacheStillValid) {
50420
- const sliced2 = cached2.summaries.slice(offset, offset + limit);
50864
+ const sliced2 = cached22.summaries.slice(offset, offset + limit);
50421
50865
  return {
50422
50866
  sessions: sliced2,
50423
- hasMore: cached2.summaries.length > offset + limit
50867
+ hasMore: cached22.summaries.length > offset + limit
50424
50868
  };
50425
50869
  }
50426
50870
  cacheWasInvalidated = true;
@@ -66889,8 +67333,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
66889
67333
  return null;
66890
67334
  }
66891
67335
  registerProviderScriptRootSafely(path30.dirname(path30.dirname(providerDir)));
66892
- const cached2 = this.scriptsCache.get(dir);
66893
- if (cached2) return cached2;
67336
+ const cached22 = this.scriptsCache.get(dir);
67337
+ if (cached22) return cached22;
66894
67338
  const scriptsJs = path30.join(dir, "scripts.js");
66895
67339
  if (fs20.existsSync(scriptsJs)) {
66896
67340
  try {
@@ -68869,6 +69313,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
68869
69313
  }
68870
69314
  };
68871
69315
  }
69316
+ init_build_info();
68872
69317
  var import_child_process7 = require("child_process");
68873
69318
  var import_child_process8 = require("child_process");
68874
69319
  var fs222 = __toESM2(require("fs"));
@@ -69651,13 +70096,13 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
69651
70096
  nodes
69652
70097
  };
69653
70098
  }
69654
- function reconcileInlineMeshCache(cached2, incoming) {
69655
- if (!cached2 || typeof cached2 !== "object" || Array.isArray(cached2)) return incoming;
69656
- if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return cached2;
69657
- const cachedNodes = Array.isArray(cached2.nodes) ? cached2.nodes : [];
70099
+ function reconcileInlineMeshCache(cached22, incoming) {
70100
+ if (!cached22 || typeof cached22 !== "object" || Array.isArray(cached22)) return incoming;
70101
+ if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return cached22;
70102
+ const cachedNodes = Array.isArray(cached22.nodes) ? cached22.nodes : [];
69658
70103
  const incomingNodes = Array.isArray(incoming.nodes) ? incoming.nodes : [];
69659
- if (!cachedNodes.length || !incomingNodes.length) return { ...cached2, ...incoming };
69660
- const cachedUpdatedAt = Date.parse(readStringValue(cached2.updatedAt, cached2.updated_at) || "");
70104
+ if (!cachedNodes.length || !incomingNodes.length) return { ...cached22, ...incoming };
70105
+ const cachedUpdatedAt = Date.parse(readStringValue(cached22.updatedAt, cached22.updated_at) || "");
69661
70106
  const incomingUpdatedAt = Date.parse(readStringValue(incoming.updatedAt, incoming.updated_at) || "");
69662
70107
  const preserveCachedMembership = Number.isFinite(cachedUpdatedAt) && (!Number.isFinite(incomingUpdatedAt) || cachedUpdatedAt > incomingUpdatedAt);
69663
70108
  const cachedById = /* @__PURE__ */ new Map();
@@ -69686,7 +70131,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
69686
70131
  }
69687
70132
  }
69688
70133
  return {
69689
- ...cached2,
70134
+ ...cached22,
69690
70135
  ...incoming,
69691
70136
  nodes
69692
70137
  };
@@ -71370,13 +71815,13 @@ ${e?.stderr || ""}`
71370
71815
  };
71371
71816
  }
71372
71817
  getCachedAggregateMeshStatus(meshId, mesh, options) {
71373
- const cached2 = this.aggregateMeshStatusCache.get(meshId);
71374
- if (!cached2?.snapshot || cached2.snapshot.success !== true || !Array.isArray(cached2.snapshot.nodes)) return null;
71375
- if (cached2.queueRevision !== getMeshQueueRevision(meshId)) return null;
71376
- let snapshot = this.cloneJsonValue(cached2.snapshot);
71818
+ const cached22 = this.aggregateMeshStatusCache.get(meshId);
71819
+ if (!cached22?.snapshot || cached22.snapshot.success !== true || !Array.isArray(cached22.snapshot.nodes)) return null;
71820
+ if (cached22.queueRevision !== getMeshQueueRevision(meshId)) return null;
71821
+ let snapshot = this.cloneJsonValue(cached22.snapshot);
71377
71822
  snapshot = this.hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options);
71378
71823
  if (shouldRefreshStalePendingAggregate(snapshot, options)) return null;
71379
- const ageMs = Math.max(0, Date.now() - cached2.builtAt);
71824
+ const ageMs = Math.max(0, Date.now() - cached22.builtAt);
71380
71825
  const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === "object" ? snapshot.sourceOfTruth : {};
71381
71826
  snapshot.sourceOfTruth = {
71382
71827
  ...sourceOfTruth,
@@ -71387,7 +71832,7 @@ ${e?.stderr || ""}`
71387
71832
  source: "memory",
71388
71833
  refreshReason: "memory_cache_hit",
71389
71834
  ageMs,
71390
- cachedAt: new Date(cached2.builtAt).toISOString(),
71835
+ cachedAt: new Date(cached22.builtAt).toISOString(),
71391
71836
  returnedAt: (/* @__PURE__ */ new Date()).toISOString()
71392
71837
  }
71393
71838
  };
@@ -71431,9 +71876,9 @@ ${e?.stderr || ""}`
71431
71876
  warmInlineMeshCache(meshId, inlineMesh) {
71432
71877
  if (!inlineMesh || typeof inlineMesh !== "object") return void 0;
71433
71878
  const sanitizedInlineMesh = sanitizeInlineMesh(inlineMesh);
71434
- const cached2 = this.inlineMeshCache.get(meshId);
71435
- if (cached2) {
71436
- const merged = reconcileInlineMeshCache(cached2, sanitizedInlineMesh);
71879
+ const cached22 = this.inlineMeshCache.get(meshId);
71880
+ if (cached22) {
71881
+ const merged = reconcileInlineMeshCache(cached22, sanitizedInlineMesh);
71437
71882
  this.inlineMeshCache.set(meshId, merged);
71438
71883
  return merged;
71439
71884
  }
@@ -71443,14 +71888,14 @@ ${e?.stderr || ""}`
71443
71888
  async getMeshForCommand(meshId, inlineMesh, options) {
71444
71889
  const preferInline = options?.preferInline === true;
71445
71890
  if (preferInline) {
71446
- const cached22 = this.getCachedInlineMesh(meshId);
71447
- if (cached22) {
71891
+ const cached3 = this.getCachedInlineMesh(meshId);
71892
+ if (cached3) {
71448
71893
  if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
71449
- const merged = reconcileInlineMeshCache(cached22, inlineMesh);
71894
+ const merged = reconcileInlineMeshCache(cached3, inlineMesh);
71450
71895
  this.inlineMeshCache.set(meshId, sanitizeInlineMesh(merged));
71451
71896
  return { mesh: merged, inline: true, source: "inline_cache" };
71452
71897
  }
71453
- return { mesh: cached22, inline: true, source: "inline_cache" };
71898
+ return { mesh: cached3, inline: true, source: "inline_cache" };
71454
71899
  }
71455
71900
  if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
71456
71901
  this.warmInlineMeshCache(meshId, inlineMesh);
@@ -71463,8 +71908,8 @@ ${e?.stderr || ""}`
71463
71908
  if (mesh) return { mesh, inline: false, source: "local_config" };
71464
71909
  } catch {
71465
71910
  }
71466
- const cached2 = this.getCachedInlineMesh(meshId);
71467
- if (cached2) return { mesh: cached2, inline: true, source: "inline_cache" };
71911
+ const cached22 = this.getCachedInlineMesh(meshId);
71912
+ if (cached22) return { mesh: cached22, inline: true, source: "inline_cache" };
71468
71913
  const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
71469
71914
  return warmedInline ? { mesh: warmedInline, inline: true, source: "inline_bootstrap" } : null;
71470
71915
  }
@@ -71771,6 +72216,8 @@ ${e?.stderr || ""}`
71771
72216
  const skippedSessionIds = [];
71772
72217
  const skippedLiveSessionIds = [];
71773
72218
  const skippedCoordinatorSessionIds = [];
72219
+ const skippedLiveSessionReasons = [];
72220
+ const actedLiveDelegateSessionIds = [];
71774
72221
  const deleteUnsupportedSessionIds = [];
71775
72222
  const recordsRemainSessionIds = [];
71776
72223
  const errors = [];
@@ -71804,16 +72251,31 @@ ${e?.stderr || ""}`
71804
72251
  const surfaceKind = getSessionHostSurfaceKind(record2);
71805
72252
  const liveRuntime = surfaceKind === "live_runtime";
71806
72253
  const coordinatorSession = readStringValue(record2?.meta?.meshCoordinatorFor) === args.meshId;
72254
+ const recordNodeId = readStringValue(record2?.meta?.meshNodeId);
72255
+ const recordMeshNodeFor = readStringValue(record2?.meta?.meshNodeFor);
72256
+ const delegateBoundToThisNode = !!recordNodeId && recordNodeId === args.nodeId && (!recordMeshNodeFor || recordMeshNodeFor === args.meshId);
71807
72257
  if (!hasExplicitSessionIds && coordinatorSession) {
71808
72258
  skippedSessionIds.push(sessionId);
71809
72259
  skippedCoordinatorSessionIds.push(sessionId);
71810
72260
  continue;
71811
72261
  }
71812
- if (!hasExplicitSessionIds && liveRuntime) {
72262
+ if (!hasExplicitSessionIds && liveRuntime && !delegateBoundToThisNode) {
71813
72263
  skippedSessionIds.push(sessionId);
71814
72264
  skippedLiveSessionIds.push(sessionId);
72265
+ const matchedByWorkspaceOnly = !recordNodeId;
72266
+ 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";
72267
+ skippedLiveSessionReasons.push({ sessionId, reason });
71815
72268
  continue;
71816
72269
  }
72270
+ if (!hasExplicitSessionIds && liveRuntime && delegateBoundToThisNode && args.mode === "delete_stopped") {
72271
+ skippedSessionIds.push(sessionId);
72272
+ skippedLiveSessionIds.push(sessionId);
72273
+ skippedLiveSessionReasons.push({ sessionId, reason: "live_delegate_preserved_by_delete_stopped_mode_use_stop_or_stop_and_delete" });
72274
+ continue;
72275
+ }
72276
+ if (!hasExplicitSessionIds && liveRuntime && delegateBoundToThisNode) {
72277
+ actedLiveDelegateSessionIds.push(sessionId);
72278
+ }
71817
72279
  try {
71818
72280
  if (args.mode === "stop") {
71819
72281
  if (!completed) {
@@ -71875,6 +72337,8 @@ ${e?.stderr || ""}`
71875
72337
  skippedSessionIds,
71876
72338
  skippedLiveSessionIds,
71877
72339
  skippedCoordinatorSessionIds,
72340
+ ...actedLiveDelegateSessionIds.length ? { actedLiveDelegateSessionIds } : {},
72341
+ ...skippedLiveSessionReasons.length ? { skippedLiveSessionReasons } : {},
71878
72342
  ...deleteUnsupported ? {
71879
72343
  deleteUnsupported: true,
71880
72344
  effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
@@ -72641,10 +73105,31 @@ ${hintLines.join("\n")}` : "",
72641
73105
  };
72642
73106
  }
72643
73107
  const cleanupStarted = Date.now();
73108
+ const refineSessionCleanupMode = this.normalizeMeshSessionCleanupMode(
73109
+ mesh?.policy?.sessionCleanupOnNodeRemove
73110
+ );
73111
+ let refineSessionIds;
73112
+ if (refineSessionCleanupMode !== "preserve" && this.deps.sessionHostControl) {
73113
+ try {
73114
+ const liveSessions = await this.deps.sessionHostControl.listSessions();
73115
+ const workspace = typeof node.workspace === "string" ? node.workspace : "";
73116
+ refineSessionIds = liveSessions.filter((record2) => {
73117
+ const sid = typeof record2?.sessionId === "string" ? record2.sessionId : "";
73118
+ if (!sid) return false;
73119
+ if (readStringValue(record2?.meta?.meshCoordinatorFor) === meshId) return false;
73120
+ const boundToNode = readStringValue(record2?.meta?.meshNodeId) === nodeId;
73121
+ const matchedByWorkspace = !!workspace && record2?.workspace === workspace;
73122
+ return boundToNode || matchedByWorkspace;
73123
+ }).map((record2) => String(record2.sessionId));
73124
+ } catch {
73125
+ refineSessionIds = void 0;
73126
+ }
73127
+ }
72644
73128
  const removeResult = await this.execute("remove_mesh_node", {
72645
73129
  meshId,
72646
73130
  nodeId,
72647
- sessionCleanupMode: "preserve",
73131
+ sessionCleanupMode: refineSessionCleanupMode,
73132
+ ...refineSessionIds && refineSessionIds.length > 0 ? { sessionIds: refineSessionIds } : {},
72648
73133
  inlineMesh: args?.inlineMesh
72649
73134
  });
72650
73135
  recordMeshRefineStage(refineStages, "cleanup", removeResult?.success === false ? "failed" : "passed", cleanupStarted, {
@@ -72802,8 +73287,8 @@ ${hintLines.join("\n")}` : "",
72802
73287
  const repoRootBaseRef = /* @__PURE__ */ new Map();
72803
73288
  const submodulePathsByRepoRoot = /* @__PURE__ */ new Map();
72804
73289
  const resolveBaseRef = async (repoRoot) => {
72805
- const cached2 = repoRootBaseRef.get(repoRoot);
72806
- if (cached2) return cached2;
73290
+ const cached22 = repoRootBaseRef.get(repoRoot);
73291
+ if (cached22) return cached22;
72807
73292
  let baseBranch = "main";
72808
73293
  try {
72809
73294
  const { stdout } = await execFileAsync4("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
@@ -73701,7 +74186,7 @@ ${hintLines.join("\n")}` : "",
73701
74186
  version: this.deps.statusVersion || "unknown",
73702
74187
  profile: "metadata"
73703
74188
  });
73704
- return { success: true, status: snapshot };
74189
+ return { success: true, status: snapshot, daemonBuild: getDaemonBuildInfo() };
73705
74190
  }
73706
74191
  case "get_machine_runtime_stats": {
73707
74192
  return {
@@ -74671,6 +75156,7 @@ ${hintLines.join("\n")}` : "",
74671
75156
  let workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
74672
75157
  let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
74673
75158
  let nodeDaemonId;
75159
+ let allowAutoPublishSubmoduleMainCommits = false;
74674
75160
  if (meshId && nodeId) {
74675
75161
  const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
74676
75162
  const mesh = meshRecord?.mesh;
@@ -74681,6 +75167,7 @@ ${hintLines.join("\n")}` : "",
74681
75167
  if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
74682
75168
  submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
74683
75169
  }
75170
+ allowAutoPublishSubmoduleMainCommits = mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true;
74684
75171
  nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
74685
75172
  }
74686
75173
  const selfDaemonId = this.deps.statusInstanceId;
@@ -74701,7 +75188,10 @@ ${hintLines.join("\n")}` : "",
74701
75188
  execute: args?.execute === true,
74702
75189
  dryRun: args?.dryRun === true,
74703
75190
  updateSubmodules: args?.updateSubmodules === true,
74704
- submoduleIgnorePaths
75191
+ submoduleIgnorePaths,
75192
+ mode: args?.mode === "push" ? "push" : "merge",
75193
+ pushSubmodules: args?.pushSubmodules === true,
75194
+ allowAutoPublishSubmoduleMainCommits
74705
75195
  });
74706
75196
  return result;
74707
75197
  }
@@ -74709,6 +75199,23 @@ ${hintLines.join("\n")}` : "",
74709
75199
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
74710
75200
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
74711
75201
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
75202
+ const isDryRun = args?.dryRun !== false && args?.execute !== true;
75203
+ if (isDryRun) {
75204
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
75205
+ const mesh = meshRecord?.mesh;
75206
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
75207
+ if (!node?.workspace) return { success: false, error: `Node '${nodeId}' workspace not found` };
75208
+ return {
75209
+ success: true,
75210
+ dryRun: true,
75211
+ nodeId,
75212
+ workspace: node.workspace,
75213
+ validationPlan: buildMeshRefineValidationPlan(mesh, node.workspace),
75214
+ mergeWillRun: false,
75215
+ cleanupWillRun: false,
75216
+ hint: "Dry-run only \u2014 no merge/push/cleanup performed. Re-invoke with execute:true to converge this node."
75217
+ };
75218
+ }
74712
75219
  return this.startMeshRefineJob(meshId, nodeId, args);
74713
75220
  }
74714
75221
  case "batch_refine_mesh_nodes": {
@@ -74730,9 +75237,17 @@ ${hintLines.join("\n")}` : "",
74730
75237
  const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
74731
75238
  args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
74732
75239
  );
75240
+ const explicitSessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim()) : void 0;
74733
75241
  let sessionCleanup;
74734
75242
  if (node && sessionCleanupMode !== "preserve") {
74735
- sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode, source: "mesh_remove_node" });
75243
+ sessionCleanup = await this.cleanupMeshSessions({
75244
+ meshId,
75245
+ nodeId,
75246
+ node,
75247
+ mode: sessionCleanupMode,
75248
+ ...explicitSessionIds && explicitSessionIds.length > 0 ? { sessionIds: explicitSessionIds } : {},
75249
+ source: "mesh_remove_node"
75250
+ });
74736
75251
  if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
74737
75252
  }
74738
75253
  let worktreeCleanup;
@@ -76397,6 +76912,7 @@ ${ptyResult.output.slice(-2e3)}`);
76397
76912
  return h.toString(36);
76398
76913
  }
76399
76914
  };
76915
+ init_build_info();
76400
76916
  init_logger();
76401
76917
  init_debug_config();
76402
76918
  var DEFAULT_DAEMON_PORT2 = 19222;