@adhdev/daemon-core 0.9.82-rc.82 → 0.9.82-rc.84

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.mjs CHANGED
@@ -34,6 +34,7 @@ var init_repo_mesh_types = __esm({
34
34
  requirePreTaskCheckpoint: false,
35
35
  requirePostTaskCheckpoint: true,
36
36
  requireApprovalForPush: true,
37
+ allowAutoPublishSubmoduleMainCommits: false,
37
38
  requireApprovalForDestructiveGit: true,
38
39
  dirtyWorkspaceBehavior: "warn",
39
40
  maxParallelTasks: 2,
@@ -787,6 +788,7 @@ function mergeMeshPolicy(base, patch) {
787
788
  }
788
789
  const maxParallelTasks = Number(policy.maxParallelTasks);
789
790
  policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
791
+ policy.allowAutoPublishSubmoduleMainCommits = policy.allowAutoPublishSubmoduleMainCommits === true;
790
792
  if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
791
793
  policy.sessionCleanupOnNodeRemove = "preserve";
792
794
  }
@@ -1173,6 +1175,9 @@ function buildPolicySection(policy) {
1173
1175
  if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
1174
1176
  if (policy.requirePostTaskCheckpoint) rules.push("- Create a git checkpoint **after** each task completes");
1175
1177
  if (policy.requireApprovalForPush) rules.push("- **Ask for user approval** before pushing to remote");
1178
+ if (policy.allowAutoPublishSubmoduleMainCommits) {
1179
+ rules.push("- Refinery may auto-publish unreachable submodule gitlink commits to submodule origin/main with non-force pushes after validation and patch-equivalence pass");
1180
+ }
1176
1181
  if (policy.requireApprovalForDestructiveGit) rules.push("- **Ask for user approval** before destructive git operations (force push, reset, etc.)");
1177
1182
  const dirtyBehavior = {
1178
1183
  block: "- **Do not** send tasks to nodes with dirty workspaces",
@@ -1204,7 +1209,7 @@ function buildRulesSection(coordinatorCliType) {
1204
1209
  - **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
1205
1210
  - **Do not strand completed branches.** A checkpointed or clean feature/worktree branch is not done by itself. Merge/refine it to the mesh default branch, fast-forward obvious clean behind-only branches with \`mesh_fast_forward_node\`, or explicitly report one of \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\` with the next action.
1206
1211
  - **Keep Refinery validation project-configurable.** \`mesh_refine_node\` must execute validation from repo mesh/refine config (for example \`.adhdev/refine.{json,yaml,yml}\`, \`.adhdev/repo-mesh-refine.*\`, or \`repo-mesh.refine.*\`). Heuristics are suggestions/scaffolding only, not the execution path.
1207
- - **Treat submodule main reachability as publish-needed.** A \`submodule_reachability_failed\` refine result means the root gitlink points at a submodule commit that is not reachable from the configured submodule remote main branch. Do not treat feature-branch reachability as complete, retry validation blindly, or start code review first. Classify it as \`blocked_review\`, request user approval to push/publish the submodule commit to submodule main, then rerun \`mesh_refine_node\`.
1212
+ - **Treat submodule main reachability as publish-needed.** A \`submodule_reachability_failed\` refine result means the root gitlink points at a submodule commit that is not reachable from the configured submodule remote main branch. Do not treat feature-branch reachability as complete, retry validation blindly, or start code review first. Classify it as \`blocked_review\`, request user approval to push/publish the submodule commit to submodule main, then rerun \`mesh_refine_node\`, unless the mesh or repo refine config explicitly enabled \`allowAutoPublishSubmoduleMainCommits\` and Refinery reports exact path/commit/remote/branch evidence with post-publish verification.
1208
1213
  - **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
1209
1214
  }
1210
1215
  var TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION;
@@ -1251,7 +1256,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
1251
1256
  4. **Monitor** \u2014 Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly. Use \`mesh_view_queue\` to see the status of all pending, assigned, completed, and failed tasks. Do not call \`mesh_read_chat\` again within a few seconds for the same generating session. Use at most one compact \`mesh_read_chat\` check after a completion/approval signal. Handle approvals via \`mesh_approve\`.
1252
1257
  5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
1253
1258
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
1254
- 7. **Converge branches** \u2014 Before marking any task complete, classify every touched node/branch into exactly one final state: \`merged_to_main\`, \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\`. Use \`mesh_status\` branchConvergenceSummary. For obvious clean branch catch-up (ahead 0, behind > 0, upstream fresh, no dirty/stash/submodule issues), use \`mesh_fast_forward_node\` dry-run first and execute only when explicitly safe/approved; this avoids consuming an agent session. Use \`mesh_refine_node\` for clean worktree branches when safe. Before/refine merging root commits that contain submodule gitlink changes, require each submodule commit to be reachable from the configured submodule remote main branch, not merely present on a feature ref or local checkout. If \`mesh_refine_node\` returns \`submodule_reachability_failed\` or publish-required evidence, keep the public convergence bucket as \`blocked_review\`, ask the user for explicit approval to push/publish the unreachable submodule commit(s) to submodule main, then rerun \`mesh_refine_node\`; do not merge the root branch until the submodule commit(s) are reachable from submodule origin/main. A task that remains on a non-main branch is not fully complete unless the final report names the follow-up state and next step.
1259
+ 7. **Converge branches** \u2014 Before marking any task complete, classify every touched node/branch into exactly one final state: \`merged_to_main\`, \`pushed_feature_branch_needs_merge\`, \`blocked_review\`, \`cleanup_candidate\`, or \`not_mergeable\`. Use \`mesh_status\` branchConvergenceSummary. For obvious clean branch catch-up (ahead 0, behind > 0, upstream fresh, no dirty/stash/submodule issues), use \`mesh_fast_forward_node\` dry-run first and execute only when explicitly safe/approved; this avoids consuming an agent session. Use \`mesh_refine_node\` for clean worktree branches when safe. Before/refine merging root commits that contain submodule gitlink changes, require each submodule commit to be reachable from the configured submodule remote main branch, not merely present on a feature ref or local checkout. If \`mesh_refine_node\` returns \`submodule_reachability_failed\` or publish-required evidence, keep the public convergence bucket as \`blocked_review\`; unless \`allowAutoPublishSubmoduleMainCommits\` is explicitly enabled and Refinery reports successful non-force publish plus post-publish verification, ask the user for explicit approval to push/publish the unreachable submodule commit(s) to submodule main, then rerun \`mesh_refine_node\`. Do not merge the root branch until the submodule commit(s) are reachable from submodule origin/main. A task that remains on a non-main branch is not fully complete unless the final report names the follow-up state and next step.
1255
1260
  8. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
1256
1261
  9. **Report** \u2014 Summarize what was done, what changed, any issues, and the branch convergence state.
1257
1262
 
@@ -3201,7 +3206,8 @@ function injectMeshSystemMessage(components, args) {
3201
3206
  const providerSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId) || void 0;
3202
3207
  const finalSummary = readNonEmptyString2(args.metadataEvent.finalSummary) || void 0;
3203
3208
  const workerResult = readWorkerResultMetadata(args.metadataEvent);
3204
- const completedTask = sessionId ? updateSessionTaskStatus(args.meshId, sessionId, "completed") : null;
3209
+ const hasCompletionEvidence = !!finalSummary || !!workerResult;
3210
+ const completedTask = sessionId && hasCompletionEvidence ? updateSessionTaskStatus(args.meshId, sessionId, "completed") : null;
3205
3211
  if (completedTask) {
3206
3212
  completedTaskForLedger = { id: completedTask.id };
3207
3213
  try {
@@ -8421,6 +8427,11 @@ var MESH_REFINE_CONFIG_SCHEMA = {
8421
8427
  required: ["version"],
8422
8428
  properties: {
8423
8429
  version: { const: 1 },
8430
+ allowAutoPublishSubmoduleMainCommits: {
8431
+ type: "boolean",
8432
+ default: false,
8433
+ description: "When true, Refinery may non-force publish submodule gitlink commits referenced by the refined root tree to each submodule origin/main after validation and patch-equivalence pass, then verify reachability."
8434
+ },
8424
8435
  validation: {
8425
8436
  type: "object",
8426
8437
  additionalProperties: false,
@@ -8513,6 +8524,9 @@ function validateMeshRefineConfig(config, source = "inline") {
8513
8524
  const rejectedCommands = [];
8514
8525
  if (!isRecord(config)) return { valid: false, errors: ["config must be an object"], commands, rejectedCommands };
8515
8526
  if (config.version !== 1) errors.push("version must be 1");
8527
+ if (config.allowAutoPublishSubmoduleMainCommits !== void 0 && typeof config.allowAutoPublishSubmoduleMainCommits !== "boolean") {
8528
+ errors.push("allowAutoPublishSubmoduleMainCommits must be a boolean when provided");
8529
+ }
8516
8530
  const validation = config.validation;
8517
8531
  if (validation !== void 0 && !isRecord(validation)) errors.push("validation must be an object");
8518
8532
  const rawCommands = isRecord(validation) ? validation.commands : void 0;
@@ -15951,6 +15965,15 @@ function normalizeReadChatCommandStatus(status, activeModal) {
15951
15965
  function isGeneratingLikeStatus(status) {
15952
15966
  return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
15953
15967
  }
15968
+ function hasVisibleAssistantMessage(messages) {
15969
+ if (!Array.isArray(messages)) return false;
15970
+ return messages.some((message) => {
15971
+ if (!message || message.role !== "assistant") return false;
15972
+ const kind = typeof message.kind === "string" ? message.kind : "standard";
15973
+ if (kind !== "standard") return false;
15974
+ return String(message.content || "").trim().length > 0;
15975
+ });
15976
+ }
15954
15977
  function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
15955
15978
  if (!isGeneratingLikeStatus(parsedStatus)) return false;
15956
15979
  if (hasNonEmptyModalButtons(activeModal)) return false;
@@ -15964,6 +15987,9 @@ function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterS
15964
15987
  if (adapterRawStatus === "starting" && isGeneratingLikeStatus(parsedStatus) && !hasNonEmptyModalButtons(activeModal) && Array.isArray(parsedMessages) && parsedMessages.length === 0 && Array.isArray(adapterStatus?.messages) && adapterStatus.messages.length === 0 && !(typeof adapter.isProcessing === "function" && adapter.isProcessing())) {
15965
15988
  return "starting";
15966
15989
  }
15990
+ if (isGeneratingLikeStatus(adapterRawStatus) && parsedStatus === "idle" && !hasNonEmptyModalButtons(activeModal) && !hasVisibleAssistantMessage(parsedMessages)) {
15991
+ return adapterRawStatus;
15992
+ }
15967
15993
  if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
15968
15994
  return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
15969
15995
  }
@@ -16472,7 +16498,7 @@ async function handleReadChat(h, args) {
16472
16498
  returnedMessages,
16473
16499
  ptyStatusApprovalOnly: false
16474
16500
  });
16475
- if (supportsCliNativeTranscript(providerType)) {
16501
+ if (supportsCliNativeTranscript(providerType) && provider?.canonicalHistory?.mode === "native-source") {
16476
16502
  const agentStr = provider?.type || args?.agentType || getCurrentProviderType(h, adapter.cliType);
16477
16503
  const workspace = typeof args?.workspace === "string" ? args.workspace : typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : typeof adapter.workingDir === "string" ? adapter.workingDir : void 0;
16478
16504
  const nativeHistoryLimit = Math.max(
@@ -16631,6 +16657,17 @@ async function handleReadChat(h, args) {
16631
16657
  freshEnough: true,
16632
16658
  ptyStatusApprovalOnly: false
16633
16659
  });
16660
+ const requiresNativeSource = supportsCliNativeTranscript(agentStr) && provider?.canonicalHistory?.mode === "native-source";
16661
+ if (requiresNativeSource && !nativeSelected) {
16662
+ return {
16663
+ success: false,
16664
+ code: "native_history_not_safely_available",
16665
+ error: "Provider-native history was not safely available for the requested CLI session.",
16666
+ providerSessionId: historyProviderSessionId,
16667
+ messageSource,
16668
+ transcriptProvenance: messageSource
16669
+ };
16670
+ }
16634
16671
  return buildReadChatCommandResult({
16635
16672
  messages: historyMessages,
16636
16673
  status: "idle",
@@ -21534,6 +21571,14 @@ function hasAdapterPendingResponse(adapter) {
21534
21571
  function countMessages(value) {
21535
21572
  return Array.isArray(value) ? value.length : 0;
21536
21573
  }
21574
+ function hasFinalAssistantMessage(value) {
21575
+ const messages = Array.isArray(value) ? value : [];
21576
+ const last = messages[messages.length - 1];
21577
+ if (!last || last.role !== "assistant") return false;
21578
+ if (last.bubbleState === "streaming") return false;
21579
+ if (last.meta?.streaming === true) return false;
21580
+ return typeof last.content === "string" && last.content.trim().length > 0;
21581
+ }
21537
21582
  function hasZeroMessageStartingLaunch(adapter) {
21538
21583
  const adapterStatus = adapter?.getStatus?.({ allowParse: false }) ?? adapter?.getStatus?.() ?? {};
21539
21584
  const parsedStatus = typeof adapter?.getScriptParsedStatus === "function" ? adapter.getScriptParsedStatus() : {};
@@ -21545,6 +21590,17 @@ function hasZeroMessageStartingLaunch(adapter) {
21545
21590
  if (countMessages(adapterStatus?.messages) > 0 || countMessages(parsedStatus?.messages) > 0) return false;
21546
21591
  return !hasAdapterPendingResponse(adapter);
21547
21592
  }
21593
+ function hasCompletedStartingLaunch(adapter) {
21594
+ const adapterStatus = adapter?.getStatus?.({ allowParse: false }) ?? adapter?.getStatus?.() ?? {};
21595
+ const adapterRawStatus = normalizeAgentStatus(adapterStatus?.status);
21596
+ if (adapterRawStatus !== "starting") return false;
21597
+ if (hasAdapterPendingResponse(adapter)) return false;
21598
+ const parsedStatus = typeof adapter?.getScriptParsedStatus === "function" ? adapter.getScriptParsedStatus() : {};
21599
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
21600
+ if (parsedRawStatus !== "idle") return false;
21601
+ if (hasNonEmptyModalButtons2(adapterStatus?.activeModal ?? adapterStatus?.modal ?? parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
21602
+ return hasFinalAssistantMessage(parsedStatus?.messages);
21603
+ }
21548
21604
  function shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapter) {
21549
21605
  const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
21550
21606
  if (!BUSY_AGENT_STATUSES.has(parsedRawStatus)) return false;
@@ -21554,6 +21610,7 @@ function shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapte
21554
21610
  }
21555
21611
  function getEffectiveAgentSendStatus(adapter) {
21556
21612
  const adapterStatus = normalizeAgentStatus(adapter?.getStatus?.({ allowParse: false })?.status ?? adapter?.getStatus?.()?.status);
21613
+ if (adapterStatus === "starting" && hasCompletedStartingLaunch(adapter)) return "idle";
21557
21614
  if (adapterStatus && adapterStatus !== "idle") return adapterStatus;
21558
21615
  if (adapterStatus !== "idle") return adapterStatus;
21559
21616
  if (typeof adapter?.getScriptParsedStatus !== "function") return adapterStatus;
@@ -26532,6 +26589,16 @@ function buildSubmodulePublishRequiredNextStep(entries) {
26532
26589
  const refs = entries.map((entry) => `${entry.path}@${entry.commit}`).join(", ");
26533
26590
  return `Ask the user for explicit approval to push/publish the unreachable submodule commit(s) (${refs}) to the configured submodule remote main branch, then rerun mesh_refine_node. Do not merge the root branch until every submodule gitlink commit is reachable from submodule origin/main.`;
26534
26591
  }
26592
+ function resolveRefineryAutoPublishSubmoduleMainCommits(mesh, workspace) {
26593
+ if (mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true) {
26594
+ return { enabled: true, source: "mesh.policy.allowAutoPublishSubmoduleMainCommits" };
26595
+ }
26596
+ const loaded = loadMeshRefineConfig(mesh, workspace);
26597
+ if (loaded.config?.allowAutoPublishSubmoduleMainCommits === true) {
26598
+ return { enabled: true, source: loaded.path || loaded.source };
26599
+ }
26600
+ return { enabled: false };
26601
+ }
26535
26602
  async function computeGitPatchId(cwd, fromRef, toRef) {
26536
26603
  const { execFileSync: execFileSync3 } = await import("child_process");
26537
26604
  const diff = execFileSync3("git", ["diff", "--patch", "--full-index", fromRef, toRef], {
@@ -26600,7 +26667,7 @@ async function runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead)
26600
26667
  };
26601
26668
  }
26602
26669
  }
26603
- async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26670
+ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, options = {}) {
26604
26671
  const startedAt = Date.now();
26605
26672
  const entries = [];
26606
26673
  try {
@@ -26621,6 +26688,17 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26621
26688
  await runGit2(submodulePath, ["-c", "protocol.file.allow=always", "fetch", "origin", `refs/heads/${branch}:refs/remotes/origin/${branch}`]);
26622
26689
  await runGit2(submodulePath, ["merge-base", "--is-ancestor", commit, `refs/remotes/origin/${branch}`]);
26623
26690
  };
26691
+ const publishCommitToRemoteMain = async (submodulePath, commit, branch = "main") => {
26692
+ const refspec = `${commit}:refs/heads/${branch}`;
26693
+ const { stdout, stderr } = await execFileAsync3("git", ["push", "origin", refspec], {
26694
+ cwd: submodulePath,
26695
+ encoding: "utf8",
26696
+ timeout: 3e4,
26697
+ maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES,
26698
+ windowsHide: true
26699
+ });
26700
+ return { stdout: String(stdout || ""), stderr: String(stderr || ""), refspec };
26701
+ };
26624
26702
  const treeOutput = await runGit2(repoRoot, ["ls-tree", "-r", "-z", mergedTree]);
26625
26703
  const gitlinks = treeOutput.split("\0").filter(Boolean).map((record) => {
26626
26704
  const match = /^160000\s+commit\s+([0-9a-f]{40})\t(.+)$/.exec(record);
@@ -26661,11 +26739,43 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26661
26739
  continue;
26662
26740
  }
26663
26741
  entry.remoteMainBranch = "main";
26664
- await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, "main");
26665
- entry.fetchedFromOrigin = true;
26666
- entry.remoteReachable = true;
26667
- entry.remoteMainReachable = true;
26668
- entry.reachable = true;
26742
+ try {
26743
+ await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, "main");
26744
+ entry.fetchedFromOrigin = true;
26745
+ entry.remoteReachable = true;
26746
+ entry.remoteMainReachable = true;
26747
+ entry.reachable = true;
26748
+ } catch (e) {
26749
+ entry.remoteReachable = false;
26750
+ entry.remoteMainReachable = false;
26751
+ entry.publishRequired = true;
26752
+ const details = truncateValidationOutput(e?.stderr || e?.message || String(e));
26753
+ entry.error = `Submodule remote main reachability check failed for origin/main: ${details}`;
26754
+ if (options.allowAutoPublishSubmoduleMainCommits === true && entry.localReachable === true) {
26755
+ entry.autoPublishAllowed = true;
26756
+ entry.autoPublishAttempted = true;
26757
+ try {
26758
+ const publish = await publishCommitToRemoteMain(submodulePath, gitlink.commit, "main");
26759
+ entry.autoPublishRefspec = publish.refspec;
26760
+ entry.publishStdout = truncateValidationOutput(publish.stdout);
26761
+ entry.publishStderr = truncateValidationOutput(publish.stderr);
26762
+ entry.autoPublishSucceeded = true;
26763
+ await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, "main");
26764
+ entry.fetchedFromOrigin = true;
26765
+ entry.remoteReachable = true;
26766
+ entry.remoteMainReachable = true;
26767
+ entry.autoPublishVerified = true;
26768
+ entry.publishRequired = false;
26769
+ entry.reachable = true;
26770
+ entry.error = void 0;
26771
+ } catch (publishError) {
26772
+ entry.autoPublishSucceeded = false;
26773
+ entry.autoPublishVerified = false;
26774
+ const publishDetails = truncateValidationOutput(publishError?.stderr || publishError?.message || String(publishError));
26775
+ entry.error = `Submodule auto-publish to origin/main failed or could not be verified: ${publishDetails}`;
26776
+ }
26777
+ }
26778
+ }
26669
26779
  } catch (e) {
26670
26780
  entry.remoteReachable = false;
26671
26781
  entry.remoteMainReachable = false;
@@ -26685,7 +26795,9 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26685
26795
  checked: entries.length,
26686
26796
  unreachable: unreachable.map((entry) => ({ ...entry, publishRequired: entry.publishRequired !== false })),
26687
26797
  entries: entries.map((entry) => entry.reachable ? entry : { ...entry, publishRequired: entry.publishRequired !== false }),
26688
- durationMs: Date.now() - startedAt
26798
+ durationMs: Date.now() - startedAt,
26799
+ autoPublishAllowed: options.allowAutoPublishSubmoduleMainCommits === true,
26800
+ autoPublishPolicySource: options.autoPublishPolicySource
26689
26801
  };
26690
26802
  } catch (e) {
26691
26803
  const unreachable = entries.filter((entry) => !entry.reachable).map((entry) => ({ ...entry, publishRequired: true }));
@@ -26695,6 +26807,8 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26695
26807
  unreachable,
26696
26808
  entries: entries.map((entry) => entry.reachable ? entry : { ...entry, publishRequired: true }),
26697
26809
  durationMs: Date.now() - startedAt,
26810
+ autoPublishAllowed: options.allowAutoPublishSubmoduleMainCommits === true,
26811
+ autoPublishPolicySource: options.autoPublishPolicySource,
26698
26812
  error: truncateValidationOutput(e?.message || String(e))
26699
26813
  };
26700
26814
  }
@@ -27833,13 +27947,36 @@ var DaemonCommandRouter = class {
27833
27947
  };
27834
27948
  }
27835
27949
  const submoduleReachabilityStarted = Date.now();
27836
- const submoduleReachability = await runMeshRefineSubmoduleReachabilityGate(repoRoot, patchEquivalence.mergedTree || branchHead);
27950
+ const autoPublishSubmoduleMainCommits = resolveRefineryAutoPublishSubmoduleMainCommits(mesh, node.workspace);
27951
+ const submoduleReachability = await runMeshRefineSubmoduleReachabilityGate(repoRoot, patchEquivalence.mergedTree || branchHead, {
27952
+ allowAutoPublishSubmoduleMainCommits: autoPublishSubmoduleMainCommits.enabled,
27953
+ autoPublishPolicySource: autoPublishSubmoduleMainCommits.source
27954
+ });
27837
27955
  recordMeshRefineStage(refineStages, "submodule_reachability", submoduleReachability.status, submoduleReachabilityStarted, {
27838
27956
  checked: submoduleReachability.checked,
27957
+ autoPublishAllowed: submoduleReachability.autoPublishAllowed,
27958
+ autoPublishPolicySource: submoduleReachability.autoPublishPolicySource,
27959
+ autoPublished: submoduleReachability.entries.filter((entry) => entry.autoPublishAttempted).map((entry) => ({
27960
+ path: entry.path,
27961
+ commit: entry.commit,
27962
+ remote: entry.remote,
27963
+ remoteUrl: entry.remoteUrl,
27964
+ remoteMainBranch: entry.remoteMainBranch,
27965
+ refspec: entry.autoPublishRefspec,
27966
+ succeeded: entry.autoPublishSucceeded,
27967
+ verified: entry.autoPublishVerified,
27968
+ remoteMainReachable: entry.remoteMainReachable,
27969
+ error: entry.error
27970
+ })),
27839
27971
  unreachable: submoduleReachability.unreachable.map((entry) => ({
27840
27972
  path: entry.path,
27841
27973
  commit: entry.commit,
27842
27974
  publishRequired: entry.publishRequired === true,
27975
+ autoPublishAllowed: entry.autoPublishAllowed,
27976
+ autoPublishAttempted: entry.autoPublishAttempted,
27977
+ autoPublishSucceeded: entry.autoPublishSucceeded,
27978
+ autoPublishVerified: entry.autoPublishVerified,
27979
+ autoPublishRefspec: entry.autoPublishRefspec,
27843
27980
  remote: entry.remote,
27844
27981
  remoteUrl: entry.remoteUrl,
27845
27982
  remoteReachable: entry.remoteReachable,
@@ -27873,6 +28010,11 @@ var DaemonCommandRouter = class {
27873
28010
  remoteReachable: entry.remoteReachable,
27874
28011
  remoteMainBranch: entry.remoteMainBranch,
27875
28012
  remoteMainReachable: entry.remoteMainReachable,
28013
+ autoPublishAllowed: entry.autoPublishAllowed,
28014
+ autoPublishAttempted: entry.autoPublishAttempted,
28015
+ autoPublishSucceeded: entry.autoPublishSucceeded,
28016
+ autoPublishVerified: entry.autoPublishVerified,
28017
+ autoPublishRefspec: entry.autoPublishRefspec,
27876
28018
  error: entry.error
27877
28019
  })),
27878
28020
  branch,
@@ -27947,7 +28089,7 @@ var DaemonCommandRouter = class {
27947
28089
  appendLedgerEntry2(meshId, {
27948
28090
  kind: "node_removed",
27949
28091
  nodeId,
27950
- payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary, patchEquivalence }
28092
+ payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary, patchEquivalence, submoduleReachability }
27951
28093
  });
27952
28094
  recordMeshRefineStage(refineStages, "ledger", "passed", ledgerStarted);
27953
28095
  } catch (e) {
@@ -27975,6 +28117,7 @@ var DaemonCommandRouter = class {
27975
28117
  removeResult,
27976
28118
  validationSummary,
27977
28119
  patchEquivalence,
28120
+ submoduleReachability,
27978
28121
  mergeResult,
27979
28122
  refineStages,
27980
28123
  ...ledgerError ? { ledgerError } : {},
@@ -27989,6 +28132,7 @@ var DaemonCommandRouter = class {
27989
28132
  removeResult,
27990
28133
  validationSummary,
27991
28134
  patchEquivalence,
28135
+ submoduleReachability,
27992
28136
  mergeResult,
27993
28137
  refineStages,
27994
28138
  ...ledgerError ? { ledgerError } : {},