@adhdev/daemon-core 0.9.82-rc.77 → 0.9.82-rc.79
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 +231 -83
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +233 -85
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-active-work.d.ts +3 -0
- package/dist/mesh/mesh-events.d.ts +1 -0
- package/dist/providers/cli-provider-instance.d.ts +1 -1
- package/package.json +1 -1
- package/src/commands/cli-manager.ts +45 -1
- package/src/commands/router.ts +75 -34
- package/src/mesh/coordinator-prompt.ts +24 -7
- package/src/mesh/mesh-active-work.ts +32 -15
- package/src/mesh/mesh-events.ts +54 -12
- package/src/providers/cli-provider-instance.ts +23 -12
package/dist/index.mjs
CHANGED
|
@@ -1128,25 +1128,42 @@ ${userInstruction}`);
|
|
|
1128
1128
|
return sections.join("\n\n");
|
|
1129
1129
|
}
|
|
1130
1130
|
function buildNodeStatusSection(nodes) {
|
|
1131
|
-
const lines = [
|
|
1131
|
+
const lines = [
|
|
1132
|
+
"## Current Node Status",
|
|
1133
|
+
"",
|
|
1134
|
+
"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.",
|
|
1135
|
+
""
|
|
1136
|
+
];
|
|
1132
1137
|
for (const n of nodes) {
|
|
1133
1138
|
const healthIcon = n.health === "online" ? "\u{1F7E2}" : n.health === "dirty" ? "\u{1F7E1}" : n.health === "offline" ? "\u26AB" : "\u{1F534}";
|
|
1134
1139
|
const sessions = n.activeSessions.length > 0 ? `sessions: ${n.activeSessions.join(", ")}` : "no active sessions";
|
|
1135
1140
|
const branch = n.git?.branch ? `branch: \`${n.git.branch}\`` : "";
|
|
1136
|
-
|
|
1137
|
-
|
|
1141
|
+
const context = [
|
|
1142
|
+
n.daemonId ? `daemon: \`${n.daemonId}\`` : "",
|
|
1143
|
+
n.providers?.length ? `providers: ${n.providers.join(", ")}` : ""
|
|
1144
|
+
].filter(Boolean).join(" | ");
|
|
1145
|
+
lines.push(`- ${healthIcon} **${n.machineLabel}** (nodeId: \`${n.nodeId}\`)`);
|
|
1146
|
+
lines.push(` workspace: \`${n.workspace}\`${context ? ` | ${context}` : ""} | ${branch} | ${sessions}`);
|
|
1138
1147
|
if (n.error) lines.push(` \u26A0\uFE0F ${n.error}`);
|
|
1139
1148
|
}
|
|
1140
1149
|
return lines.join("\n");
|
|
1141
1150
|
}
|
|
1142
1151
|
function buildNodeConfigSection(mesh) {
|
|
1143
|
-
const lines = [
|
|
1152
|
+
const lines = [
|
|
1153
|
+
"## Configured Nodes",
|
|
1154
|
+
"",
|
|
1155
|
+
"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.",
|
|
1156
|
+
""
|
|
1157
|
+
];
|
|
1144
1158
|
for (const n of mesh.nodes) {
|
|
1145
1159
|
const labels = [];
|
|
1146
1160
|
if (n.isLocalWorktree) labels.push("worktree");
|
|
1147
1161
|
if (n.policy?.readOnly) labels.push("read-only");
|
|
1148
1162
|
const suffix = labels.length ? ` [${labels.join(", ")}]` : "";
|
|
1149
|
-
|
|
1163
|
+
const explicitMachineLabel = typeof n.machineLabel === "string" ? n.machineLabel : "";
|
|
1164
|
+
const explicitLabel = explicitMachineLabel ? ` label: **${explicitMachineLabel}** |` : "";
|
|
1165
|
+
const providerPriority = n.policy?.providerPriority?.length ? ` | providers: ${n.policy.providerPriority.join(", ")}` : "";
|
|
1166
|
+
lines.push(`- ${explicitLabel} nodeId: \`${n.id}\` | workspace: \`${n.workspace}\`${n.daemonId ? ` | daemon: \`${n.daemonId}\`` : ""}${providerPriority}${suffix}`);
|
|
1150
1167
|
}
|
|
1151
1168
|
lines.push("", "_Use `mesh_status` to probe live health before delegating work._");
|
|
1152
1169
|
return lines.join("\n");
|
|
@@ -1187,7 +1204,7 @@ function buildRulesSection(coordinatorCliType) {
|
|
|
1187
1204
|
- **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
|
|
1188
1205
|
- **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.
|
|
1189
1206
|
- **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.
|
|
1190
|
-
- **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\`.
|
|
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\`.
|
|
1191
1208
|
- **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
|
|
1192
1209
|
}
|
|
1193
1210
|
var TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION;
|
|
@@ -1234,7 +1251,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
|
|
|
1234
1251
|
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\`.
|
|
1235
1252
|
5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
|
|
1236
1253
|
6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
|
|
1237
|
-
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
|
|
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.
|
|
1238
1255
|
8. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
|
|
1239
1256
|
9. **Report** \u2014 Summarize what was done, what changed, any issues, and the branch convergence state.
|
|
1240
1257
|
|
|
@@ -3046,23 +3063,54 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
|
|
|
3046
3063
|
const jobId = readRefineJobId({ metadataEvent: args.metadataEvent });
|
|
3047
3064
|
const result = readRecord(args.metadataEvent.result);
|
|
3048
3065
|
const validationSummary = readRecord(result?.validationSummary);
|
|
3066
|
+
const patchEquivalence = readRecord(result?.patchEquivalence);
|
|
3067
|
+
const finalConvergence = readRecord(result?.finalBranchConvergenceState);
|
|
3049
3068
|
const validationStatus = readNonEmptyString2(validationSummary?.status);
|
|
3069
|
+
const patchStatus = readNonEmptyString2(patchEquivalence?.status) || (patchEquivalence?.equivalent === true ? "passed" : "");
|
|
3050
3070
|
const into = readNonEmptyString2(result?.into);
|
|
3051
3071
|
const branch = readNonEmptyString2(result?.branch);
|
|
3072
|
+
const mergeStatus = result?.merged === true ? "merged" : readNonEmptyString2(finalConvergence?.status);
|
|
3073
|
+
const convergenceStatus = readNonEmptyString2(finalConvergence?.status);
|
|
3074
|
+
const nextStep = readNonEmptyString2(result?.nextStep) || readNonEmptyString2(finalConvergence?.nextStep) || "Continue from the updated mesh state.";
|
|
3052
3075
|
const details = [
|
|
3053
3076
|
jobId ? `job_id=${jobId}` : "",
|
|
3054
3077
|
branch && into ? `${branch}\u2192${into}` : "",
|
|
3055
|
-
validationStatus ? `validation=${validationStatus}` : ""
|
|
3078
|
+
validationStatus ? `validation=${validationStatus}` : "",
|
|
3079
|
+
patchStatus ? `patch_equivalence=${patchStatus}` : "",
|
|
3080
|
+
mergeStatus ? `merge=${mergeStatus}` : "",
|
|
3081
|
+
convergenceStatus ? `final_convergence=${convergenceStatus}` : ""
|
|
3056
3082
|
].filter(Boolean).join("; ");
|
|
3057
|
-
return `[System] Refinery async job for ${args.nodeLabel} completed successfully${details ? ` (${details})` : ""}.
|
|
3083
|
+
return `[System] Refinery async job for ${args.nodeLabel} completed successfully${details ? ` (${details})` : ""}.
|
|
3084
|
+
Next step: ${nextStep}`;
|
|
3058
3085
|
}
|
|
3059
3086
|
if (args.event === "refine:failed") {
|
|
3060
3087
|
const jobId = readRefineJobId({ metadataEvent: args.metadataEvent });
|
|
3061
3088
|
const result = readRecord(args.metadataEvent.result);
|
|
3089
|
+
const validationSummary = readRecord(result?.validationSummary);
|
|
3090
|
+
const patchEquivalence = readRecord(result?.patchEquivalence);
|
|
3091
|
+
const finalConvergence = readRecord(result?.finalBranchConvergenceState);
|
|
3062
3092
|
const code = readNonEmptyString2(result?.code);
|
|
3063
3093
|
const error = readNonEmptyString2(result?.error);
|
|
3064
|
-
const
|
|
3065
|
-
|
|
3094
|
+
const validationStatus = readNonEmptyString2(validationSummary?.status);
|
|
3095
|
+
const patchStatus = readNonEmptyString2(patchEquivalence?.status) || (patchEquivalence?.equivalent === true ? "passed" : "");
|
|
3096
|
+
const mergeStatus = result?.merged === true ? "merged" : finalConvergence?.merged === false ? "not_merged" : "";
|
|
3097
|
+
const convergenceStatus = readNonEmptyString2(result?.convergenceStatus) || readNonEmptyString2(finalConvergence?.status);
|
|
3098
|
+
const blockedReason = readNonEmptyString2(result?.blockedReason);
|
|
3099
|
+
const nextStep = readNonEmptyString2(result?.nextStep) || readNonEmptyString2(finalConvergence?.nextStep);
|
|
3100
|
+
const details = [
|
|
3101
|
+
jobId ? `job_id=${jobId}` : "",
|
|
3102
|
+
code ? `code=${code}` : "",
|
|
3103
|
+
validationStatus ? `validation=${validationStatus}` : "",
|
|
3104
|
+
patchStatus ? `patch_equivalence=${patchStatus}` : "",
|
|
3105
|
+
mergeStatus ? `merge=${mergeStatus}` : "",
|
|
3106
|
+
convergenceStatus ? `convergence=${convergenceStatus}` : "",
|
|
3107
|
+
blockedReason ? `reason=${blockedReason}` : ""
|
|
3108
|
+
].filter(Boolean).join("; ");
|
|
3109
|
+
const parts = [
|
|
3110
|
+
`[System] Refinery async job for ${args.nodeLabel} failed${details ? ` (${details})` : ""}${error ? `: ${error}` : "."}`,
|
|
3111
|
+
nextStep ? `Next step: ${nextStep}` : "Review the terminal refine event/ledger before retrying."
|
|
3112
|
+
];
|
|
3113
|
+
return parts.join("\n");
|
|
3066
3114
|
}
|
|
3067
3115
|
return "";
|
|
3068
3116
|
}
|
|
@@ -3184,7 +3232,8 @@ function injectMeshSystemMessage(components, args) {
|
|
|
3184
3232
|
remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
|
|
3185
3233
|
}
|
|
3186
3234
|
if (sessionId) {
|
|
3187
|
-
updateSessionTaskStatus(args.meshId, sessionId, "failed");
|
|
3235
|
+
const failedTask = updateSessionTaskStatus(args.meshId, sessionId, "failed");
|
|
3236
|
+
completedTaskForLedger = failedTask ? { id: failedTask.id } : null;
|
|
3188
3237
|
}
|
|
3189
3238
|
}
|
|
3190
3239
|
const ledgerKind = EVENT_TO_LEDGER_KIND[args.event];
|
|
@@ -3279,6 +3328,13 @@ function injectMeshSystemMessage(components, args) {
|
|
|
3279
3328
|
LOG.warn("MeshRecovery", `Failed to build recovery context: ${e?.message || e}`);
|
|
3280
3329
|
}
|
|
3281
3330
|
}
|
|
3331
|
+
const messageText = buildMeshSystemMessage({
|
|
3332
|
+
event: args.event,
|
|
3333
|
+
nodeLabel: args.nodeLabel,
|
|
3334
|
+
metadataEvent: args.metadataEvent,
|
|
3335
|
+
recoveryContext
|
|
3336
|
+
});
|
|
3337
|
+
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
3282
3338
|
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
3283
3339
|
const instState = inst.getState();
|
|
3284
3340
|
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
@@ -3296,19 +3352,13 @@ function injectMeshSystemMessage(components, args) {
|
|
|
3296
3352
|
...args.metadataEvent,
|
|
3297
3353
|
...recoveryContext ? { recoveryContext } : {}
|
|
3298
3354
|
},
|
|
3355
|
+
coordinatorMessage: messageText,
|
|
3299
3356
|
queuedAt: Date.now()
|
|
3300
3357
|
})) {
|
|
3301
3358
|
LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
|
|
3302
3359
|
}
|
|
3303
3360
|
return { success: true, forwarded: 0 };
|
|
3304
3361
|
}
|
|
3305
|
-
const messageText = buildMeshSystemMessage({
|
|
3306
|
-
event: args.event,
|
|
3307
|
-
nodeLabel: args.nodeLabel,
|
|
3308
|
-
metadataEvent: args.metadataEvent,
|
|
3309
|
-
recoveryContext
|
|
3310
|
-
});
|
|
3311
|
-
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
3312
3362
|
for (const coord of coordinatorInstances) {
|
|
3313
3363
|
const coordState = coord.getState();
|
|
3314
3364
|
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
@@ -9020,9 +9070,11 @@ function elapsedSince(value, now) {
|
|
|
9020
9070
|
return Number.isFinite(started) ? Math.max(0, now - started) : 0;
|
|
9021
9071
|
}
|
|
9022
9072
|
function sessionStatusFromNodes(nodes, nodeId, sessionId) {
|
|
9023
|
-
if (!
|
|
9073
|
+
if (!Array.isArray(nodes)) return {};
|
|
9074
|
+
if (!nodeId) return { staleReason: "direct task has no node id" };
|
|
9024
9075
|
const node = nodes.find((item) => readString2(item?.id) === nodeId || readString2(item?.nodeId) === nodeId || readString2(item?.node_id) === nodeId);
|
|
9025
|
-
if (!node) return
|
|
9076
|
+
if (!node) return { staleReason: "direct task node is no longer in the live mesh" };
|
|
9077
|
+
if (!sessionId) return {};
|
|
9026
9078
|
const candidates = [];
|
|
9027
9079
|
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]) {
|
|
9028
9080
|
if (Array.isArray(value)) candidates.push(...value);
|
|
@@ -9031,16 +9083,18 @@ function sessionStatusFromNodes(nodes, nodeId, sessionId) {
|
|
|
9031
9083
|
if (value && typeof value === "object") candidates.push(value);
|
|
9032
9084
|
}
|
|
9033
9085
|
const session = candidates.find((item) => {
|
|
9086
|
+
if (typeof item === "string") return item === sessionId;
|
|
9034
9087
|
const id = readString2(item?.id) || readString2(item?.sessionId) || readString2(item?.session_id) || readString2(item?.runtimeSessionId) || readString2(item?.instanceId);
|
|
9035
9088
|
return id === sessionId;
|
|
9036
9089
|
});
|
|
9037
|
-
if (!session) return
|
|
9090
|
+
if (!session) return { staleReason: "direct task session is not present in live session records" };
|
|
9091
|
+
if (typeof session === "string") return {};
|
|
9038
9092
|
const raw = `${readString2(session.status) || ""} ${readString2(session.lifecycle) || ""} ${readString2(session.state) || ""} ${readString2(session.activeChat?.status) || ""}`.toLowerCase();
|
|
9039
|
-
if (raw.includes("approval")) return "awaiting_approval";
|
|
9040
|
-
if (raw.includes("generating") || raw.includes("running") || raw.includes("busy")) return "generating";
|
|
9041
|
-
if (raw.includes("failed") || raw.includes("stopped") || raw.includes("terminated") || raw.includes("exited")) return "failed";
|
|
9042
|
-
if (raw.includes("idle") || raw.includes("waiting_input") || raw.includes("ready")) return "idle";
|
|
9043
|
-
return
|
|
9093
|
+
if (raw.includes("approval")) return { status: "awaiting_approval" };
|
|
9094
|
+
if (raw.includes("generating") || raw.includes("running") || raw.includes("busy")) return { status: "generating" };
|
|
9095
|
+
if (raw.includes("failed") || raw.includes("stopped") || raw.includes("terminated") || raw.includes("exited")) return { status: "failed" };
|
|
9096
|
+
if (raw.includes("idle") || raw.includes("waiting_input") || raw.includes("ready")) return { status: "idle" };
|
|
9097
|
+
return {};
|
|
9044
9098
|
}
|
|
9045
9099
|
function isDirectDispatch(entry) {
|
|
9046
9100
|
if (entry.kind !== "task_dispatched") return false;
|
|
@@ -9087,15 +9141,17 @@ function buildMeshActiveWorkSummary(activeWork) {
|
|
|
9087
9141
|
failedCount: statusCounts.failed,
|
|
9088
9142
|
idleCount: statusCounts.idle,
|
|
9089
9143
|
sourceCounts,
|
|
9090
|
-
statusCounts
|
|
9144
|
+
statusCounts,
|
|
9145
|
+
staleDirectCount: activeWork.filter((item) => item.source === "direct" && item.staleReason).length
|
|
9091
9146
|
};
|
|
9092
9147
|
}
|
|
9093
9148
|
function buildMeshActiveWork(opts) {
|
|
9094
9149
|
const now = opts.now ?? Date.now();
|
|
9095
9150
|
const records = [];
|
|
9151
|
+
const staleDirectWork = [];
|
|
9096
9152
|
for (const task of opts.queue || []) {
|
|
9097
9153
|
if (task.status !== "pending" && task.status !== "assigned") continue;
|
|
9098
|
-
const { title, summary } = summarizeMessage(task.message || "");
|
|
9154
|
+
const { title, summary: summary2 } = summarizeMessage(task.message || "");
|
|
9099
9155
|
records.push({
|
|
9100
9156
|
taskId: task.id,
|
|
9101
9157
|
source: "queue",
|
|
@@ -9103,7 +9159,7 @@ function buildMeshActiveWork(opts) {
|
|
|
9103
9159
|
nodeId: task.assignedNodeId || task.targetNodeId,
|
|
9104
9160
|
sessionId: task.assignedSessionId || task.targetSessionId,
|
|
9105
9161
|
taskTitle: title,
|
|
9106
|
-
taskSummary:
|
|
9162
|
+
taskSummary: summary2,
|
|
9107
9163
|
message: task.message,
|
|
9108
9164
|
taskMode: task.taskMode,
|
|
9109
9165
|
createdAt: task.createdAt,
|
|
@@ -9118,13 +9174,13 @@ function buildMeshActiveWork(opts) {
|
|
|
9118
9174
|
const taskId = directDispatchTaskId(dispatch);
|
|
9119
9175
|
const terminal = terminals.filter((entry) => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime()).find((entry) => terminalMatchesDispatch(entry, dispatch, taskId));
|
|
9120
9176
|
const terminalStatus = terminal ? statusFromTerminal(terminal) : void 0;
|
|
9121
|
-
const
|
|
9122
|
-
const status = terminalStatus ||
|
|
9177
|
+
const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
|
|
9178
|
+
const status = terminalStatus || live.status || "assigned";
|
|
9123
9179
|
const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
|
|
9124
9180
|
if (terminalRow && opts.includeTerminalDirect !== true) continue;
|
|
9125
9181
|
const message = readString2(dispatch.payload?.message) || readString2(dispatch.payload?.summary) || "";
|
|
9126
|
-
const { title, summary } = summarizeMessage(message);
|
|
9127
|
-
|
|
9182
|
+
const { title, summary: summary2 } = summarizeMessage(message);
|
|
9183
|
+
const record = {
|
|
9128
9184
|
taskId,
|
|
9129
9185
|
source: "direct",
|
|
9130
9186
|
status,
|
|
@@ -9132,7 +9188,7 @@ function buildMeshActiveWork(opts) {
|
|
|
9132
9188
|
sessionId: dispatch.sessionId,
|
|
9133
9189
|
providerType: dispatch.providerType || readString2(dispatch.payload?.providerType),
|
|
9134
9190
|
taskTitle: readString2(dispatch.payload?.taskTitle) || title,
|
|
9135
|
-
taskSummary: readString2(dispatch.payload?.taskSummary) ||
|
|
9191
|
+
taskSummary: readString2(dispatch.payload?.taskSummary) || summary2,
|
|
9136
9192
|
message,
|
|
9137
9193
|
taskMode: readString2(dispatch.payload?.taskMode),
|
|
9138
9194
|
createdAt: dispatch.timestamp,
|
|
@@ -9141,11 +9197,20 @@ function buildMeshActiveWork(opts) {
|
|
|
9141
9197
|
elapsedMs: elapsedSince(dispatch.timestamp, now),
|
|
9142
9198
|
terminal: terminalRow,
|
|
9143
9199
|
terminalKind: terminal?.kind,
|
|
9144
|
-
terminalAt: terminal?.timestamp
|
|
9145
|
-
|
|
9200
|
+
terminalAt: terminal?.timestamp,
|
|
9201
|
+
staleReason: live.staleReason
|
|
9202
|
+
};
|
|
9203
|
+
if (live.staleReason && !terminalRow) {
|
|
9204
|
+
staleDirectWork.push(record);
|
|
9205
|
+
continue;
|
|
9206
|
+
}
|
|
9207
|
+
records.push(record);
|
|
9146
9208
|
}
|
|
9147
9209
|
records.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
9148
|
-
|
|
9210
|
+
staleDirectWork.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
9211
|
+
const summary = buildMeshActiveWorkSummary(records);
|
|
9212
|
+
summary.staleDirectCount = staleDirectWork.length;
|
|
9213
|
+
return { activeWork: records, staleDirectWork, summary };
|
|
9149
9214
|
}
|
|
9150
9215
|
|
|
9151
9216
|
// src/index.ts
|
|
@@ -19432,23 +19497,28 @@ var CliProviderInstance = class {
|
|
|
19432
19497
|
if (hasNonEmptyCliModalButtons(parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
|
|
19433
19498
|
return !this.hasAdapterPendingResponse();
|
|
19434
19499
|
}
|
|
19435
|
-
|
|
19436
|
-
if (latestVisibleStatus !== "idle") return `status:${latestVisibleStatus}
|
|
19500
|
+
getCompletedFinalizationBlock(latestVisibleStatus) {
|
|
19501
|
+
if (latestVisibleStatus !== "idle") return { reason: `status:${latestVisibleStatus}`, terminal: true };
|
|
19437
19502
|
const adapterAny = this.adapter;
|
|
19438
|
-
if (adapterAny?.isWaitingForResponse === true) return "adapter_waiting_for_response";
|
|
19439
|
-
if (adapterAny?.currentTurnScope) return "adapter_turn_scope_active";
|
|
19503
|
+
if (adapterAny?.isWaitingForResponse === true) return { reason: "adapter_waiting_for_response", terminal: true };
|
|
19504
|
+
if (adapterAny?.currentTurnScope) return { reason: "adapter_turn_scope_active", terminal: true };
|
|
19505
|
+
if (this.hasAdapterPendingResponse()) return { reason: "adapter_pending_response", terminal: true };
|
|
19440
19506
|
const partial = typeof this.adapter.getPartialResponse === "function" ? this.adapter.getPartialResponse() : "";
|
|
19441
|
-
if (typeof partial === "string" && partial.trim()) return "partial_response_pending";
|
|
19507
|
+
if (typeof partial === "string" && partial.trim()) return { reason: "partial_response_pending", terminal: true };
|
|
19442
19508
|
let parsed;
|
|
19443
19509
|
try {
|
|
19444
19510
|
parsed = this.adapter.getScriptParsedStatus();
|
|
19445
19511
|
} catch (error) {
|
|
19446
|
-
return `parse_error:${error?.message || String(error)}
|
|
19512
|
+
return { reason: `parse_error:${error?.message || String(error)}` };
|
|
19447
19513
|
}
|
|
19448
19514
|
const parsedStatus = typeof parsed?.status === "string" ? parsed.status : "unknown";
|
|
19449
|
-
if (parsedStatus !== "idle")
|
|
19450
|
-
|
|
19451
|
-
|
|
19515
|
+
if (parsedStatus !== "idle") {
|
|
19516
|
+
const adapterStatus = this.adapter.getStatus({ allowParse: false });
|
|
19517
|
+
if (this.shouldSuppressStaleParsedBusyStatus(parsed, adapterStatus)) return null;
|
|
19518
|
+
return { reason: `parsed_status:${parsedStatus}`, terminal: isCliGeneratingLikeStatus(parsedStatus) };
|
|
19519
|
+
}
|
|
19520
|
+
if (parsed?.activeModal || parsed?.modal) return { reason: "parsed_modal_active", terminal: true };
|
|
19521
|
+
if (!this.completionHasFinalAssistantMessage(parsed?.messages)) return { reason: "missing_final_assistant" };
|
|
19452
19522
|
return null;
|
|
19453
19523
|
}
|
|
19454
19524
|
scheduleCompletedDebounceFlush(delayMs) {
|
|
@@ -19470,10 +19540,11 @@ var CliProviderInstance = class {
|
|
|
19470
19540
|
this.completedDebounceTimer = null;
|
|
19471
19541
|
return;
|
|
19472
19542
|
}
|
|
19473
|
-
const
|
|
19474
|
-
if (
|
|
19543
|
+
const block2 = this.getCompletedFinalizationBlock(latestVisibleStatus);
|
|
19544
|
+
if (block2) {
|
|
19545
|
+
const blockReason = block2.reason;
|
|
19475
19546
|
const waitedMs = Date.now() - pending.firstObservedAt;
|
|
19476
|
-
if (waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS) {
|
|
19547
|
+
if (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS) {
|
|
19477
19548
|
if (pending.loggedBlockReason !== blockReason) {
|
|
19478
19549
|
LOG.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
|
|
19479
19550
|
pending.loggedBlockReason = blockReason;
|
|
@@ -21342,6 +21413,47 @@ var BUSY_AGENT_STATUSES = /* @__PURE__ */ new Set(["generating", "running", "str
|
|
|
21342
21413
|
function normalizeAgentStatus(value) {
|
|
21343
21414
|
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
21344
21415
|
}
|
|
21416
|
+
function hasNonEmptyModalButtons2(activeModal) {
|
|
21417
|
+
const buttons = activeModal?.buttons;
|
|
21418
|
+
return Array.isArray(buttons) && buttons.some((button) => String(button || "").trim().length > 0);
|
|
21419
|
+
}
|
|
21420
|
+
function hasAdapterPendingResponse(adapter) {
|
|
21421
|
+
if (adapter?.isWaitingForResponse === true) return true;
|
|
21422
|
+
if (adapter?.currentTurnScope) return true;
|
|
21423
|
+
try {
|
|
21424
|
+
if (typeof adapter?.isProcessing === "function" && adapter.isProcessing()) return true;
|
|
21425
|
+
} catch {
|
|
21426
|
+
}
|
|
21427
|
+
try {
|
|
21428
|
+
const partial = typeof adapter?.getPartialResponse === "function" ? adapter.getPartialResponse() : "";
|
|
21429
|
+
if (typeof partial === "string" && partial.trim()) return true;
|
|
21430
|
+
} catch {
|
|
21431
|
+
}
|
|
21432
|
+
return false;
|
|
21433
|
+
}
|
|
21434
|
+
function shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapter) {
|
|
21435
|
+
const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
|
|
21436
|
+
if (!BUSY_AGENT_STATUSES.has(parsedRawStatus)) return false;
|
|
21437
|
+
if (adapterStatus !== "idle") return false;
|
|
21438
|
+
if (hasNonEmptyModalButtons2(parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
|
|
21439
|
+
return !hasAdapterPendingResponse(adapter);
|
|
21440
|
+
}
|
|
21441
|
+
function getEffectiveAgentSendStatus(adapter) {
|
|
21442
|
+
const adapterStatus = normalizeAgentStatus(adapter?.getStatus?.({ allowParse: false })?.status ?? adapter?.getStatus?.()?.status);
|
|
21443
|
+
if (adapterStatus && adapterStatus !== "idle") return adapterStatus;
|
|
21444
|
+
if (adapterStatus !== "idle") return adapterStatus;
|
|
21445
|
+
if (typeof adapter?.getScriptParsedStatus !== "function") return adapterStatus;
|
|
21446
|
+
try {
|
|
21447
|
+
const parsedStatus = adapter.getScriptParsedStatus();
|
|
21448
|
+
const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
|
|
21449
|
+
if (BUSY_AGENT_STATUSES.has(parsedRawStatus) && !shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapter)) {
|
|
21450
|
+
return parsedRawStatus;
|
|
21451
|
+
}
|
|
21452
|
+
} catch {
|
|
21453
|
+
return adapterStatus;
|
|
21454
|
+
}
|
|
21455
|
+
return adapterStatus;
|
|
21456
|
+
}
|
|
21345
21457
|
var chalkModule = chalk;
|
|
21346
21458
|
var chalkApi = typeof chalkModule.yellow === "function" ? chalkModule : chalkModule.default || null;
|
|
21347
21459
|
function colorize(color, text) {
|
|
@@ -22116,7 +22228,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
22116
22228
|
if (!found) throw new Error(`CLI agent not running: ${agentType}`);
|
|
22117
22229
|
const { adapter, key } = found;
|
|
22118
22230
|
if (action === "send_chat") {
|
|
22119
|
-
const currentStatus =
|
|
22231
|
+
const currentStatus = getEffectiveAgentSendStatus(adapter);
|
|
22120
22232
|
if (BUSY_AGENT_STATUSES.has(currentStatus)) {
|
|
22121
22233
|
return {
|
|
22122
22234
|
success: false,
|
|
@@ -25461,8 +25573,8 @@ async function maybeRunDaemonUpgradeHelperFromEnv() {
|
|
|
25461
25573
|
|
|
25462
25574
|
// src/commands/router.ts
|
|
25463
25575
|
init_mesh_work_queue();
|
|
25464
|
-
import { homedir as homedir19
|
|
25465
|
-
import { join as pathJoin, resolve as pathResolve } from "path";
|
|
25576
|
+
import { homedir as homedir19 } from "os";
|
|
25577
|
+
import { basename as pathBasename, join as pathJoin, resolve as pathResolve } from "path";
|
|
25466
25578
|
import * as fs11 from "fs";
|
|
25467
25579
|
var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
|
|
25468
25580
|
var CHANNEL_SERVER_URL = {
|
|
@@ -25605,6 +25717,17 @@ function readGitSubmodules(value, parentRepoRoot) {
|
|
|
25605
25717
|
}).filter((entry) => entry !== null);
|
|
25606
25718
|
return submodules.length > 0 ? submodules : void 0;
|
|
25607
25719
|
}
|
|
25720
|
+
function buildMeshNodeDisplayLabel(node, nodeId, providerPriority) {
|
|
25721
|
+
const explicit = readStringValue(node.machineLabel, node.machine_label, node.machineNickname, node.machine_nickname, node.alias);
|
|
25722
|
+
if (explicit) return explicit;
|
|
25723
|
+
const workspace = readStringValue(node.workspace, node.repoRoot, node.repo_root);
|
|
25724
|
+
const workspaceName = workspace ? pathBasename(workspace) : void 0;
|
|
25725
|
+
const host = readStringValue(node.hostname, node.host, node.daemonId, node.daemon_id, node.machineId, node.machine_id);
|
|
25726
|
+
const provider = providerPriority[0] || (Array.isArray(node.providers) ? readStringValue(...node.providers) : void 0);
|
|
25727
|
+
const parts = [workspaceName, host, provider].filter(Boolean);
|
|
25728
|
+
if (parts.length > 0) return parts.join(" \xB7 ");
|
|
25729
|
+
return nodeId || "unidentified mesh node";
|
|
25730
|
+
}
|
|
25608
25731
|
function normalizeInlineMeshGitStatus(status, node, options) {
|
|
25609
25732
|
const isGitRepo = readBooleanValue(status.isGitRepo);
|
|
25610
25733
|
if (!Object.keys(status).length || isGitRepo === void 0) return void 0;
|
|
@@ -26275,7 +26398,7 @@ function recordMeshRefineStage(stages, stage, status, startedAt, details) {
|
|
|
26275
26398
|
}
|
|
26276
26399
|
function buildSubmodulePublishRequiredNextStep(entries) {
|
|
26277
26400
|
const refs = entries.map((entry) => `${entry.path}@${entry.commit}`).join(", ");
|
|
26278
|
-
return `Ask the user for explicit approval to push/publish the unreachable submodule commit(s) (${refs}) to
|
|
26401
|
+
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.`;
|
|
26279
26402
|
}
|
|
26280
26403
|
async function computeGitPatchId(cwd, fromRef, toRef) {
|
|
26281
26404
|
const { execFileSync: execFileSync3 } = await import("child_process");
|
|
@@ -26362,15 +26485,9 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
|
|
|
26362
26485
|
});
|
|
26363
26486
|
return String(stdout || "");
|
|
26364
26487
|
};
|
|
26365
|
-
const
|
|
26366
|
-
|
|
26367
|
-
|
|
26368
|
-
await runGit2(probeDir, ["init", "-q"]);
|
|
26369
|
-
await runGit2(probeDir, ["-c", "protocol.file.allow=always", "fetch", "--depth=1", remoteUrl, commit]);
|
|
26370
|
-
await runGit2(probeDir, ["cat-file", "-e", `${commit}^{commit}`]);
|
|
26371
|
-
} finally {
|
|
26372
|
-
fs11.rmSync(probeDir, { recursive: true, force: true });
|
|
26373
|
-
}
|
|
26488
|
+
const verifyRemoteMainContainsCommit = async (submodulePath, commit, branch = "main") => {
|
|
26489
|
+
await runGit2(submodulePath, ["-c", "protocol.file.allow=always", "fetch", "origin", `refs/heads/${branch}:refs/remotes/origin/${branch}`]);
|
|
26490
|
+
await runGit2(submodulePath, ["merge-base", "--is-ancestor", commit, `refs/remotes/origin/${branch}`]);
|
|
26374
26491
|
};
|
|
26375
26492
|
const treeOutput = await runGit2(repoRoot, ["ls-tree", "-r", "-z", mergedTree]);
|
|
26376
26493
|
const gitlinks = treeOutput.split("\0").filter(Boolean).map((record) => {
|
|
@@ -26411,15 +26528,18 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree) {
|
|
|
26411
26528
|
entries.push(entry);
|
|
26412
26529
|
continue;
|
|
26413
26530
|
}
|
|
26414
|
-
|
|
26531
|
+
entry.remoteMainBranch = "main";
|
|
26532
|
+
await verifyRemoteMainContainsCommit(submodulePath, gitlink.commit, "main");
|
|
26415
26533
|
entry.fetchedFromOrigin = true;
|
|
26416
26534
|
entry.remoteReachable = true;
|
|
26535
|
+
entry.remoteMainReachable = true;
|
|
26417
26536
|
entry.reachable = true;
|
|
26418
26537
|
} catch (e) {
|
|
26419
26538
|
entry.remoteReachable = false;
|
|
26539
|
+
entry.remoteMainReachable = false;
|
|
26420
26540
|
entry.publishRequired = true;
|
|
26421
26541
|
const details = truncateValidationOutput(e?.stderr || e?.message || String(e));
|
|
26422
|
-
entry.error = `Submodule remote reachability check failed for origin: ${details}`;
|
|
26542
|
+
entry.error = `Submodule remote main reachability check failed for origin/main: ${details}`;
|
|
26423
26543
|
}
|
|
26424
26544
|
} catch (e) {
|
|
26425
26545
|
entry.error = truncateValidationOutput(e?.message || String(e));
|
|
@@ -27394,28 +27514,51 @@ var DaemonCommandRouter = class {
|
|
|
27394
27514
|
};
|
|
27395
27515
|
}
|
|
27396
27516
|
queueRefineJobEvent(event, handle, result) {
|
|
27397
|
-
|
|
27517
|
+
const metadataEvent = {
|
|
27518
|
+
source: "refine_mesh_node_async_job",
|
|
27519
|
+
jobId: handle.jobId,
|
|
27520
|
+
interactionId: handle.interactionId,
|
|
27521
|
+
meshId: handle.meshId,
|
|
27522
|
+
nodeId: handle.targetNodeId,
|
|
27523
|
+
targetDaemonId: handle.targetDaemonId,
|
|
27524
|
+
workspace: handle.workspace,
|
|
27525
|
+
status: handle.status,
|
|
27526
|
+
startedAt: handle.startedAt,
|
|
27527
|
+
completedAt: handle.completedAt,
|
|
27528
|
+
retryOfJobId: handle.retryOfJobId,
|
|
27529
|
+
...result ? { result } : {}
|
|
27530
|
+
};
|
|
27531
|
+
const eventPayload = {
|
|
27398
27532
|
event,
|
|
27399
27533
|
meshId: handle.meshId,
|
|
27400
27534
|
nodeLabel: handle.targetNodeId,
|
|
27401
27535
|
nodeId: handle.targetNodeId,
|
|
27402
27536
|
workspace: handle.workspace,
|
|
27403
|
-
metadataEvent
|
|
27404
|
-
source: "refine_mesh_node_async_job",
|
|
27405
|
-
jobId: handle.jobId,
|
|
27406
|
-
interactionId: handle.interactionId,
|
|
27407
|
-
meshId: handle.meshId,
|
|
27408
|
-
nodeId: handle.targetNodeId,
|
|
27409
|
-
targetDaemonId: handle.targetDaemonId,
|
|
27410
|
-
workspace: handle.workspace,
|
|
27411
|
-
status: handle.status,
|
|
27412
|
-
startedAt: handle.startedAt,
|
|
27413
|
-
completedAt: handle.completedAt,
|
|
27414
|
-
retryOfJobId: handle.retryOfJobId,
|
|
27415
|
-
...result ? { result } : {}
|
|
27416
|
-
},
|
|
27537
|
+
metadataEvent,
|
|
27417
27538
|
queuedAt: Date.now()
|
|
27418
|
-
}
|
|
27539
|
+
};
|
|
27540
|
+
if (typeof this.deps.instanceManager?.getByCategory === "function") {
|
|
27541
|
+
const forwarded = handleMeshForwardEvent(
|
|
27542
|
+
{ instanceManager: this.deps.instanceManager },
|
|
27543
|
+
{
|
|
27544
|
+
event,
|
|
27545
|
+
meshId: handle.meshId,
|
|
27546
|
+
nodeId: handle.targetNodeId,
|
|
27547
|
+
workspace: handle.workspace,
|
|
27548
|
+
jobId: handle.jobId,
|
|
27549
|
+
interactionId: handle.interactionId,
|
|
27550
|
+
status: handle.status,
|
|
27551
|
+
targetDaemonId: handle.targetDaemonId,
|
|
27552
|
+
startedAt: handle.startedAt,
|
|
27553
|
+
completedAt: handle.completedAt,
|
|
27554
|
+
retryOfJobId: handle.retryOfJobId,
|
|
27555
|
+
...result ? { result } : {}
|
|
27556
|
+
}
|
|
27557
|
+
);
|
|
27558
|
+
if (forwarded?.success === true) return;
|
|
27559
|
+
LOG.warn("Mesh", `[Refinery] Failed to forward async refine event ${event}: ${forwarded?.error || "unknown error"}`);
|
|
27560
|
+
}
|
|
27561
|
+
queuePendingMeshCoordinatorEvent(eventPayload);
|
|
27419
27562
|
}
|
|
27420
27563
|
async appendRefineJobLedger(kind, handle, result) {
|
|
27421
27564
|
try {
|
|
@@ -27567,6 +27710,8 @@ var DaemonCommandRouter = class {
|
|
|
27567
27710
|
remote: entry.remote,
|
|
27568
27711
|
remoteUrl: entry.remoteUrl,
|
|
27569
27712
|
remoteReachable: entry.remoteReachable,
|
|
27713
|
+
remoteMainBranch: entry.remoteMainBranch,
|
|
27714
|
+
remoteMainReachable: entry.remoteMainReachable,
|
|
27570
27715
|
error: entry.error
|
|
27571
27716
|
})),
|
|
27572
27717
|
error: submoduleReachability.error
|
|
@@ -27579,13 +27724,13 @@ var DaemonCommandRouter = class {
|
|
|
27579
27724
|
convergenceStatus: "blocked_review",
|
|
27580
27725
|
publishRequired: true,
|
|
27581
27726
|
blockedReason: "submodule_publish_required",
|
|
27582
|
-
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.",
|
|
27727
|
+
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.",
|
|
27583
27728
|
nextStep,
|
|
27584
27729
|
nextSteps: [
|
|
27585
27730
|
"Ask the user for explicit approval before pushing or publishing any submodule commit.",
|
|
27586
|
-
"Push/publish each unreachable submodule commit to the configured submodule remote shown in the evidence.",
|
|
27731
|
+
"Push/publish each unreachable submodule commit to the configured submodule remote main branch shown in the evidence.",
|
|
27587
27732
|
"Rerun mesh_refine_node after remote reachability is confirmed.",
|
|
27588
|
-
"Do not merge the root branch until every submodule gitlink commit is reachable from
|
|
27733
|
+
"Do not merge the root branch until every submodule gitlink commit is reachable from submodule origin/main."
|
|
27589
27734
|
],
|
|
27590
27735
|
unreachableSubmoduleCommits: submoduleReachability.unreachable.map((entry) => ({
|
|
27591
27736
|
path: entry.path,
|
|
@@ -27593,6 +27738,8 @@ var DaemonCommandRouter = class {
|
|
|
27593
27738
|
remote: entry.remote,
|
|
27594
27739
|
remoteUrl: entry.remoteUrl,
|
|
27595
27740
|
remoteReachable: entry.remoteReachable,
|
|
27741
|
+
remoteMainBranch: entry.remoteMainBranch,
|
|
27742
|
+
remoteMainReachable: entry.remoteMainReachable,
|
|
27596
27743
|
error: entry.error
|
|
27597
27744
|
})),
|
|
27598
27745
|
branch,
|
|
@@ -29467,7 +29614,8 @@ ${block2}`);
|
|
|
29467
29614
|
) || Boolean(meshRecord?.inline && nodeIndex === 0);
|
|
29468
29615
|
const status = {
|
|
29469
29616
|
nodeId,
|
|
29470
|
-
machineLabel: node
|
|
29617
|
+
machineLabel: buildMeshNodeDisplayLabel(node, nodeId, providerPriority),
|
|
29618
|
+
labelSource: readStringValue(node.machineLabel, node.machine_label, node.machineNickname, node.machine_nickname, node.alias) ? "explicit_metadata" : "workspace_host_provider_context",
|
|
29471
29619
|
workspace: node.workspace,
|
|
29472
29620
|
repoRoot: node.repoRoot,
|
|
29473
29621
|
isLocalWorktree: node.isLocalWorktree,
|