@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.js CHANGED
@@ -39,6 +39,7 @@ var init_repo_mesh_types = __esm({
39
39
  requirePreTaskCheckpoint: false,
40
40
  requirePostTaskCheckpoint: true,
41
41
  requireApprovalForPush: true,
42
+ allowAutoPublishSubmoduleMainCommits: false,
42
43
  requireApprovalForDestructiveGit: true,
43
44
  dirtyWorkspaceBehavior: "warn",
44
45
  maxParallelTasks: 2,
@@ -789,6 +790,7 @@ function mergeMeshPolicy(base, patch) {
789
790
  }
790
791
  const maxParallelTasks = Number(policy.maxParallelTasks);
791
792
  policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
793
+ policy.allowAutoPublishSubmoduleMainCommits = policy.allowAutoPublishSubmoduleMainCommits === true;
792
794
  if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
793
795
  policy.sessionCleanupOnNodeRemove = "preserve";
794
796
  }
@@ -1178,6 +1180,9 @@ function buildPolicySection(policy) {
1178
1180
  if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
1179
1181
  if (policy.requirePostTaskCheckpoint) rules.push("- Create a git checkpoint **after** each task completes");
1180
1182
  if (policy.requireApprovalForPush) rules.push("- **Ask for user approval** before pushing to remote");
1183
+ if (policy.allowAutoPublishSubmoduleMainCommits) {
1184
+ rules.push("- Refinery may auto-publish unreachable submodule gitlink commits to submodule origin/main with non-force pushes after validation and patch-equivalence pass");
1185
+ }
1181
1186
  if (policy.requireApprovalForDestructiveGit) rules.push("- **Ask for user approval** before destructive git operations (force push, reset, etc.)");
1182
1187
  const dirtyBehavior = {
1183
1188
  block: "- **Do not** send tasks to nodes with dirty workspaces",
@@ -1209,7 +1214,7 @@ function buildRulesSection(coordinatorCliType) {
1209
1214
  - **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
1210
1215
  - **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.
1211
1216
  - **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.
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\`.
1217
+ - **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.
1213
1218
  - **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
1214
1219
  }
1215
1220
  var TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION;
@@ -1256,7 +1261,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
1256
1261
  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\`.
1257
1262
  5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
1258
1263
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
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\`, 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.
1264
+ 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.
1260
1265
  8. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
1261
1266
  9. **Report** \u2014 Summarize what was done, what changed, any issues, and the branch convergence state.
1262
1267
 
@@ -3206,7 +3211,8 @@ function injectMeshSystemMessage(components, args) {
3206
3211
  const providerSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId) || void 0;
3207
3212
  const finalSummary = readNonEmptyString2(args.metadataEvent.finalSummary) || void 0;
3208
3213
  const workerResult = readWorkerResultMetadata(args.metadataEvent);
3209
- const completedTask = sessionId ? updateSessionTaskStatus(args.meshId, sessionId, "completed") : null;
3214
+ const hasCompletionEvidence = !!finalSummary || !!workerResult;
3215
+ const completedTask = sessionId && hasCompletionEvidence ? updateSessionTaskStatus(args.meshId, sessionId, "completed") : null;
3210
3216
  if (completedTask) {
3211
3217
  completedTaskForLedger = { id: completedTask.id };
3212
3218
  try {
@@ -8680,6 +8686,11 @@ var MESH_REFINE_CONFIG_SCHEMA = {
8680
8686
  required: ["version"],
8681
8687
  properties: {
8682
8688
  version: { const: 1 },
8689
+ allowAutoPublishSubmoduleMainCommits: {
8690
+ type: "boolean",
8691
+ default: false,
8692
+ 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."
8693
+ },
8683
8694
  validation: {
8684
8695
  type: "object",
8685
8696
  additionalProperties: false,
@@ -8772,6 +8783,9 @@ function validateMeshRefineConfig(config, source = "inline") {
8772
8783
  const rejectedCommands = [];
8773
8784
  if (!isRecord(config)) return { valid: false, errors: ["config must be an object"], commands, rejectedCommands };
8774
8785
  if (config.version !== 1) errors.push("version must be 1");
8786
+ if (config.allowAutoPublishSubmoduleMainCommits !== void 0 && typeof config.allowAutoPublishSubmoduleMainCommits !== "boolean") {
8787
+ errors.push("allowAutoPublishSubmoduleMainCommits must be a boolean when provided");
8788
+ }
8775
8789
  const validation = config.validation;
8776
8790
  if (validation !== void 0 && !isRecord(validation)) errors.push("validation must be an object");
8777
8791
  const rawCommands = isRecord(validation) ? validation.commands : void 0;
@@ -16210,6 +16224,15 @@ function normalizeReadChatCommandStatus(status, activeModal) {
16210
16224
  function isGeneratingLikeStatus(status) {
16211
16225
  return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
16212
16226
  }
16227
+ function hasVisibleAssistantMessage(messages) {
16228
+ if (!Array.isArray(messages)) return false;
16229
+ return messages.some((message) => {
16230
+ if (!message || message.role !== "assistant") return false;
16231
+ const kind = typeof message.kind === "string" ? message.kind : "standard";
16232
+ if (kind !== "standard") return false;
16233
+ return String(message.content || "").trim().length > 0;
16234
+ });
16235
+ }
16213
16236
  function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
16214
16237
  if (!isGeneratingLikeStatus(parsedStatus)) return false;
16215
16238
  if (hasNonEmptyModalButtons(activeModal)) return false;
@@ -16223,6 +16246,9 @@ function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterS
16223
16246
  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())) {
16224
16247
  return "starting";
16225
16248
  }
16249
+ if (isGeneratingLikeStatus(adapterRawStatus) && parsedStatus === "idle" && !hasNonEmptyModalButtons(activeModal) && !hasVisibleAssistantMessage(parsedMessages)) {
16250
+ return adapterRawStatus;
16251
+ }
16226
16252
  if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
16227
16253
  return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
16228
16254
  }
@@ -16731,7 +16757,7 @@ async function handleReadChat(h, args) {
16731
16757
  returnedMessages,
16732
16758
  ptyStatusApprovalOnly: false
16733
16759
  });
16734
- if (supportsCliNativeTranscript(providerType)) {
16760
+ if (supportsCliNativeTranscript(providerType) && provider?.canonicalHistory?.mode === "native-source") {
16735
16761
  const agentStr = provider?.type || args?.agentType || getCurrentProviderType(h, adapter.cliType);
16736
16762
  const workspace = typeof args?.workspace === "string" ? args.workspace : typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : typeof adapter.workingDir === "string" ? adapter.workingDir : void 0;
16737
16763
  const nativeHistoryLimit = Math.max(
@@ -16890,6 +16916,17 @@ async function handleReadChat(h, args) {
16890
16916
  freshEnough: true,
16891
16917
  ptyStatusApprovalOnly: false
16892
16918
  });
16919
+ const requiresNativeSource = supportsCliNativeTranscript(agentStr) && provider?.canonicalHistory?.mode === "native-source";
16920
+ if (requiresNativeSource && !nativeSelected) {
16921
+ return {
16922
+ success: false,
16923
+ code: "native_history_not_safely_available",
16924
+ error: "Provider-native history was not safely available for the requested CLI session.",
16925
+ providerSessionId: historyProviderSessionId,
16926
+ messageSource,
16927
+ transcriptProvenance: messageSource
16928
+ };
16929
+ }
16893
16930
  return buildReadChatCommandResult({
16894
16931
  messages: historyMessages,
16895
16932
  status: "idle",
@@ -21788,6 +21825,14 @@ function hasAdapterPendingResponse(adapter) {
21788
21825
  function countMessages(value) {
21789
21826
  return Array.isArray(value) ? value.length : 0;
21790
21827
  }
21828
+ function hasFinalAssistantMessage(value) {
21829
+ const messages = Array.isArray(value) ? value : [];
21830
+ const last = messages[messages.length - 1];
21831
+ if (!last || last.role !== "assistant") return false;
21832
+ if (last.bubbleState === "streaming") return false;
21833
+ if (last.meta?.streaming === true) return false;
21834
+ return typeof last.content === "string" && last.content.trim().length > 0;
21835
+ }
21791
21836
  function hasZeroMessageStartingLaunch(adapter) {
21792
21837
  const adapterStatus = adapter?.getStatus?.({ allowParse: false }) ?? adapter?.getStatus?.() ?? {};
21793
21838
  const parsedStatus = typeof adapter?.getScriptParsedStatus === "function" ? adapter.getScriptParsedStatus() : {};
@@ -21799,6 +21844,17 @@ function hasZeroMessageStartingLaunch(adapter) {
21799
21844
  if (countMessages(adapterStatus?.messages) > 0 || countMessages(parsedStatus?.messages) > 0) return false;
21800
21845
  return !hasAdapterPendingResponse(adapter);
21801
21846
  }
21847
+ function hasCompletedStartingLaunch(adapter) {
21848
+ const adapterStatus = adapter?.getStatus?.({ allowParse: false }) ?? adapter?.getStatus?.() ?? {};
21849
+ const adapterRawStatus = normalizeAgentStatus(adapterStatus?.status);
21850
+ if (adapterRawStatus !== "starting") return false;
21851
+ if (hasAdapterPendingResponse(adapter)) return false;
21852
+ const parsedStatus = typeof adapter?.getScriptParsedStatus === "function" ? adapter.getScriptParsedStatus() : {};
21853
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
21854
+ if (parsedRawStatus !== "idle") return false;
21855
+ if (hasNonEmptyModalButtons2(adapterStatus?.activeModal ?? adapterStatus?.modal ?? parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
21856
+ return hasFinalAssistantMessage(parsedStatus?.messages);
21857
+ }
21802
21858
  function shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapter) {
21803
21859
  const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
21804
21860
  if (!BUSY_AGENT_STATUSES.has(parsedRawStatus)) return false;
@@ -21808,6 +21864,7 @@ function shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapte
21808
21864
  }
21809
21865
  function getEffectiveAgentSendStatus(adapter) {
21810
21866
  const adapterStatus = normalizeAgentStatus(adapter?.getStatus?.({ allowParse: false })?.status ?? adapter?.getStatus?.()?.status);
21867
+ if (adapterStatus === "starting" && hasCompletedStartingLaunch(adapter)) return "idle";
21811
21868
  if (adapterStatus && adapterStatus !== "idle") return adapterStatus;
21812
21869
  if (adapterStatus !== "idle") return adapterStatus;
21813
21870
  if (typeof adapter?.getScriptParsedStatus !== "function") return adapterStatus;
@@ -26786,6 +26843,16 @@ function buildSubmodulePublishRequiredNextStep(entries) {
26786
26843
  const refs = entries.map((entry) => `${entry.path}@${entry.commit}`).join(", ");
26787
26844
  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.`;
26788
26845
  }
26846
+ function resolveRefineryAutoPublishSubmoduleMainCommits(mesh, workspace) {
26847
+ if (mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true) {
26848
+ return { enabled: true, source: "mesh.policy.allowAutoPublishSubmoduleMainCommits" };
26849
+ }
26850
+ const loaded = loadMeshRefineConfig(mesh, workspace);
26851
+ if (loaded.config?.allowAutoPublishSubmoduleMainCommits === true) {
26852
+ return { enabled: true, source: loaded.path || loaded.source };
26853
+ }
26854
+ return { enabled: false };
26855
+ }
26789
26856
  async function computeGitPatchId(cwd, fromRef, toRef) {
26790
26857
  const { execFileSync: execFileSync3 } = await import("child_process");
26791
26858
  const diff = execFileSync3("git", ["diff", "--patch", "--full-index", fromRef, toRef], {
@@ -26854,7 +26921,7 @@ async function runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead)
26854
26921
  };
26855
26922
  }
26856
26923
  }
26857
- async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26924
+ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, options = {}) {
26858
26925
  const startedAt = Date.now();
26859
26926
  const entries = [];
26860
26927
  try {
@@ -26875,6 +26942,17 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26875
26942
  await runGit2(submodulePath, ["-c", "protocol.file.allow=always", "fetch", "origin", `refs/heads/${branch}:refs/remotes/origin/${branch}`]);
26876
26943
  await runGit2(submodulePath, ["merge-base", "--is-ancestor", commit, `refs/remotes/origin/${branch}`]);
26877
26944
  };
26945
+ const publishCommitToRemoteMain = async (submodulePath, commit, branch = "main") => {
26946
+ const refspec = `${commit}:refs/heads/${branch}`;
26947
+ const { stdout, stderr } = await execFileAsync3("git", ["push", "origin", refspec], {
26948
+ cwd: submodulePath,
26949
+ encoding: "utf8",
26950
+ timeout: 3e4,
26951
+ maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES,
26952
+ windowsHide: true
26953
+ });
26954
+ return { stdout: String(stdout || ""), stderr: String(stderr || ""), refspec };
26955
+ };
26878
26956
  const treeOutput = await runGit2(repoRoot, ["ls-tree", "-r", "-z", mergedTree]);
26879
26957
  const gitlinks = treeOutput.split("\0").filter(Boolean).map((record) => {
26880
26958
  const match = /^160000\s+commit\s+([0-9a-f]{40})\t(.+)$/.exec(record);
@@ -26915,11 +26993,43 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26915
26993
  continue;
26916
26994
  }
26917
26995
  entry.remoteMainBranch = "main";
26918
- await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, "main");
26919
- entry.fetchedFromOrigin = true;
26920
- entry.remoteReachable = true;
26921
- entry.remoteMainReachable = true;
26922
- entry.reachable = true;
26996
+ try {
26997
+ await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, "main");
26998
+ entry.fetchedFromOrigin = true;
26999
+ entry.remoteReachable = true;
27000
+ entry.remoteMainReachable = true;
27001
+ entry.reachable = true;
27002
+ } catch (e) {
27003
+ entry.remoteReachable = false;
27004
+ entry.remoteMainReachable = false;
27005
+ entry.publishRequired = true;
27006
+ const details = truncateValidationOutput(e?.stderr || e?.message || String(e));
27007
+ entry.error = `Submodule remote main reachability check failed for origin/main: ${details}`;
27008
+ if (options.allowAutoPublishSubmoduleMainCommits === true && entry.localReachable === true) {
27009
+ entry.autoPublishAllowed = true;
27010
+ entry.autoPublishAttempted = true;
27011
+ try {
27012
+ const publish = await publishCommitToRemoteMain(submodulePath, gitlink.commit, "main");
27013
+ entry.autoPublishRefspec = publish.refspec;
27014
+ entry.publishStdout = truncateValidationOutput(publish.stdout);
27015
+ entry.publishStderr = truncateValidationOutput(publish.stderr);
27016
+ entry.autoPublishSucceeded = true;
27017
+ await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, "main");
27018
+ entry.fetchedFromOrigin = true;
27019
+ entry.remoteReachable = true;
27020
+ entry.remoteMainReachable = true;
27021
+ entry.autoPublishVerified = true;
27022
+ entry.publishRequired = false;
27023
+ entry.reachable = true;
27024
+ entry.error = void 0;
27025
+ } catch (publishError) {
27026
+ entry.autoPublishSucceeded = false;
27027
+ entry.autoPublishVerified = false;
27028
+ const publishDetails = truncateValidationOutput(publishError?.stderr || publishError?.message || String(publishError));
27029
+ entry.error = `Submodule auto-publish to origin/main failed or could not be verified: ${publishDetails}`;
27030
+ }
27031
+ }
27032
+ }
26923
27033
  } catch (e) {
26924
27034
  entry.remoteReachable = false;
26925
27035
  entry.remoteMainReachable = false;
@@ -26939,7 +27049,9 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26939
27049
  checked: entries.length,
26940
27050
  unreachable: unreachable.map((entry) => ({ ...entry, publishRequired: entry.publishRequired !== false })),
26941
27051
  entries: entries.map((entry) => entry.reachable ? entry : { ...entry, publishRequired: entry.publishRequired !== false }),
26942
- durationMs: Date.now() - startedAt
27052
+ durationMs: Date.now() - startedAt,
27053
+ autoPublishAllowed: options.allowAutoPublishSubmoduleMainCommits === true,
27054
+ autoPublishPolicySource: options.autoPublishPolicySource
26943
27055
  };
26944
27056
  } catch (e) {
26945
27057
  const unreachable = entries.filter((entry) => !entry.reachable).map((entry) => ({ ...entry, publishRequired: true }));
@@ -26949,6 +27061,8 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26949
27061
  unreachable,
26950
27062
  entries: entries.map((entry) => entry.reachable ? entry : { ...entry, publishRequired: true }),
26951
27063
  durationMs: Date.now() - startedAt,
27064
+ autoPublishAllowed: options.allowAutoPublishSubmoduleMainCommits === true,
27065
+ autoPublishPolicySource: options.autoPublishPolicySource,
26952
27066
  error: truncateValidationOutput(e?.message || String(e))
26953
27067
  };
26954
27068
  }
@@ -28087,13 +28201,36 @@ var DaemonCommandRouter = class {
28087
28201
  };
28088
28202
  }
28089
28203
  const submoduleReachabilityStarted = Date.now();
28090
- const submoduleReachability = await runMeshRefineSubmoduleReachabilityGate(repoRoot, patchEquivalence.mergedTree || branchHead);
28204
+ const autoPublishSubmoduleMainCommits = resolveRefineryAutoPublishSubmoduleMainCommits(mesh, node.workspace);
28205
+ const submoduleReachability = await runMeshRefineSubmoduleReachabilityGate(repoRoot, patchEquivalence.mergedTree || branchHead, {
28206
+ allowAutoPublishSubmoduleMainCommits: autoPublishSubmoduleMainCommits.enabled,
28207
+ autoPublishPolicySource: autoPublishSubmoduleMainCommits.source
28208
+ });
28091
28209
  recordMeshRefineStage(refineStages, "submodule_reachability", submoduleReachability.status, submoduleReachabilityStarted, {
28092
28210
  checked: submoduleReachability.checked,
28211
+ autoPublishAllowed: submoduleReachability.autoPublishAllowed,
28212
+ autoPublishPolicySource: submoduleReachability.autoPublishPolicySource,
28213
+ autoPublished: submoduleReachability.entries.filter((entry) => entry.autoPublishAttempted).map((entry) => ({
28214
+ path: entry.path,
28215
+ commit: entry.commit,
28216
+ remote: entry.remote,
28217
+ remoteUrl: entry.remoteUrl,
28218
+ remoteMainBranch: entry.remoteMainBranch,
28219
+ refspec: entry.autoPublishRefspec,
28220
+ succeeded: entry.autoPublishSucceeded,
28221
+ verified: entry.autoPublishVerified,
28222
+ remoteMainReachable: entry.remoteMainReachable,
28223
+ error: entry.error
28224
+ })),
28093
28225
  unreachable: submoduleReachability.unreachable.map((entry) => ({
28094
28226
  path: entry.path,
28095
28227
  commit: entry.commit,
28096
28228
  publishRequired: entry.publishRequired === true,
28229
+ autoPublishAllowed: entry.autoPublishAllowed,
28230
+ autoPublishAttempted: entry.autoPublishAttempted,
28231
+ autoPublishSucceeded: entry.autoPublishSucceeded,
28232
+ autoPublishVerified: entry.autoPublishVerified,
28233
+ autoPublishRefspec: entry.autoPublishRefspec,
28097
28234
  remote: entry.remote,
28098
28235
  remoteUrl: entry.remoteUrl,
28099
28236
  remoteReachable: entry.remoteReachable,
@@ -28127,6 +28264,11 @@ var DaemonCommandRouter = class {
28127
28264
  remoteReachable: entry.remoteReachable,
28128
28265
  remoteMainBranch: entry.remoteMainBranch,
28129
28266
  remoteMainReachable: entry.remoteMainReachable,
28267
+ autoPublishAllowed: entry.autoPublishAllowed,
28268
+ autoPublishAttempted: entry.autoPublishAttempted,
28269
+ autoPublishSucceeded: entry.autoPublishSucceeded,
28270
+ autoPublishVerified: entry.autoPublishVerified,
28271
+ autoPublishRefspec: entry.autoPublishRefspec,
28130
28272
  error: entry.error
28131
28273
  })),
28132
28274
  branch,
@@ -28201,7 +28343,7 @@ var DaemonCommandRouter = class {
28201
28343
  appendLedgerEntry2(meshId, {
28202
28344
  kind: "node_removed",
28203
28345
  nodeId,
28204
- payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary, patchEquivalence }
28346
+ payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary, patchEquivalence, submoduleReachability }
28205
28347
  });
28206
28348
  recordMeshRefineStage(refineStages, "ledger", "passed", ledgerStarted);
28207
28349
  } catch (e) {
@@ -28229,6 +28371,7 @@ var DaemonCommandRouter = class {
28229
28371
  removeResult,
28230
28372
  validationSummary,
28231
28373
  patchEquivalence,
28374
+ submoduleReachability,
28232
28375
  mergeResult,
28233
28376
  refineStages,
28234
28377
  ...ledgerError ? { ledgerError } : {},
@@ -28243,6 +28386,7 @@ var DaemonCommandRouter = class {
28243
28386
  removeResult,
28244
28387
  validationSummary,
28245
28388
  patchEquivalence,
28389
+ submoduleReachability,
28246
28390
  mergeResult,
28247
28391
  refineStages,
28248
28392
  ...ledgerError ? { ledgerError } : {},