@adhdev/daemon-core 0.9.82-rc.373 → 0.9.82-rc.375
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 +372 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +372 -66
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +53 -0
- package/dist/mesh/mesh-events-stale.d.ts +12 -0
- package/dist/mesh/mesh-ledger.d.ts +1 -1
- package/dist/providers/chat-message-normalization.d.ts +1 -1
- package/dist/providers/cli-provider-instance.d.ts +3 -0
- package/package.json +2 -2
- package/src/commands/high-family/mesh-coordinator-launch.ts +67 -2
- package/src/commands/med-family/cli-agent.ts +25 -13
- package/src/commands/med-family/fast-forward.ts +80 -48
- package/src/commands/med-family/mesh-crud.ts +12 -2
- package/src/mesh/coordinator-prompt.ts +145 -0
- package/src/mesh/mesh-events-coordinator.ts +64 -1
- package/src/mesh/mesh-events-stale.ts +23 -0
- package/src/mesh/mesh-events-utils.ts +1 -1
- package/src/mesh/mesh-ledger.ts +5 -0
- package/src/mesh/mesh-reconcile-loop.ts +145 -10
- package/src/providers/chat-message-normalization.ts +1 -1
- package/src/providers/cli-provider-instance.ts +69 -2
package/dist/index.js
CHANGED
|
@@ -316,10 +316,10 @@ function readInjected(value) {
|
|
|
316
316
|
}
|
|
317
317
|
function getDaemonBuildInfo() {
|
|
318
318
|
if (cached) return cached;
|
|
319
|
-
const commit = readInjected(true ? "
|
|
320
|
-
const commitShort = readInjected(true ? "
|
|
321
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
322
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
319
|
+
const commit = readInjected(true ? "b17fb9165bd52c9e2ab8cccf2ce80734e2165680" : void 0) ?? "unknown";
|
|
320
|
+
const commitShort = readInjected(true ? "b17fb916" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
321
|
+
const version = readInjected(true ? "0.9.82-rc.375" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
322
|
+
const builtAt = readInjected(true ? "2026-06-25T02:21:59.111Z" : void 0);
|
|
323
323
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
324
324
|
return cached;
|
|
325
325
|
}
|
|
@@ -3042,6 +3042,10 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
3042
3042
|
if (ctx.missionSection?.trim()) {
|
|
3043
3043
|
sections.push(ctx.missionSection.trim());
|
|
3044
3044
|
}
|
|
3045
|
+
const recentActivity = buildRecentActivitySection(ctx.recentActivity);
|
|
3046
|
+
if (recentActivity) sections.push(recentActivity);
|
|
3047
|
+
const operatingNotes = buildOperatingNotesSection(ctx.operatingNotes);
|
|
3048
|
+
if (operatingNotes) sections.push(operatingNotes);
|
|
3045
3049
|
sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
|
|
3046
3050
|
sections.push(TOOLS_SECTION);
|
|
3047
3051
|
sections.push(TOOL_EXPOSURE_PREFLIGHT_SECTION);
|
|
@@ -3073,6 +3077,8 @@ function expandPromptPlaceholders(template, ctx) {
|
|
|
3073
3077
|
cliType: coordinatorCliType || "",
|
|
3074
3078
|
nodes: nodesSection,
|
|
3075
3079
|
mission: ctx.missionSection?.trim() || "",
|
|
3080
|
+
recentActivity: buildRecentActivitySection(ctx.recentActivity) || "",
|
|
3081
|
+
operatingNotes: buildOperatingNotesSection(ctx.operatingNotes) || "",
|
|
3076
3082
|
policy: buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }),
|
|
3077
3083
|
tools: TOOLS_SECTION,
|
|
3078
3084
|
workflow: WORKFLOW_SECTION,
|
|
@@ -3144,6 +3150,56 @@ function indentFollowing(text, pad) {
|
|
|
3144
3150
|
if (lines.length === 1) return lines[0];
|
|
3145
3151
|
return [lines[0], ...lines.slice(1).map((l) => pad + l)].join("\n");
|
|
3146
3152
|
}
|
|
3153
|
+
function buildRecentActivitySection(activity) {
|
|
3154
|
+
if (!activity) return "";
|
|
3155
|
+
const failures = Array.isArray(activity.recentFailures) ? activity.recentFailures : [];
|
|
3156
|
+
const pending = Number.isFinite(activity.pendingTasks) ? Number(activity.pendingTasks) : 0;
|
|
3157
|
+
const assigned = Number.isFinite(activity.assignedTasks) ? Number(activity.assignedTasks) : 0;
|
|
3158
|
+
const stalled = Number.isFinite(activity.stalledTasks) ? Number(activity.stalledTasks) : 0;
|
|
3159
|
+
const recentFailureCount = Number.isFinite(activity.recentFailureCount) ? Number(activity.recentFailureCount) : failures.length;
|
|
3160
|
+
if (failures.length === 0 && pending === 0 && assigned === 0 && stalled === 0 && recentFailureCount === 0) {
|
|
3161
|
+
return "";
|
|
3162
|
+
}
|
|
3163
|
+
const lines = ["## Recent Activity", ""];
|
|
3164
|
+
lines.push("A snapshot of this mesh's recent ledger/queue state at launch. Use it to decide what needs attention first; call `mesh_task_history` / `mesh_view_queue` for full detail.");
|
|
3165
|
+
lines.push("");
|
|
3166
|
+
const counts = [];
|
|
3167
|
+
if (pending > 0) counts.push(`**${pending}** pending`);
|
|
3168
|
+
if (assigned > 0) counts.push(`**${assigned}** assigned`);
|
|
3169
|
+
if (stalled > 0) counts.push(`**${stalled}** stalled`);
|
|
3170
|
+
if (recentFailureCount > 0) counts.push(`**${recentFailureCount}** failed in the last 30 min`);
|
|
3171
|
+
if (counts.length) lines.push(`- Queue/ledger: ${counts.join(", ")}.`);
|
|
3172
|
+
if (activity.lastActivityAt) lines.push(`- Last ledger activity: ${activity.lastActivityAt}.`);
|
|
3173
|
+
if (failures.length > 0) {
|
|
3174
|
+
const recent = failures.slice(-5).reverse();
|
|
3175
|
+
lines.push("", "Recent failures (newest first):");
|
|
3176
|
+
for (const f of recent) {
|
|
3177
|
+
const when = f.timestamp ? `${f.timestamp} ` : "";
|
|
3178
|
+
const node = f.nodeId ? `node \`${f.nodeId}\`` : "unknown node";
|
|
3179
|
+
const summary = (f.summary || "").trim();
|
|
3180
|
+
lines.push(`- ${when}${node}${summary ? ` \u2014 ${summary}` : ""}`);
|
|
3181
|
+
}
|
|
3182
|
+
lines.push("", "_Check `mesh_task_history` before retrying; repeated failures on the same node mean reassign or escalate, not retry._");
|
|
3183
|
+
}
|
|
3184
|
+
return lines.join("\n");
|
|
3185
|
+
}
|
|
3186
|
+
function buildOperatingNotesSection(notes) {
|
|
3187
|
+
const valid = Array.isArray(notes) ? notes.filter((n) => n && typeof n.text === "string" && n.text.trim()) : [];
|
|
3188
|
+
if (valid.length === 0) return "";
|
|
3189
|
+
const categoryLabel = {
|
|
3190
|
+
provider_quirk: "provider quirk",
|
|
3191
|
+
pattern_to_avoid: "pattern to avoid",
|
|
3192
|
+
recovery_lesson: "recovery lesson"
|
|
3193
|
+
};
|
|
3194
|
+
const lines = ["## Operating Notes", ""];
|
|
3195
|
+
lines.push("Lessons earlier coordinators on this mesh recorded via `mesh_record_note`. Treat them as accumulated operating knowledge \u2014 apply them. When you learn a durable lesson (a provider quirk, a pattern to avoid, a recovery lesson), record it with `mesh_record_note` so future coordinators inherit it.");
|
|
3196
|
+
lines.push("");
|
|
3197
|
+
for (const n of valid) {
|
|
3198
|
+
const cat = n.category && categoryLabel[n.category] ? `[${categoryLabel[n.category]}] ` : "";
|
|
3199
|
+
lines.push(`- ${cat}${n.text.trim()}`);
|
|
3200
|
+
}
|
|
3201
|
+
return lines.join("\n");
|
|
3202
|
+
}
|
|
3147
3203
|
function buildPolicySection(policy) {
|
|
3148
3204
|
const rules = [];
|
|
3149
3205
|
if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
|
|
@@ -3207,6 +3263,7 @@ var init_coordinator_prompt = __esm({
|
|
|
3207
3263
|
| \`mesh_read_chat\` | Read recent chat messages from a delegated agent session |
|
|
3208
3264
|
| \`mesh_read_debug\` | Collect a daemon-side chat/parser debug bundle for a session |
|
|
3209
3265
|
| \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
|
|
3266
|
+
| \`mesh_record_note\` | Record a durable, provider-neutral operating note (provider quirk / pattern to avoid / recovery lesson). Future coordinators see it under "## Operating Notes" at launch |
|
|
3210
3267
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
3211
3268
|
| \`mesh_read_node_logs\` | Fetch a remote node's daemon log tail directly over P2P (grep/since/byte-bounded, secrets redacted) \u2014 no session/PowerShell needed to debug a node's daemon |
|
|
3212
3269
|
| \`mesh_fast_forward_node\` | Safely dry-run or explicitly execute an obvious clean fast-forward without launching an agent session |
|
|
@@ -8749,7 +8806,7 @@ var init_mesh_events_utils = __esm({
|
|
|
8749
8806
|
"src/mesh/mesh-events-utils.ts"() {
|
|
8750
8807
|
"use strict";
|
|
8751
8808
|
MESH_SURFACED_PREVIEW_MAX_CHARS = 512;
|
|
8752
|
-
MESH_COMPLETION_SURFACE_MAX_CHARS =
|
|
8809
|
+
MESH_COMPLETION_SURFACE_MAX_CHARS = 16e3;
|
|
8753
8810
|
}
|
|
8754
8811
|
});
|
|
8755
8812
|
|
|
@@ -9389,6 +9446,22 @@ function isWeakCompletionLedgerPayload(payload) {
|
|
|
9389
9446
|
const diag = readRecord4(payload.completionDiagnostic);
|
|
9390
9447
|
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
9391
9448
|
}
|
|
9449
|
+
function findTerminalLedgerEvidenceForTask(args) {
|
|
9450
|
+
const taskId = readNonEmptyString2(args.taskId);
|
|
9451
|
+
if (!taskId) return null;
|
|
9452
|
+
const entries = readLedgerEntries(args.meshId, { tail: args.tail ?? 500 });
|
|
9453
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
9454
|
+
const entry = entries[i];
|
|
9455
|
+
if (entry.kind !== "task_completed" && entry.kind !== "task_failed" && entry.kind !== "task_stalled") continue;
|
|
9456
|
+
const terminalTaskId = readNonEmptyString2(entry.payload?.taskId);
|
|
9457
|
+
if (terminalTaskId !== taskId) continue;
|
|
9458
|
+
if (entry.kind === "task_completed" && isWeakCompletionLedgerPayload(entry.payload)) continue;
|
|
9459
|
+
if (args.sessionId && entry.sessionId && entry.sessionId !== args.sessionId) continue;
|
|
9460
|
+
if (!args.sessionId && args.nodeId && entry.nodeId && !meshNodeIdMatches(entry, args.nodeId)) continue;
|
|
9461
|
+
return { id: entry.id, kind: entry.kind, payload: entry.payload || {}, timestamp: entry.timestamp };
|
|
9462
|
+
}
|
|
9463
|
+
return null;
|
|
9464
|
+
}
|
|
9392
9465
|
function findDirectDispatchLedgerEntry(args) {
|
|
9393
9466
|
const entries = readLedgerEntries(args.meshId, { tail: 500 });
|
|
9394
9467
|
for (let i = entries.length - 1; i >= 0; i--) {
|
|
@@ -11517,7 +11590,7 @@ var init_chat_message_normalization = __esm({
|
|
|
11517
11590
|
"src/providers/chat-message-normalization.ts"() {
|
|
11518
11591
|
"use strict";
|
|
11519
11592
|
init_contracts();
|
|
11520
|
-
DEFAULT_FINAL_SUMMARY_MAX_CHARS =
|
|
11593
|
+
DEFAULT_FINAL_SUMMARY_MAX_CHARS = 16e3;
|
|
11521
11594
|
BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
|
|
11522
11595
|
CHAT_MESSAGE_VISIBILITIES = ["user", "debug", "internal", "hidden"];
|
|
11523
11596
|
CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES = ["visible", "chat", "user", "debug", "internal", "hidden"];
|
|
@@ -12924,6 +12997,18 @@ function isWeakTerminalLedgerPayload(payload) {
|
|
|
12924
12997
|
const diag = readRecord4(payload.completionDiagnostic);
|
|
12925
12998
|
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
12926
12999
|
}
|
|
13000
|
+
function supersedesTruncatedTerminalSummary(args) {
|
|
13001
|
+
if (!args.terminalTaskId || !args.eventTaskId || args.terminalTaskId !== args.eventTaskId) return false;
|
|
13002
|
+
if (!isGenuineCompletionEvidence(args.metadataEvent)) return false;
|
|
13003
|
+
const terminalSummary = readNonEmptyString2(args.terminalPayload.finalSummary);
|
|
13004
|
+
const eventSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
13005
|
+
if (!eventSummary) return false;
|
|
13006
|
+
if (terminalSummary === eventSummary) return false;
|
|
13007
|
+
if (isWeakTerminalLedgerPayload(args.terminalPayload)) return false;
|
|
13008
|
+
if (!terminalSummary) return true;
|
|
13009
|
+
if (eventSummary.startsWith(terminalSummary)) return true;
|
|
13010
|
+
return eventSummary.length > terminalSummary.length + 32;
|
|
13011
|
+
}
|
|
12927
13012
|
function resolveActiveDirectDispatchTaskId(meshId, sessionId) {
|
|
12928
13013
|
try {
|
|
12929
13014
|
const matches = getActiveDirectDispatches(meshId).filter((d) => d.sessionId === sessionId);
|
|
@@ -13033,6 +13118,23 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
13033
13118
|
if (!task) {
|
|
13034
13119
|
return false;
|
|
13035
13120
|
}
|
|
13121
|
+
const terminal = findTerminalLedgerEvidenceForTask({
|
|
13122
|
+
meshId,
|
|
13123
|
+
taskId: task.id
|
|
13124
|
+
});
|
|
13125
|
+
if (terminal) {
|
|
13126
|
+
const status = terminal.kind === "task_completed" ? "completed" : "failed";
|
|
13127
|
+
updateTaskStatus(meshId, task.id, status);
|
|
13128
|
+
LOG.info("MeshQueue", `Skipped dispatch for terminal task ${task.id} on mesh ${meshId}; ${terminal.kind} ledger evidence already exists`);
|
|
13129
|
+
traceMeshEventDrop("dispatch_terminal_ledger", {
|
|
13130
|
+
taskId: task.id,
|
|
13131
|
+
sessionId,
|
|
13132
|
+
nodeId,
|
|
13133
|
+
meshId,
|
|
13134
|
+
event: "agent_command"
|
|
13135
|
+
}, terminal.kind);
|
|
13136
|
+
return false;
|
|
13137
|
+
}
|
|
13036
13138
|
LOG.info("MeshQueue", `Node ${nodeId} (${sessionId}) pulled task ${task.id}`);
|
|
13037
13139
|
if (node?.daemonId && components.dispatchMeshCommand) {
|
|
13038
13140
|
const isLocalNode = components.cliManager.adapters.has(sessionId);
|
|
@@ -13823,7 +13925,13 @@ function evaluateMeshEventSuppression(args, ctx) {
|
|
|
13823
13925
|
const terminalTaskId = readNonEmptyString2(terminal.payload.taskId);
|
|
13824
13926
|
const eventTaskId = readNonEmptyString2(args.metadataEvent.taskId);
|
|
13825
13927
|
const distinctTaskCompletion = !!eventTaskId && !!terminalTaskId && eventTaskId !== terminalTaskId;
|
|
13826
|
-
|
|
13928
|
+
const supersedesTruncatedTerminal = supersedesTruncatedTerminalSummary({
|
|
13929
|
+
terminalPayload: terminal.payload,
|
|
13930
|
+
metadataEvent: args.metadataEvent,
|
|
13931
|
+
terminalTaskId,
|
|
13932
|
+
eventTaskId
|
|
13933
|
+
});
|
|
13934
|
+
if (!newDispatchAfterTerminal && !supersedesWeakTerminal && !distinctTaskCompletion && !supersedesTruncatedTerminal) {
|
|
13827
13935
|
const terminalProviderSessionId = readNonEmptyString2(terminal.payload.providerSessionId);
|
|
13828
13936
|
const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
|
|
13829
13937
|
const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
|
|
@@ -14570,20 +14678,24 @@ function daemonHostsMesh(mesh, daemonIds) {
|
|
|
14570
14678
|
if (host.role && host.role !== "host") return false;
|
|
14571
14679
|
const hostDaemonId = readNonEmptyString2(host.hostDaemonId);
|
|
14572
14680
|
if (!hostDaemonId) return true;
|
|
14573
|
-
return daemonIds
|
|
14681
|
+
return daemonIdListIncludes(daemonIds, hostDaemonId);
|
|
14682
|
+
}
|
|
14683
|
+
function daemonIdListIncludes(ids, id) {
|
|
14684
|
+
if (!id) return false;
|
|
14685
|
+
return ids.some((candidate) => candidate === id || daemonIdsEquivalent(candidate, id));
|
|
14574
14686
|
}
|
|
14575
14687
|
function resolveCoordinatorSelfIds(mesh, drainDaemonIds) {
|
|
14576
14688
|
const ids = new Set(drainDaemonIds);
|
|
14577
14689
|
for (const node of mesh.nodes) {
|
|
14578
14690
|
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
14579
14691
|
const nodeMachineId = readNonEmptyString2(node.machineId);
|
|
14580
|
-
const isSelf = nodeDaemonId && drainDaemonIds
|
|
14692
|
+
const isSelf = nodeDaemonId && daemonIdListIncludes(drainDaemonIds, nodeDaemonId) || nodeMachineId && daemonIdListIncludes(drainDaemonIds, nodeMachineId);
|
|
14581
14693
|
if (!isSelf) continue;
|
|
14582
14694
|
if (nodeDaemonId) ids.add(nodeDaemonId);
|
|
14583
14695
|
if (nodeMachineId) ids.add(nodeMachineId);
|
|
14584
14696
|
}
|
|
14585
14697
|
const hostDaemonId = readNonEmptyString2(mesh.meshHost?.hostDaemonId);
|
|
14586
|
-
if (hostDaemonId && ids
|
|
14698
|
+
if (hostDaemonId && daemonIdListIncludes([...ids], hostDaemonId)) ids.add(hostDaemonId);
|
|
14587
14699
|
return [...ids];
|
|
14588
14700
|
}
|
|
14589
14701
|
function findLiveCoordinators(components) {
|
|
@@ -14596,6 +14708,16 @@ function findLiveCoordinators(components) {
|
|
|
14596
14708
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
14597
14709
|
const modalParked = status === "waiting_choice" || status === "waiting_approval";
|
|
14598
14710
|
const sessionId = readNonEmptyString2(state.instanceId);
|
|
14711
|
+
const stateKey = `${meshId}::${sessionId || "?"}`;
|
|
14712
|
+
const prevParked = coordinatorModalParkState.get(stateKey);
|
|
14713
|
+
if (prevParked !== modalParked) {
|
|
14714
|
+
coordinatorModalParkState.set(stateKey, modalParked);
|
|
14715
|
+
if (modalParked) {
|
|
14716
|
+
LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) entered modal-park (status=${status}) \u2014 terminal events for it will be held until the modal is answered`);
|
|
14717
|
+
} else if (prevParked === true) {
|
|
14718
|
+
LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) left modal-park (status=${status}) \u2014 held events will drain on this/next tick`);
|
|
14719
|
+
}
|
|
14720
|
+
}
|
|
14599
14721
|
out.push({ meshId, instance: inst, sessionId, idle: status === "idle", modalParked });
|
|
14600
14722
|
}
|
|
14601
14723
|
return out;
|
|
@@ -14661,6 +14783,23 @@ function recoverStrandedAssignedDispatches(meshId, store) {
|
|
|
14661
14783
|
const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
|
|
14662
14784
|
if (!Number.isFinite(dispatchedAtMs)) continue;
|
|
14663
14785
|
if (nowMs - dispatchedAtMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
|
|
14786
|
+
const terminal = findTerminalLedgerEvidenceForTask({
|
|
14787
|
+
meshId,
|
|
14788
|
+
taskId: row.id
|
|
14789
|
+
});
|
|
14790
|
+
if (terminal) {
|
|
14791
|
+
const status = terminal.kind === "task_completed" ? "completed" : "failed";
|
|
14792
|
+
updateTaskStatus(meshId, row.id, status);
|
|
14793
|
+
LOG.warn("MeshReconcile", `Skipped stranded reclaim redispatch for terminal task ${row.id} on mesh ${meshId}; ${terminal.kind} ledger evidence already exists`);
|
|
14794
|
+
traceMeshEventDrop("assigned_stranded_terminal_ledger", {
|
|
14795
|
+
taskId: row.id,
|
|
14796
|
+
sessionId: row.assignedSessionId,
|
|
14797
|
+
nodeId: row.assignedNodeId,
|
|
14798
|
+
meshId,
|
|
14799
|
+
event: "agent:generating_completed"
|
|
14800
|
+
}, terminal.kind);
|
|
14801
|
+
continue;
|
|
14802
|
+
}
|
|
14664
14803
|
if (store.taskHasConfirmedDelivery(meshId, row.id)) continue;
|
|
14665
14804
|
const reclaimed = reclaimStrandedAssignedTask(meshId, row.id, {
|
|
14666
14805
|
reason: "assigned_stranded_dispatch_unconfirmed",
|
|
@@ -14772,7 +14911,55 @@ async function runMeshReconcileTick(components) {
|
|
|
14772
14911
|
const forceOnly = idleCoordinators.length === 0;
|
|
14773
14912
|
if (targetCoordinators.length === 0) {
|
|
14774
14913
|
if (modalParkedCoordinators.length > 0) {
|
|
14775
|
-
|
|
14914
|
+
const liveSessionIds = new Set(
|
|
14915
|
+
meshCoordinators.map((c) => readNonEmptyString2(c.sessionId)).filter(Boolean)
|
|
14916
|
+
);
|
|
14917
|
+
let orphanEscaped = 0;
|
|
14918
|
+
const hasPendingForOrphanPeek = !store || (() => {
|
|
14919
|
+
try {
|
|
14920
|
+
return store.pendingEventCount(meshId) > 0;
|
|
14921
|
+
} catch {
|
|
14922
|
+
return true;
|
|
14923
|
+
}
|
|
14924
|
+
})();
|
|
14925
|
+
if (hasPendingForOrphanPeek) {
|
|
14926
|
+
let peeked = [];
|
|
14927
|
+
try {
|
|
14928
|
+
peeked = getPendingMeshCoordinatorEvents(meshId, drainDaemonIds.length > 0 ? drainDaemonIds : void 0);
|
|
14929
|
+
} catch {
|
|
14930
|
+
peeked = [];
|
|
14931
|
+
}
|
|
14932
|
+
const isOrphan = (e) => {
|
|
14933
|
+
const want = readNonEmptyString2(e.targetCoordinatorSessionId);
|
|
14934
|
+
return !!want && !liveSessionIds.has(want);
|
|
14935
|
+
};
|
|
14936
|
+
const orphanEventNames = new Set(peeked.filter(isOrphan).map((e) => e.event));
|
|
14937
|
+
if (orphanEventNames.size > 0) {
|
|
14938
|
+
let drained = [];
|
|
14939
|
+
try {
|
|
14940
|
+
drained = drainPendingMeshCoordinatorEvents(
|
|
14941
|
+
meshId,
|
|
14942
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId,
|
|
14943
|
+
{ onlyEvents: orphanEventNames }
|
|
14944
|
+
);
|
|
14945
|
+
} catch (e) {
|
|
14946
|
+
LOG.warn("MeshReconcile", `Orphan-escape drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
14947
|
+
drained = [];
|
|
14948
|
+
}
|
|
14949
|
+
for (const pending of drained) {
|
|
14950
|
+
if (isOrphan(pending)) {
|
|
14951
|
+
holdOrExpireStrictUnmatchedEvent(pending, readNonEmptyString2(pending.targetCoordinatorSessionId), meshId);
|
|
14952
|
+
orphanEscaped++;
|
|
14953
|
+
} else {
|
|
14954
|
+
try {
|
|
14955
|
+
queuePendingMeshCoordinatorEvent(pending);
|
|
14956
|
+
} catch {
|
|
14957
|
+
}
|
|
14958
|
+
}
|
|
14959
|
+
}
|
|
14960
|
+
}
|
|
14961
|
+
}
|
|
14962
|
+
LOG.info("MeshReconcile", `Reconcile skip \u2192 modal-parked: holding pending event(s) for mesh ${meshId} (${modalParkedCoordinators.length} coordinator(s) awaiting a modal answer; events left queued${orphanEscaped > 0 ? `; ${orphanEscaped} orphan-targeted event(s) routed to strict-route TTL` : ""})`);
|
|
14776
14963
|
let hasPending = true;
|
|
14777
14964
|
if (store) {
|
|
14778
14965
|
try {
|
|
@@ -14957,7 +15144,7 @@ async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDa
|
|
|
14957
15144
|
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
14958
15145
|
if (!nodeDaemonId) continue;
|
|
14959
15146
|
if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) continue;
|
|
14960
|
-
if (candidateDaemonIds
|
|
15147
|
+
if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) continue;
|
|
14961
15148
|
for (const pendingEventArgs of pulls) {
|
|
14962
15149
|
let events;
|
|
14963
15150
|
try {
|
|
@@ -15013,7 +15200,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
15013
15200
|
if (!sessionId || !nodeId || !taskId) continue;
|
|
15014
15201
|
const node = nodeById.get(nodeId);
|
|
15015
15202
|
const nodeDaemonId = readNonEmptyString2(node?.daemonId);
|
|
15016
|
-
const isLocalNode = !nodeDaemonId || selfIds
|
|
15203
|
+
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId) || !!components.instanceManager.getInstance(sessionId);
|
|
15017
15204
|
const providerType = readNonEmptyString2(dispatch.providerType);
|
|
15018
15205
|
const readArgs = {
|
|
15019
15206
|
sessionId,
|
|
@@ -15043,6 +15230,19 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
15043
15230
|
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
15044
15231
|
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
15045
15232
|
if (!evidence.finalSummary) continue;
|
|
15233
|
+
const dispatchedAtMs = Date.parse(readNonEmptyString2(dispatch.dispatchedAt));
|
|
15234
|
+
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
|
|
15235
|
+
if (Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs < dispatchedAtMs) {
|
|
15236
|
+
LOG.info("MeshReconcile", `Stale-summary guard: skipping transcript reconcile for task ${taskId} on node ${nodeId} (mesh ${mesh.id}) \u2014 final assistant message (${evidence.transcriptMessageAt}) predates this task's dispatch (${dispatch.dispatchedAt}); it is a prior task's summary`);
|
|
15237
|
+
traceMeshEventDrop("reconcile_stale_summary_before_dispatch", {
|
|
15238
|
+
taskId,
|
|
15239
|
+
sessionId,
|
|
15240
|
+
nodeId,
|
|
15241
|
+
meshId: mesh.id,
|
|
15242
|
+
event: "agent:generating_completed"
|
|
15243
|
+
}, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
|
|
15244
|
+
continue;
|
|
15245
|
+
}
|
|
15046
15246
|
const providerSessionId = readNonEmptyString2(payload.providerSessionId);
|
|
15047
15247
|
const coordinatorDaemonId = selfIds.find((id) => !!id);
|
|
15048
15248
|
try {
|
|
@@ -15088,7 +15288,7 @@ async function collectLiveNodesWithSessions(components, mesh, selfIds, localDaem
|
|
|
15088
15288
|
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
15089
15289
|
return Promise.all(mesh.nodes.map(async (node) => {
|
|
15090
15290
|
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
15091
|
-
const isLocalNode = !nodeDaemonId || selfIds
|
|
15291
|
+
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId);
|
|
15092
15292
|
let statusResult;
|
|
15093
15293
|
try {
|
|
15094
15294
|
if (isLocalNode) {
|
|
@@ -15170,7 +15370,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
15170
15370
|
}
|
|
15171
15371
|
};
|
|
15172
15372
|
}
|
|
15173
|
-
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
|
|
15373
|
+
var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
|
|
15174
15374
|
var init_mesh_reconcile_loop = __esm({
|
|
15175
15375
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
15176
15376
|
"use strict";
|
|
@@ -15192,6 +15392,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
15192
15392
|
init_chat_message_normalization();
|
|
15193
15393
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
15194
15394
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
15395
|
+
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
15195
15396
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
15196
15397
|
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
15197
15398
|
STRICT_SESSION_MATCH_TTL_MS = 6e4;
|
|
@@ -38130,6 +38331,8 @@ function getMessageTime(message) {
|
|
|
38130
38331
|
}
|
|
38131
38332
|
var COMPLETED_FINALIZATION_RETRY_MS = 1e3;
|
|
38132
38333
|
var COMPLETED_FINALIZATION_MAX_WAIT_MS = 3e4;
|
|
38334
|
+
var NATIVE_HISTORY_MESH_IDLE_SETTLE_MS = 1500;
|
|
38335
|
+
var USER_INPUT_ACK_DEDUP_WINDOW_MS = 6e4;
|
|
38133
38336
|
var TERMINAL_MESH_EVENTS = /* @__PURE__ */ new Set([
|
|
38134
38337
|
"agent:generating_completed",
|
|
38135
38338
|
"agent:stopped",
|
|
@@ -38401,6 +38604,14 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
38401
38604
|
runtimeMessages = [];
|
|
38402
38605
|
lastPersistedHistoryMessages = [];
|
|
38403
38606
|
lastAcknowledgedUserInputAt = 0;
|
|
38607
|
+
// TASKBUBBLE-DUP: per-content last-ack timestamps so the same dispatched
|
|
38608
|
+
// prompt acked twice in quick succession (the worker buffers the first
|
|
38609
|
+
// send during bootstrap/busy, then a redelivery — dispatch-confirm-timeout
|
|
38610
|
+
// requeue or a reconcile re-dispatch — fires a SECOND send_chat before the
|
|
38611
|
+
// outbound queue drains) collapses to ONE user bubble. Keyed on the trimmed
|
|
38612
|
+
// content; an entry older than USER_INPUT_ACK_DEDUP_WINDOW_MS is treated as
|
|
38613
|
+
// a fresh, intentional resend and is NOT suppressed.
|
|
38614
|
+
recentUserInputAcks = /* @__PURE__ */ new Map();
|
|
38404
38615
|
lastNativeSourceCanonicalCheckAt = 0;
|
|
38405
38616
|
lastNativeSourceCanonicalCacheKey = void 0;
|
|
38406
38617
|
cachedSqliteDb = null;
|
|
@@ -38835,6 +39046,15 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
38835
39046
|
const content = typeof input === "string" ? input.trim() : buildCliStructuredInputPrompt(input).trim();
|
|
38836
39047
|
if (!content) return;
|
|
38837
39048
|
const receivedAt = Date.now();
|
|
39049
|
+
const ackContentKey = shortHash(`${this.instanceId}:${content}`, 24);
|
|
39050
|
+
const lastAckAt = this.recentUserInputAcks.get(ackContentKey);
|
|
39051
|
+
if (lastAckAt !== void 0 && receivedAt - lastAckAt <= USER_INPUT_ACK_DEDUP_WINDOW_MS) {
|
|
39052
|
+
this.recentUserInputAcks.set(ackContentKey, receivedAt);
|
|
39053
|
+
this.pruneRecentUserInputAcks(receivedAt);
|
|
39054
|
+
return;
|
|
39055
|
+
}
|
|
39056
|
+
this.recentUserInputAcks.set(ackContentKey, receivedAt);
|
|
39057
|
+
this.pruneRecentUserInputAcks(receivedAt);
|
|
38838
39058
|
this.lastAcknowledgedUserInputAt = receivedAt;
|
|
38839
39059
|
const dedupKey = `user_input_ack:${shortHash(`${this.instanceId}:${content}:${receivedAt}`, 24)}`;
|
|
38840
39060
|
this.appendRuntimeMessage(buildChatMessage({
|
|
@@ -38852,6 +39072,13 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
38852
39072
|
}
|
|
38853
39073
|
}), dedupKey);
|
|
38854
39074
|
}
|
|
39075
|
+
/** Drop user-input ack entries older than the dedup window so the map can't grow unbounded. */
|
|
39076
|
+
pruneRecentUserInputAcks(now) {
|
|
39077
|
+
if (this.recentUserInputAcks.size <= 1) return;
|
|
39078
|
+
for (const [key, at] of this.recentUserInputAcks) {
|
|
39079
|
+
if (now - at > USER_INPUT_ACK_DEDUP_WINDOW_MS) this.recentUserInputAcks.delete(key);
|
|
39080
|
+
}
|
|
39081
|
+
}
|
|
38855
39082
|
dispose() {
|
|
38856
39083
|
this.adapter.shutdown();
|
|
38857
39084
|
this.monitor.reset();
|
|
@@ -39541,8 +39768,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
39541
39768
|
previousStatus: this.lastStatus
|
|
39542
39769
|
};
|
|
39543
39770
|
const ownsExternalHistory = !!this.adapter?.chatMessagesOwnedExternally;
|
|
39544
|
-
const
|
|
39545
|
-
|
|
39771
|
+
const meshWorkerSession = this.isMeshWorkerSession();
|
|
39772
|
+
const flushDelay = ownsExternalHistory ? meshWorkerSession ? NATIVE_HISTORY_MESH_IDLE_SETTLE_MS : 0 : 3e3;
|
|
39773
|
+
LOG.debug("CLI", `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} meshWorker=${meshWorkerSession} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
|
|
39546
39774
|
this.scheduleCompletedDebounceFlush(flushDelay);
|
|
39547
39775
|
}
|
|
39548
39776
|
} else if (newStatus === "idle" && this.lastStatus === "starting") {
|
|
@@ -42597,11 +42825,11 @@ var cliAgentHandlers = {
|
|
|
42597
42825
|
}
|
|
42598
42826
|
}
|
|
42599
42827
|
}
|
|
42600
|
-
const agentResult = await ctx.deps.cliManager.handleCliCommand("agent_command", args);
|
|
42601
42828
|
const meshCtx = args?.meshContext;
|
|
42602
42829
|
const dispatchNodeId = readStringValue(meshCtx?.nodeId);
|
|
42603
42830
|
const dispatchMeshId = readStringValue(meshCtx?.meshId);
|
|
42604
|
-
|
|
42831
|
+
const isSendChat = args?.action === "send_chat";
|
|
42832
|
+
if (isSendChat && dispatchNodeId && dispatchMeshId) {
|
|
42605
42833
|
try {
|
|
42606
42834
|
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
42607
42835
|
const meshObj = getMesh2(dispatchMeshId) ?? ctx.getCachedInlineMesh(dispatchMeshId);
|
|
@@ -42609,17 +42837,22 @@ var cliAgentHandlers = {
|
|
|
42609
42837
|
const bootstrapStatus = readStringValue(nodeObj?.worktreeBootstrap?.status);
|
|
42610
42838
|
if (bootstrapStatus === "running") {
|
|
42611
42839
|
return {
|
|
42612
|
-
success:
|
|
42613
|
-
|
|
42614
|
-
|
|
42615
|
-
|
|
42616
|
-
|
|
42840
|
+
success: false,
|
|
42841
|
+
recoverable: true,
|
|
42842
|
+
dispatched: false,
|
|
42843
|
+
code: "mesh_node_bootstrap_pending",
|
|
42844
|
+
reason: "bootstrap_still_running",
|
|
42845
|
+
nodeId: dispatchNodeId,
|
|
42846
|
+
meshId: dispatchMeshId,
|
|
42847
|
+
...readStringValue(meshCtx?.taskId) ? { taskId: readStringValue(meshCtx?.taskId) } : {},
|
|
42848
|
+
error: `Node '${dispatchNodeId}' worktree bootstrap is still running; a task injected now would land in the session input buffer before the provider is ready to consume it and be silently lost. Dispatch deferred.`,
|
|
42849
|
+
nextAction: "Wait for the worktree_bootstrap_complete event (or poll mesh_status until the node session is ready), then re-send the task with mesh_send_task. Alternatively use mesh_enqueue_task so the queue auto-assigns it once a ready session is available."
|
|
42617
42850
|
};
|
|
42618
42851
|
}
|
|
42619
42852
|
} catch {
|
|
42620
42853
|
}
|
|
42621
42854
|
}
|
|
42622
|
-
return
|
|
42855
|
+
return ctx.deps.cliManager.handleCliCommand("agent_command", args);
|
|
42623
42856
|
},
|
|
42624
42857
|
// ─── Logs ───
|
|
42625
42858
|
list_saved_sessions: async (ctx, args) => {
|
|
@@ -46871,7 +47104,7 @@ var meshCrudHandlers = {
|
|
|
46871
47104
|
return "";
|
|
46872
47105
|
}
|
|
46873
47106
|
})();
|
|
46874
|
-
const isCoordinatorBaseNode = !!selfDaemonId && (nodeDaemonId
|
|
47107
|
+
const isCoordinatorBaseNode = !!selfDaemonId && (daemonIdsEquivalent(nodeDaemonId, selfDaemonId) || daemonIdsEquivalent(nodeMachineId, selfDaemonId)) || !!selfMachineId && (daemonIdsEquivalent(nodeDaemonId, selfMachineId) || daemonIdsEquivalent(nodeMachineId, selfMachineId));
|
|
46875
47108
|
if (isCoordinatorBaseNode) {
|
|
46876
47109
|
return {
|
|
46877
47110
|
success: false,
|
|
@@ -47741,49 +47974,72 @@ var fastForwardHandlers = {
|
|
|
47741
47974
|
};
|
|
47742
47975
|
},
|
|
47743
47976
|
fast_forward_mesh_node: async (ctx, args) => {
|
|
47744
|
-
const
|
|
47745
|
-
const
|
|
47746
|
-
|
|
47747
|
-
|
|
47748
|
-
|
|
47749
|
-
|
|
47750
|
-
|
|
47751
|
-
|
|
47752
|
-
|
|
47753
|
-
|
|
47754
|
-
if (
|
|
47755
|
-
|
|
47977
|
+
const workspaceForError = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
47978
|
+
const meshIdForError = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
47979
|
+
const nodeIdForError = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
47980
|
+
try {
|
|
47981
|
+
const meshId = meshIdForError;
|
|
47982
|
+
const nodeId = nodeIdForError;
|
|
47983
|
+
let workspace = workspaceForError;
|
|
47984
|
+
let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
|
|
47985
|
+
let nodeDaemonId;
|
|
47986
|
+
let allowAutoPublishSubmoduleMainCommits = false;
|
|
47987
|
+
if (meshId && nodeId) {
|
|
47988
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
47989
|
+
const mesh = meshRecord?.mesh;
|
|
47990
|
+
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
47991
|
+
if (!workspace) {
|
|
47992
|
+
workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
|
|
47993
|
+
}
|
|
47994
|
+
if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
|
|
47995
|
+
submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
|
|
47996
|
+
}
|
|
47997
|
+
allowAutoPublishSubmoduleMainCommits = mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true;
|
|
47998
|
+
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
47756
47999
|
}
|
|
47757
|
-
|
|
47758
|
-
|
|
48000
|
+
const selfDaemonId = ctx.deps.statusInstanceId;
|
|
48001
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
48002
|
+
if (isRemote && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
48003
|
+
const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
48004
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
48005
|
+
workspace,
|
|
48006
|
+
_meshDirectDispatch: true
|
|
48007
|
+
});
|
|
48008
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
47759
48009
|
}
|
|
47760
|
-
|
|
47761
|
-
|
|
47762
|
-
|
|
47763
|
-
const selfDaemonId = ctx.deps.statusInstanceId;
|
|
47764
|
-
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
47765
|
-
if (isRemote && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
47766
|
-
const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
47767
|
-
...typeof args === "object" && args !== null ? args : {},
|
|
48010
|
+
const result = await fastForwardMeshNode({
|
|
48011
|
+
meshId: meshId || void 0,
|
|
48012
|
+
nodeId: nodeId || void 0,
|
|
47768
48013
|
workspace,
|
|
47769
|
-
|
|
48014
|
+
branch: typeof args?.branch === "string" ? args.branch : void 0,
|
|
48015
|
+
execute: args?.execute === true,
|
|
48016
|
+
dryRun: args?.dryRun === true,
|
|
48017
|
+
updateSubmodules: args?.updateSubmodules === true,
|
|
48018
|
+
submoduleIgnorePaths,
|
|
48019
|
+
mode: args?.mode === "push" ? "push" : "merge",
|
|
48020
|
+
pushSubmodules: args?.pushSubmodules === true,
|
|
48021
|
+
allowAutoPublishSubmoduleMainCommits
|
|
47770
48022
|
});
|
|
47771
|
-
return
|
|
48023
|
+
return result;
|
|
48024
|
+
} catch (e) {
|
|
48025
|
+
const errorMessage = e?.message || String(e);
|
|
48026
|
+
return {
|
|
48027
|
+
success: false,
|
|
48028
|
+
code: "fast_forward_safety_gate_error",
|
|
48029
|
+
...meshIdForError ? { meshId: meshIdForError } : {},
|
|
48030
|
+
...nodeIdForError ? { nodeId: nodeIdForError } : {},
|
|
48031
|
+
workspace: workspaceForError,
|
|
48032
|
+
mode: args?.mode === "push" ? "push" : "merge",
|
|
48033
|
+
allowed: false,
|
|
48034
|
+
willRun: false,
|
|
48035
|
+
executed: false,
|
|
48036
|
+
// Surface the throw as a blocking reason instead of an opaque IPC crash
|
|
48037
|
+
// so the coordinator gets the same structured shape a clean node returns.
|
|
48038
|
+
blockingReasons: ["fast_forward_safety_gate_error"],
|
|
48039
|
+
operationError: errorMessage,
|
|
48040
|
+
error: errorMessage
|
|
48041
|
+
};
|
|
47772
48042
|
}
|
|
47773
|
-
const result = await fastForwardMeshNode({
|
|
47774
|
-
meshId: meshId || void 0,
|
|
47775
|
-
nodeId: nodeId || void 0,
|
|
47776
|
-
workspace,
|
|
47777
|
-
branch: typeof args?.branch === "string" ? args.branch : void 0,
|
|
47778
|
-
execute: args?.execute === true,
|
|
47779
|
-
dryRun: args?.dryRun === true,
|
|
47780
|
-
updateSubmodules: args?.updateSubmodules === true,
|
|
47781
|
-
submoduleIgnorePaths,
|
|
47782
|
-
mode: args?.mode === "push" ? "push" : "merge",
|
|
47783
|
-
pushSubmodules: args?.pushSubmodules === true,
|
|
47784
|
-
allowAutoPublishSubmoduleMainCommits
|
|
47785
|
-
});
|
|
47786
|
-
return result;
|
|
47787
48043
|
},
|
|
47788
48044
|
refine_mesh_node: async (ctx, args) => {
|
|
47789
48045
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
@@ -47940,6 +48196,56 @@ var meshCoordinatorLaunchHandlers = {
|
|
|
47940
48196
|
return "";
|
|
47941
48197
|
}
|
|
47942
48198
|
};
|
|
48199
|
+
const buildRecentActivityBestEffort = async (id) => {
|
|
48200
|
+
try {
|
|
48201
|
+
const { getLedgerSummary: getLedgerSummary2, readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
48202
|
+
const { getMeshQueueStats: getMeshQueueStats2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
48203
|
+
const summary = getLedgerSummary2(id);
|
|
48204
|
+
const queue = getMeshQueueStats2(id);
|
|
48205
|
+
const failureEntries = readLedgerEntries2(id, { kind: ["task_failed"], tail: 5 });
|
|
48206
|
+
const recentFailures = failureEntries.map((e) => {
|
|
48207
|
+
const p = e.payload || {};
|
|
48208
|
+
const raw = typeof p.taskSummary === "string" ? p.taskSummary : typeof p.message === "string" ? p.message : typeof p.error === "string" ? p.error : "";
|
|
48209
|
+
const summaryText = raw.length > 160 ? `${raw.slice(0, 160)}\u2026` : raw;
|
|
48210
|
+
return {
|
|
48211
|
+
timestamp: e.timestamp,
|
|
48212
|
+
nodeId: e.nodeId,
|
|
48213
|
+
summary: summaryText
|
|
48214
|
+
};
|
|
48215
|
+
});
|
|
48216
|
+
return {
|
|
48217
|
+
recentFailures,
|
|
48218
|
+
recentFailureCount: summary.recentFailures,
|
|
48219
|
+
pendingTasks: queue.pending,
|
|
48220
|
+
assignedTasks: queue.assigned,
|
|
48221
|
+
stalledTasks: summary.taskStalled,
|
|
48222
|
+
lastActivityAt: summary.lastActivityAt
|
|
48223
|
+
};
|
|
48224
|
+
} catch {
|
|
48225
|
+
return void 0;
|
|
48226
|
+
}
|
|
48227
|
+
};
|
|
48228
|
+
const buildOperatingNotesBestEffort = async (id) => {
|
|
48229
|
+
try {
|
|
48230
|
+
const { readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
48231
|
+
const noteEntries = readLedgerEntries2(id, { kind: ["coordinator_operating_note"], tail: 20 });
|
|
48232
|
+
const notes = noteEntries.map((e) => {
|
|
48233
|
+
const p = e.payload || {};
|
|
48234
|
+
const text = typeof p.text === "string" ? p.text.trim() : "";
|
|
48235
|
+
if (!text) return null;
|
|
48236
|
+
const category = p.category === "provider_quirk" || p.category === "pattern_to_avoid" || p.category === "recovery_lesson" ? p.category : void 0;
|
|
48237
|
+
return {
|
|
48238
|
+
text,
|
|
48239
|
+
category,
|
|
48240
|
+
createdAt: typeof p.createdAt === "string" ? p.createdAt : e.timestamp,
|
|
48241
|
+
sourceCoordinator: typeof p.sourceCoordinator === "string" ? p.sourceCoordinator : void 0
|
|
48242
|
+
};
|
|
48243
|
+
}).filter((n) => n !== null);
|
|
48244
|
+
return notes.length ? notes : void 0;
|
|
48245
|
+
} catch {
|
|
48246
|
+
return void 0;
|
|
48247
|
+
}
|
|
48248
|
+
};
|
|
47943
48249
|
let mesh;
|
|
47944
48250
|
if (args?.inlineMesh && typeof args.inlineMesh === "object") {
|
|
47945
48251
|
mesh = args.inlineMesh;
|
|
@@ -48030,7 +48336,7 @@ var meshCoordinatorLaunchHandlers = {
|
|
|
48030
48336
|
if (coordinatorSetup.kind === "cli_command") {
|
|
48031
48337
|
let cliCmdSystemPrompt = "";
|
|
48032
48338
|
try {
|
|
48033
|
-
cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id) });
|
|
48339
|
+
cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildOperatingNotesBestEffort(mesh.id) });
|
|
48034
48340
|
} catch (error) {
|
|
48035
48341
|
const message = error?.message || String(error);
|
|
48036
48342
|
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
@@ -48207,7 +48513,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48207
48513
|
}
|
|
48208
48514
|
let systemPrompt = "";
|
|
48209
48515
|
try {
|
|
48210
|
-
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id) });
|
|
48516
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildOperatingNotesBestEffort(mesh.id) });
|
|
48211
48517
|
} catch (error) {
|
|
48212
48518
|
const message = error?.message || String(error);
|
|
48213
48519
|
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|