@adhdev/daemon-core 0.9.82-rc.76 → 0.9.82-rc.78

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
@@ -1133,25 +1133,42 @@ ${userInstruction}`);
1133
1133
  return sections.join("\n\n");
1134
1134
  }
1135
1135
  function buildNodeStatusSection(nodes) {
1136
- const lines = ["## Current Node Status", ""];
1136
+ const lines = [
1137
+ "## Current Node Status",
1138
+ "",
1139
+ "Node labels are display context, not aliases. Use exact `nodeId` values in mesh tool calls; do not invent shorthand names such as M1/M2 unless they are explicitly configured labels.",
1140
+ ""
1141
+ ];
1137
1142
  for (const n of nodes) {
1138
1143
  const healthIcon = n.health === "online" ? "\u{1F7E2}" : n.health === "dirty" ? "\u{1F7E1}" : n.health === "offline" ? "\u26AB" : "\u{1F534}";
1139
1144
  const sessions = n.activeSessions.length > 0 ? `sessions: ${n.activeSessions.join(", ")}` : "no active sessions";
1140
1145
  const branch = n.git?.branch ? `branch: \`${n.git.branch}\`` : "";
1141
- lines.push(`- ${healthIcon} **${n.machineLabel}** (${n.nodeId})`);
1142
- lines.push(` workspace: \`${n.workspace}\` | ${branch} | ${sessions}`);
1146
+ const context = [
1147
+ n.daemonId ? `daemon: \`${n.daemonId}\`` : "",
1148
+ n.providers?.length ? `providers: ${n.providers.join(", ")}` : ""
1149
+ ].filter(Boolean).join(" | ");
1150
+ lines.push(`- ${healthIcon} **${n.machineLabel}** (nodeId: \`${n.nodeId}\`)`);
1151
+ lines.push(` workspace: \`${n.workspace}\`${context ? ` | ${context}` : ""} | ${branch} | ${sessions}`);
1143
1152
  if (n.error) lines.push(` \u26A0\uFE0F ${n.error}`);
1144
1153
  }
1145
1154
  return lines.join("\n");
1146
1155
  }
1147
1156
  function buildNodeConfigSection(mesh) {
1148
- const lines = ["## Configured Nodes", ""];
1157
+ const lines = [
1158
+ "## Configured Nodes",
1159
+ "",
1160
+ "Node labels are display context, not aliases. Use exact `nodeId` values in mesh tool calls; do not invent shorthand names such as M1/M2 unless they are explicitly configured labels.",
1161
+ ""
1162
+ ];
1149
1163
  for (const n of mesh.nodes) {
1150
1164
  const labels = [];
1151
1165
  if (n.isLocalWorktree) labels.push("worktree");
1152
1166
  if (n.policy?.readOnly) labels.push("read-only");
1153
1167
  const suffix = labels.length ? ` [${labels.join(", ")}]` : "";
1154
- lines.push(`- **${n.workspace}** (${n.id})${suffix}`);
1168
+ const explicitMachineLabel = typeof n.machineLabel === "string" ? n.machineLabel : "";
1169
+ const explicitLabel = explicitMachineLabel ? ` label: **${explicitMachineLabel}** |` : "";
1170
+ const providerPriority = n.policy?.providerPriority?.length ? ` | providers: ${n.policy.providerPriority.join(", ")}` : "";
1171
+ lines.push(`- ${explicitLabel} nodeId: \`${n.id}\` | workspace: \`${n.workspace}\`${n.daemonId ? ` | daemon: \`${n.daemonId}\`` : ""}${providerPriority}${suffix}`);
1155
1172
  }
1156
1173
  lines.push("", "_Use `mesh_status` to probe live health before delegating work._");
1157
1174
  return lines.join("\n");
@@ -1192,7 +1209,7 @@ function buildRulesSection(coordinatorCliType) {
1192
1209
  - **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
1193
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.
1194
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.
1195
- - **Treat submodule 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. Do not retry validation blindly or start code review first. Classify it as \`blocked_review\`, request user approval to push/publish the submodule commit, 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\`.
1196
1213
  - **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
1197
1214
  }
1198
1215
  var TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION;
@@ -1239,7 +1256,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
1239
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\`.
1240
1257
  5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
1241
1258
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
1242
- 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 its configured remote. 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), then rerun \`mesh_refine_node\`; do not merge the root branch until the submodule commit(s) are reachable. 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\`, 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.
1243
1260
  8. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
1244
1261
  9. **Report** \u2014 Summarize what was done, what changed, any issues, and the branch convergence state.
1245
1262
 
@@ -3066,8 +3083,20 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
3066
3083
  const result = readRecord(args.metadataEvent.result);
3067
3084
  const code = readNonEmptyString2(result?.code);
3068
3085
  const error = readNonEmptyString2(result?.error);
3069
- const details = [jobId ? `job_id=${jobId}` : "", code ? `code=${code}` : ""].filter(Boolean).join("; ");
3070
- return `[System] Refinery async job for ${args.nodeLabel} failed${details ? ` (${details})` : ""}${error ? `: ${error}` : "."} Review the terminal refine event/ledger before retrying.`;
3086
+ const convergenceStatus = readNonEmptyString2(result?.convergenceStatus);
3087
+ const blockedReason = readNonEmptyString2(result?.blockedReason);
3088
+ const nextStep = readNonEmptyString2(result?.nextStep) || readNonEmptyString2(readRecord(result?.finalBranchConvergenceState)?.nextStep);
3089
+ const details = [
3090
+ jobId ? `job_id=${jobId}` : "",
3091
+ code ? `code=${code}` : "",
3092
+ convergenceStatus ? `convergence=${convergenceStatus}` : "",
3093
+ blockedReason ? `reason=${blockedReason}` : ""
3094
+ ].filter(Boolean).join("; ");
3095
+ const parts = [
3096
+ `[System] Refinery async job for ${args.nodeLabel} failed${details ? ` (${details})` : ""}${error ? `: ${error}` : "."}`,
3097
+ nextStep ? `Next step: ${nextStep}` : "Review the terminal refine event/ledger before retrying."
3098
+ ];
3099
+ return parts.join("\n");
3071
3100
  }
3072
3101
  return "";
3073
3102
  }
@@ -3189,7 +3218,8 @@ function injectMeshSystemMessage(components, args) {
3189
3218
  remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
3190
3219
  }
3191
3220
  if (sessionId) {
3192
- updateSessionTaskStatus(args.meshId, sessionId, "failed");
3221
+ const failedTask = updateSessionTaskStatus(args.meshId, sessionId, "failed");
3222
+ completedTaskForLedger = failedTask ? { id: failedTask.id } : null;
3193
3223
  }
3194
3224
  }
3195
3225
  const ledgerKind = EVENT_TO_LEDGER_KIND[args.event];
@@ -9279,9 +9309,11 @@ function elapsedSince(value, now) {
9279
9309
  return Number.isFinite(started) ? Math.max(0, now - started) : 0;
9280
9310
  }
9281
9311
  function sessionStatusFromNodes(nodes, nodeId, sessionId) {
9282
- if (!nodeId || !sessionId || !Array.isArray(nodes)) return void 0;
9312
+ if (!Array.isArray(nodes)) return {};
9313
+ if (!nodeId) return { staleReason: "direct task has no node id" };
9283
9314
  const node = nodes.find((item) => readString2(item?.id) === nodeId || readString2(item?.nodeId) === nodeId || readString2(item?.node_id) === nodeId);
9284
- if (!node) return void 0;
9315
+ if (!node) return { staleReason: "direct task node is no longer in the live mesh" };
9316
+ if (!sessionId) return {};
9285
9317
  const candidates = [];
9286
9318
  for (const value of [node.sessions, node.activeSessions, node.active_sessions, node.lastProbe?.sessions, node.last_probe?.sessions, node.lastProbe?.status?.sessions, node.last_probe?.status?.sessions]) {
9287
9319
  if (Array.isArray(value)) candidates.push(...value);
@@ -9290,16 +9322,18 @@ function sessionStatusFromNodes(nodes, nodeId, sessionId) {
9290
9322
  if (value && typeof value === "object") candidates.push(value);
9291
9323
  }
9292
9324
  const session = candidates.find((item) => {
9325
+ if (typeof item === "string") return item === sessionId;
9293
9326
  const id = readString2(item?.id) || readString2(item?.sessionId) || readString2(item?.session_id) || readString2(item?.runtimeSessionId) || readString2(item?.instanceId);
9294
9327
  return id === sessionId;
9295
9328
  });
9296
- if (!session) return void 0;
9329
+ if (!session) return { staleReason: "direct task session is not present in live session records" };
9330
+ if (typeof session === "string") return {};
9297
9331
  const raw = `${readString2(session.status) || ""} ${readString2(session.lifecycle) || ""} ${readString2(session.state) || ""} ${readString2(session.activeChat?.status) || ""}`.toLowerCase();
9298
- if (raw.includes("approval")) return "awaiting_approval";
9299
- if (raw.includes("generating") || raw.includes("running") || raw.includes("busy")) return "generating";
9300
- if (raw.includes("failed") || raw.includes("stopped") || raw.includes("terminated") || raw.includes("exited")) return "failed";
9301
- if (raw.includes("idle") || raw.includes("waiting_input") || raw.includes("ready")) return "idle";
9302
- return void 0;
9332
+ if (raw.includes("approval")) return { status: "awaiting_approval" };
9333
+ if (raw.includes("generating") || raw.includes("running") || raw.includes("busy")) return { status: "generating" };
9334
+ if (raw.includes("failed") || raw.includes("stopped") || raw.includes("terminated") || raw.includes("exited")) return { status: "failed" };
9335
+ if (raw.includes("idle") || raw.includes("waiting_input") || raw.includes("ready")) return { status: "idle" };
9336
+ return {};
9303
9337
  }
9304
9338
  function isDirectDispatch(entry) {
9305
9339
  if (entry.kind !== "task_dispatched") return false;
@@ -9346,15 +9380,17 @@ function buildMeshActiveWorkSummary(activeWork) {
9346
9380
  failedCount: statusCounts.failed,
9347
9381
  idleCount: statusCounts.idle,
9348
9382
  sourceCounts,
9349
- statusCounts
9383
+ statusCounts,
9384
+ staleDirectCount: activeWork.filter((item) => item.source === "direct" && item.staleReason).length
9350
9385
  };
9351
9386
  }
9352
9387
  function buildMeshActiveWork(opts) {
9353
9388
  const now = opts.now ?? Date.now();
9354
9389
  const records = [];
9390
+ const staleDirectWork = [];
9355
9391
  for (const task of opts.queue || []) {
9356
9392
  if (task.status !== "pending" && task.status !== "assigned") continue;
9357
- const { title, summary } = summarizeMessage(task.message || "");
9393
+ const { title, summary: summary2 } = summarizeMessage(task.message || "");
9358
9394
  records.push({
9359
9395
  taskId: task.id,
9360
9396
  source: "queue",
@@ -9362,7 +9398,7 @@ function buildMeshActiveWork(opts) {
9362
9398
  nodeId: task.assignedNodeId || task.targetNodeId,
9363
9399
  sessionId: task.assignedSessionId || task.targetSessionId,
9364
9400
  taskTitle: title,
9365
- taskSummary: summary,
9401
+ taskSummary: summary2,
9366
9402
  message: task.message,
9367
9403
  taskMode: task.taskMode,
9368
9404
  createdAt: task.createdAt,
@@ -9377,13 +9413,13 @@ function buildMeshActiveWork(opts) {
9377
9413
  const taskId = directDispatchTaskId(dispatch);
9378
9414
  const terminal = terminals.filter((entry) => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime()).find((entry) => terminalMatchesDispatch(entry, dispatch, taskId));
9379
9415
  const terminalStatus = terminal ? statusFromTerminal(terminal) : void 0;
9380
- const liveStatus = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
9381
- const status = terminalStatus || liveStatus || "assigned";
9416
+ const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
9417
+ const status = terminalStatus || live.status || "assigned";
9382
9418
  const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
9383
9419
  if (terminalRow && opts.includeTerminalDirect !== true) continue;
9384
9420
  const message = readString2(dispatch.payload?.message) || readString2(dispatch.payload?.summary) || "";
9385
- const { title, summary } = summarizeMessage(message);
9386
- records.push({
9421
+ const { title, summary: summary2 } = summarizeMessage(message);
9422
+ const record = {
9387
9423
  taskId,
9388
9424
  source: "direct",
9389
9425
  status,
@@ -9391,7 +9427,7 @@ function buildMeshActiveWork(opts) {
9391
9427
  sessionId: dispatch.sessionId,
9392
9428
  providerType: dispatch.providerType || readString2(dispatch.payload?.providerType),
9393
9429
  taskTitle: readString2(dispatch.payload?.taskTitle) || title,
9394
- taskSummary: readString2(dispatch.payload?.taskSummary) || summary,
9430
+ taskSummary: readString2(dispatch.payload?.taskSummary) || summary2,
9395
9431
  message,
9396
9432
  taskMode: readString2(dispatch.payload?.taskMode),
9397
9433
  createdAt: dispatch.timestamp,
@@ -9400,11 +9436,20 @@ function buildMeshActiveWork(opts) {
9400
9436
  elapsedMs: elapsedSince(dispatch.timestamp, now),
9401
9437
  terminal: terminalRow,
9402
9438
  terminalKind: terminal?.kind,
9403
- terminalAt: terminal?.timestamp
9404
- });
9439
+ terminalAt: terminal?.timestamp,
9440
+ staleReason: live.staleReason
9441
+ };
9442
+ if (live.staleReason && !terminalRow) {
9443
+ staleDirectWork.push(record);
9444
+ continue;
9445
+ }
9446
+ records.push(record);
9405
9447
  }
9406
9448
  records.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
9407
- return { activeWork: records, summary: buildMeshActiveWorkSummary(records) };
9449
+ staleDirectWork.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
9450
+ const summary = buildMeshActiveWorkSummary(records);
9451
+ summary.staleDirectCount = staleDirectWork.length;
9452
+ return { activeWork: records, staleDirectWork, summary };
9408
9453
  }
9409
9454
 
9410
9455
  // src/index.ts
@@ -19691,23 +19736,28 @@ var CliProviderInstance = class {
19691
19736
  if (hasNonEmptyCliModalButtons(parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
19692
19737
  return !this.hasAdapterPendingResponse();
19693
19738
  }
19694
- getCompletedFinalizationBlockReason(latestVisibleStatus) {
19695
- if (latestVisibleStatus !== "idle") return `status:${latestVisibleStatus}`;
19739
+ getCompletedFinalizationBlock(latestVisibleStatus) {
19740
+ if (latestVisibleStatus !== "idle") return { reason: `status:${latestVisibleStatus}`, terminal: true };
19696
19741
  const adapterAny = this.adapter;
19697
- if (adapterAny?.isWaitingForResponse === true) return "adapter_waiting_for_response";
19698
- if (adapterAny?.currentTurnScope) return "adapter_turn_scope_active";
19742
+ if (adapterAny?.isWaitingForResponse === true) return { reason: "adapter_waiting_for_response", terminal: true };
19743
+ if (adapterAny?.currentTurnScope) return { reason: "adapter_turn_scope_active", terminal: true };
19744
+ if (this.hasAdapterPendingResponse()) return { reason: "adapter_pending_response", terminal: true };
19699
19745
  const partial = typeof this.adapter.getPartialResponse === "function" ? this.adapter.getPartialResponse() : "";
19700
- if (typeof partial === "string" && partial.trim()) return "partial_response_pending";
19746
+ if (typeof partial === "string" && partial.trim()) return { reason: "partial_response_pending", terminal: true };
19701
19747
  let parsed;
19702
19748
  try {
19703
19749
  parsed = this.adapter.getScriptParsedStatus();
19704
19750
  } catch (error) {
19705
- return `parse_error:${error?.message || String(error)}`;
19751
+ return { reason: `parse_error:${error?.message || String(error)}` };
19706
19752
  }
19707
19753
  const parsedStatus = typeof parsed?.status === "string" ? parsed.status : "unknown";
19708
- if (parsedStatus !== "idle") return `parsed_status:${parsedStatus}`;
19709
- if (parsed?.activeModal || parsed?.modal) return "parsed_modal_active";
19710
- if (!this.completionHasFinalAssistantMessage(parsed?.messages)) return "missing_final_assistant";
19754
+ if (parsedStatus !== "idle") {
19755
+ const adapterStatus = this.adapter.getStatus({ allowParse: false });
19756
+ if (this.shouldSuppressStaleParsedBusyStatus(parsed, adapterStatus)) return null;
19757
+ return { reason: `parsed_status:${parsedStatus}`, terminal: isCliGeneratingLikeStatus(parsedStatus) };
19758
+ }
19759
+ if (parsed?.activeModal || parsed?.modal) return { reason: "parsed_modal_active", terminal: true };
19760
+ if (!this.completionHasFinalAssistantMessage(parsed?.messages)) return { reason: "missing_final_assistant" };
19711
19761
  return null;
19712
19762
  }
19713
19763
  scheduleCompletedDebounceFlush(delayMs) {
@@ -19729,10 +19779,11 @@ var CliProviderInstance = class {
19729
19779
  this.completedDebounceTimer = null;
19730
19780
  return;
19731
19781
  }
19732
- const blockReason = this.getCompletedFinalizationBlockReason(latestVisibleStatus);
19733
- if (blockReason) {
19782
+ const block2 = this.getCompletedFinalizationBlock(latestVisibleStatus);
19783
+ if (block2) {
19784
+ const blockReason = block2.reason;
19734
19785
  const waitedMs = Date.now() - pending.firstObservedAt;
19735
- if (waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS) {
19786
+ if (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS) {
19736
19787
  if (pending.loggedBlockReason !== blockReason) {
19737
19788
  LOG.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
19738
19789
  pending.loggedBlockReason = blockReason;
@@ -21596,6 +21647,47 @@ var BUSY_AGENT_STATUSES = /* @__PURE__ */ new Set(["generating", "running", "str
21596
21647
  function normalizeAgentStatus(value) {
21597
21648
  return typeof value === "string" ? value.trim().toLowerCase() : "";
21598
21649
  }
21650
+ function hasNonEmptyModalButtons2(activeModal) {
21651
+ const buttons = activeModal?.buttons;
21652
+ return Array.isArray(buttons) && buttons.some((button) => String(button || "").trim().length > 0);
21653
+ }
21654
+ function hasAdapterPendingResponse(adapter) {
21655
+ if (adapter?.isWaitingForResponse === true) return true;
21656
+ if (adapter?.currentTurnScope) return true;
21657
+ try {
21658
+ if (typeof adapter?.isProcessing === "function" && adapter.isProcessing()) return true;
21659
+ } catch {
21660
+ }
21661
+ try {
21662
+ const partial = typeof adapter?.getPartialResponse === "function" ? adapter.getPartialResponse() : "";
21663
+ if (typeof partial === "string" && partial.trim()) return true;
21664
+ } catch {
21665
+ }
21666
+ return false;
21667
+ }
21668
+ function shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapter) {
21669
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
21670
+ if (!BUSY_AGENT_STATUSES.has(parsedRawStatus)) return false;
21671
+ if (adapterStatus !== "idle") return false;
21672
+ if (hasNonEmptyModalButtons2(parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
21673
+ return !hasAdapterPendingResponse(adapter);
21674
+ }
21675
+ function getEffectiveAgentSendStatus(adapter) {
21676
+ const adapterStatus = normalizeAgentStatus(adapter?.getStatus?.({ allowParse: false })?.status ?? adapter?.getStatus?.()?.status);
21677
+ if (adapterStatus && adapterStatus !== "idle") return adapterStatus;
21678
+ if (adapterStatus !== "idle") return adapterStatus;
21679
+ if (typeof adapter?.getScriptParsedStatus !== "function") return adapterStatus;
21680
+ try {
21681
+ const parsedStatus = adapter.getScriptParsedStatus();
21682
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
21683
+ if (BUSY_AGENT_STATUSES.has(parsedRawStatus) && !shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapter)) {
21684
+ return parsedRawStatus;
21685
+ }
21686
+ } catch {
21687
+ return adapterStatus;
21688
+ }
21689
+ return adapterStatus;
21690
+ }
21599
21691
  var chalkModule = import_chalk.default;
21600
21692
  var chalkApi = typeof chalkModule.yellow === "function" ? chalkModule : chalkModule.default || null;
21601
21693
  function colorize(color, text) {
@@ -22370,7 +22462,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
22370
22462
  if (!found) throw new Error(`CLI agent not running: ${agentType}`);
22371
22463
  const { adapter, key } = found;
22372
22464
  if (action === "send_chat") {
22373
- const currentStatus = normalizeAgentStatus(adapter.getStatus?.()?.status);
22465
+ const currentStatus = getEffectiveAgentSendStatus(adapter);
22374
22466
  if (BUSY_AGENT_STATUSES.has(currentStatus)) {
22375
22467
  return {
22376
22468
  success: false,
@@ -25859,6 +25951,17 @@ function readGitSubmodules(value, parentRepoRoot) {
25859
25951
  }).filter((entry) => entry !== null);
25860
25952
  return submodules.length > 0 ? submodules : void 0;
25861
25953
  }
25954
+ function buildMeshNodeDisplayLabel(node, nodeId, providerPriority) {
25955
+ const explicit = readStringValue(node.machineLabel, node.machine_label, node.machineNickname, node.machine_nickname, node.alias);
25956
+ if (explicit) return explicit;
25957
+ const workspace = readStringValue(node.workspace, node.repoRoot, node.repo_root);
25958
+ const workspaceName = workspace ? (0, import_path8.basename)(workspace) : void 0;
25959
+ const host = readStringValue(node.hostname, node.host, node.daemonId, node.daemon_id, node.machineId, node.machine_id);
25960
+ const provider = providerPriority[0] || (Array.isArray(node.providers) ? readStringValue(...node.providers) : void 0);
25961
+ const parts = [workspaceName, host, provider].filter(Boolean);
25962
+ if (parts.length > 0) return parts.join(" \xB7 ");
25963
+ return nodeId || "unidentified mesh node";
25964
+ }
25862
25965
  function normalizeInlineMeshGitStatus(status, node, options) {
25863
25966
  const isGitRepo = readBooleanValue(status.isGitRepo);
25864
25967
  if (!Object.keys(status).length || isGitRepo === void 0) return void 0;
@@ -26529,7 +26632,7 @@ function recordMeshRefineStage(stages, stage, status, startedAt, details) {
26529
26632
  }
26530
26633
  function buildSubmodulePublishRequiredNextStep(entries) {
26531
26634
  const refs = entries.map((entry) => `${entry.path}@${entry.commit}`).join(", ");
26532
- return `Ask the user for explicit approval to push/publish the unreachable submodule commit(s) (${refs}) to their configured submodule remote(s), then rerun mesh_refine_node. Do not merge the root branch until every submodule gitlink commit is reachable from its configured remote.`;
26635
+ 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.`;
26533
26636
  }
26534
26637
  async function computeGitPatchId(cwd, fromRef, toRef) {
26535
26638
  const { execFileSync: execFileSync3 } = await import("child_process");
@@ -26616,12 +26719,13 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26616
26719
  });
26617
26720
  return String(stdout || "");
26618
26721
  };
26619
- const verifyRemoteCommitReachable = async (remoteUrl, commit) => {
26722
+ const verifyRemoteMainContainsCommit = async (remoteUrl, commit, branch = "main") => {
26620
26723
  const probeDir = fs11.mkdtempSync((0, import_path8.join)((0, import_os3.tmpdir)(), "adhdev-submodule-reachability-"));
26621
26724
  try {
26622
26725
  await runGit2(probeDir, ["init", "-q"]);
26623
- await runGit2(probeDir, ["-c", "protocol.file.allow=always", "fetch", "--depth=1", remoteUrl, commit]);
26726
+ await runGit2(probeDir, ["-c", "protocol.file.allow=always", "fetch", "--depth=1", remoteUrl, `refs/heads/${branch}:refs/remotes/origin/${branch}`]);
26624
26727
  await runGit2(probeDir, ["cat-file", "-e", `${commit}^{commit}`]);
26728
+ await runGit2(probeDir, ["merge-base", "--is-ancestor", commit, `refs/remotes/origin/${branch}`]);
26625
26729
  } finally {
26626
26730
  fs11.rmSync(probeDir, { recursive: true, force: true });
26627
26731
  }
@@ -26665,15 +26769,18 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
26665
26769
  entries.push(entry);
26666
26770
  continue;
26667
26771
  }
26668
- await verifyRemoteCommitReachable(remoteUrl, gitlink.commit);
26772
+ entry.remoteMainBranch = "main";
26773
+ await verifyRemoteMainContainsCommit(remoteUrl, gitlink.commit, "main");
26669
26774
  entry.fetchedFromOrigin = true;
26670
26775
  entry.remoteReachable = true;
26776
+ entry.remoteMainReachable = true;
26671
26777
  entry.reachable = true;
26672
26778
  } catch (e) {
26673
26779
  entry.remoteReachable = false;
26780
+ entry.remoteMainReachable = false;
26674
26781
  entry.publishRequired = true;
26675
26782
  const details = truncateValidationOutput(e?.stderr || e?.message || String(e));
26676
- entry.error = `Submodule remote reachability check failed for origin: ${details}`;
26783
+ entry.error = `Submodule remote main reachability check failed for origin/main: ${details}`;
26677
26784
  }
26678
26785
  } catch (e) {
26679
26786
  entry.error = truncateValidationOutput(e?.message || String(e));
@@ -27821,6 +27928,8 @@ var DaemonCommandRouter = class {
27821
27928
  remote: entry.remote,
27822
27929
  remoteUrl: entry.remoteUrl,
27823
27930
  remoteReachable: entry.remoteReachable,
27931
+ remoteMainBranch: entry.remoteMainBranch,
27932
+ remoteMainReachable: entry.remoteMainReachable,
27824
27933
  error: entry.error
27825
27934
  })),
27826
27935
  error: submoduleReachability.error
@@ -27833,13 +27942,13 @@ var DaemonCommandRouter = class {
27833
27942
  convergenceStatus: "blocked_review",
27834
27943
  publishRequired: true,
27835
27944
  blockedReason: "submodule_publish_required",
27836
- error: "Refinery submodule reachability preflight failed because one or more submodule gitlink commits are not reachable from their configured remote; merge/refine cleanup was not attempted.",
27945
+ error: "Refinery submodule reachability preflight failed because one or more submodule gitlink commits are not reachable from their configured remote main branch; merge/refine cleanup was not attempted.",
27837
27946
  nextStep,
27838
27947
  nextSteps: [
27839
27948
  "Ask the user for explicit approval before pushing or publishing any submodule commit.",
27840
- "Push/publish each unreachable submodule commit to the configured submodule remote shown in the evidence.",
27949
+ "Push/publish each unreachable submodule commit to the configured submodule remote main branch shown in the evidence.",
27841
27950
  "Rerun mesh_refine_node after remote reachability is confirmed.",
27842
- "Do not merge the root branch until every submodule gitlink commit is reachable from its configured remote."
27951
+ "Do not merge the root branch until every submodule gitlink commit is reachable from submodule origin/main."
27843
27952
  ],
27844
27953
  unreachableSubmoduleCommits: submoduleReachability.unreachable.map((entry) => ({
27845
27954
  path: entry.path,
@@ -27847,6 +27956,8 @@ var DaemonCommandRouter = class {
27847
27956
  remote: entry.remote,
27848
27957
  remoteUrl: entry.remoteUrl,
27849
27958
  remoteReachable: entry.remoteReachable,
27959
+ remoteMainBranch: entry.remoteMainBranch,
27960
+ remoteMainReachable: entry.remoteMainReachable,
27850
27961
  error: entry.error
27851
27962
  })),
27852
27963
  branch,
@@ -29721,7 +29832,8 @@ ${block2}`);
29721
29832
  ) || Boolean(meshRecord?.inline && nodeIndex === 0);
29722
29833
  const status = {
29723
29834
  nodeId,
29724
- machineLabel: node.machineLabel || node.id || node.nodeId,
29835
+ machineLabel: buildMeshNodeDisplayLabel(node, nodeId, providerPriority),
29836
+ labelSource: readStringValue(node.machineLabel, node.machine_label, node.machineNickname, node.machine_nickname, node.alias) ? "explicit_metadata" : "workspace_host_provider_context",
29725
29837
  workspace: node.workspace,
29726
29838
  repoRoot: node.repoRoot,
29727
29839
  isLocalWorktree: node.isLocalWorktree,