@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.mjs
CHANGED
|
@@ -311,10 +311,10 @@ function readInjected(value) {
|
|
|
311
311
|
}
|
|
312
312
|
function getDaemonBuildInfo() {
|
|
313
313
|
if (cached) return cached;
|
|
314
|
-
const commit = readInjected(true ? "
|
|
315
|
-
const commitShort = readInjected(true ? "
|
|
316
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
317
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
314
|
+
const commit = readInjected(true ? "b17fb9165bd52c9e2ab8cccf2ce80734e2165680" : void 0) ?? "unknown";
|
|
315
|
+
const commitShort = readInjected(true ? "b17fb916" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
316
|
+
const version = readInjected(true ? "0.9.82-rc.375" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
317
|
+
const builtAt = readInjected(true ? "2026-06-25T02:21:59.111Z" : void 0);
|
|
318
318
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
319
319
|
return cached;
|
|
320
320
|
}
|
|
@@ -3039,6 +3039,10 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
3039
3039
|
if (ctx.missionSection?.trim()) {
|
|
3040
3040
|
sections.push(ctx.missionSection.trim());
|
|
3041
3041
|
}
|
|
3042
|
+
const recentActivity = buildRecentActivitySection(ctx.recentActivity);
|
|
3043
|
+
if (recentActivity) sections.push(recentActivity);
|
|
3044
|
+
const operatingNotes = buildOperatingNotesSection(ctx.operatingNotes);
|
|
3045
|
+
if (operatingNotes) sections.push(operatingNotes);
|
|
3042
3046
|
sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
|
|
3043
3047
|
sections.push(TOOLS_SECTION);
|
|
3044
3048
|
sections.push(TOOL_EXPOSURE_PREFLIGHT_SECTION);
|
|
@@ -3070,6 +3074,8 @@ function expandPromptPlaceholders(template, ctx) {
|
|
|
3070
3074
|
cliType: coordinatorCliType || "",
|
|
3071
3075
|
nodes: nodesSection,
|
|
3072
3076
|
mission: ctx.missionSection?.trim() || "",
|
|
3077
|
+
recentActivity: buildRecentActivitySection(ctx.recentActivity) || "",
|
|
3078
|
+
operatingNotes: buildOperatingNotesSection(ctx.operatingNotes) || "",
|
|
3073
3079
|
policy: buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }),
|
|
3074
3080
|
tools: TOOLS_SECTION,
|
|
3075
3081
|
workflow: WORKFLOW_SECTION,
|
|
@@ -3141,6 +3147,56 @@ function indentFollowing(text, pad) {
|
|
|
3141
3147
|
if (lines.length === 1) return lines[0];
|
|
3142
3148
|
return [lines[0], ...lines.slice(1).map((l) => pad + l)].join("\n");
|
|
3143
3149
|
}
|
|
3150
|
+
function buildRecentActivitySection(activity) {
|
|
3151
|
+
if (!activity) return "";
|
|
3152
|
+
const failures = Array.isArray(activity.recentFailures) ? activity.recentFailures : [];
|
|
3153
|
+
const pending = Number.isFinite(activity.pendingTasks) ? Number(activity.pendingTasks) : 0;
|
|
3154
|
+
const assigned = Number.isFinite(activity.assignedTasks) ? Number(activity.assignedTasks) : 0;
|
|
3155
|
+
const stalled = Number.isFinite(activity.stalledTasks) ? Number(activity.stalledTasks) : 0;
|
|
3156
|
+
const recentFailureCount = Number.isFinite(activity.recentFailureCount) ? Number(activity.recentFailureCount) : failures.length;
|
|
3157
|
+
if (failures.length === 0 && pending === 0 && assigned === 0 && stalled === 0 && recentFailureCount === 0) {
|
|
3158
|
+
return "";
|
|
3159
|
+
}
|
|
3160
|
+
const lines = ["## Recent Activity", ""];
|
|
3161
|
+
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.");
|
|
3162
|
+
lines.push("");
|
|
3163
|
+
const counts = [];
|
|
3164
|
+
if (pending > 0) counts.push(`**${pending}** pending`);
|
|
3165
|
+
if (assigned > 0) counts.push(`**${assigned}** assigned`);
|
|
3166
|
+
if (stalled > 0) counts.push(`**${stalled}** stalled`);
|
|
3167
|
+
if (recentFailureCount > 0) counts.push(`**${recentFailureCount}** failed in the last 30 min`);
|
|
3168
|
+
if (counts.length) lines.push(`- Queue/ledger: ${counts.join(", ")}.`);
|
|
3169
|
+
if (activity.lastActivityAt) lines.push(`- Last ledger activity: ${activity.lastActivityAt}.`);
|
|
3170
|
+
if (failures.length > 0) {
|
|
3171
|
+
const recent = failures.slice(-5).reverse();
|
|
3172
|
+
lines.push("", "Recent failures (newest first):");
|
|
3173
|
+
for (const f of recent) {
|
|
3174
|
+
const when = f.timestamp ? `${f.timestamp} ` : "";
|
|
3175
|
+
const node = f.nodeId ? `node \`${f.nodeId}\`` : "unknown node";
|
|
3176
|
+
const summary = (f.summary || "").trim();
|
|
3177
|
+
lines.push(`- ${when}${node}${summary ? ` \u2014 ${summary}` : ""}`);
|
|
3178
|
+
}
|
|
3179
|
+
lines.push("", "_Check `mesh_task_history` before retrying; repeated failures on the same node mean reassign or escalate, not retry._");
|
|
3180
|
+
}
|
|
3181
|
+
return lines.join("\n");
|
|
3182
|
+
}
|
|
3183
|
+
function buildOperatingNotesSection(notes) {
|
|
3184
|
+
const valid = Array.isArray(notes) ? notes.filter((n) => n && typeof n.text === "string" && n.text.trim()) : [];
|
|
3185
|
+
if (valid.length === 0) return "";
|
|
3186
|
+
const categoryLabel = {
|
|
3187
|
+
provider_quirk: "provider quirk",
|
|
3188
|
+
pattern_to_avoid: "pattern to avoid",
|
|
3189
|
+
recovery_lesson: "recovery lesson"
|
|
3190
|
+
};
|
|
3191
|
+
const lines = ["## Operating Notes", ""];
|
|
3192
|
+
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.");
|
|
3193
|
+
lines.push("");
|
|
3194
|
+
for (const n of valid) {
|
|
3195
|
+
const cat = n.category && categoryLabel[n.category] ? `[${categoryLabel[n.category]}] ` : "";
|
|
3196
|
+
lines.push(`- ${cat}${n.text.trim()}`);
|
|
3197
|
+
}
|
|
3198
|
+
return lines.join("\n");
|
|
3199
|
+
}
|
|
3144
3200
|
function buildPolicySection(policy) {
|
|
3145
3201
|
const rules = [];
|
|
3146
3202
|
if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
|
|
@@ -3201,6 +3257,7 @@ var init_coordinator_prompt = __esm({
|
|
|
3201
3257
|
| \`mesh_read_chat\` | Read recent chat messages from a delegated agent session |
|
|
3202
3258
|
| \`mesh_read_debug\` | Collect a daemon-side chat/parser debug bundle for a session |
|
|
3203
3259
|
| \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
|
|
3260
|
+
| \`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 |
|
|
3204
3261
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
3205
3262
|
| \`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 |
|
|
3206
3263
|
| \`mesh_fast_forward_node\` | Safely dry-run or explicitly execute an obvious clean fast-forward without launching an agent session |
|
|
@@ -8742,7 +8799,7 @@ var init_mesh_events_utils = __esm({
|
|
|
8742
8799
|
"src/mesh/mesh-events-utils.ts"() {
|
|
8743
8800
|
"use strict";
|
|
8744
8801
|
MESH_SURFACED_PREVIEW_MAX_CHARS = 512;
|
|
8745
|
-
MESH_COMPLETION_SURFACE_MAX_CHARS =
|
|
8802
|
+
MESH_COMPLETION_SURFACE_MAX_CHARS = 16e3;
|
|
8746
8803
|
}
|
|
8747
8804
|
});
|
|
8748
8805
|
|
|
@@ -9382,6 +9439,22 @@ function isWeakCompletionLedgerPayload(payload) {
|
|
|
9382
9439
|
const diag = readRecord4(payload.completionDiagnostic);
|
|
9383
9440
|
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
9384
9441
|
}
|
|
9442
|
+
function findTerminalLedgerEvidenceForTask(args) {
|
|
9443
|
+
const taskId = readNonEmptyString2(args.taskId);
|
|
9444
|
+
if (!taskId) return null;
|
|
9445
|
+
const entries = readLedgerEntries(args.meshId, { tail: args.tail ?? 500 });
|
|
9446
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
9447
|
+
const entry = entries[i];
|
|
9448
|
+
if (entry.kind !== "task_completed" && entry.kind !== "task_failed" && entry.kind !== "task_stalled") continue;
|
|
9449
|
+
const terminalTaskId = readNonEmptyString2(entry.payload?.taskId);
|
|
9450
|
+
if (terminalTaskId !== taskId) continue;
|
|
9451
|
+
if (entry.kind === "task_completed" && isWeakCompletionLedgerPayload(entry.payload)) continue;
|
|
9452
|
+
if (args.sessionId && entry.sessionId && entry.sessionId !== args.sessionId) continue;
|
|
9453
|
+
if (!args.sessionId && args.nodeId && entry.nodeId && !meshNodeIdMatches(entry, args.nodeId)) continue;
|
|
9454
|
+
return { id: entry.id, kind: entry.kind, payload: entry.payload || {}, timestamp: entry.timestamp };
|
|
9455
|
+
}
|
|
9456
|
+
return null;
|
|
9457
|
+
}
|
|
9385
9458
|
function findDirectDispatchLedgerEntry(args) {
|
|
9386
9459
|
const entries = readLedgerEntries(args.meshId, { tail: 500 });
|
|
9387
9460
|
for (let i = entries.length - 1; i >= 0; i--) {
|
|
@@ -11512,7 +11585,7 @@ var init_chat_message_normalization = __esm({
|
|
|
11512
11585
|
"src/providers/chat-message-normalization.ts"() {
|
|
11513
11586
|
"use strict";
|
|
11514
11587
|
init_contracts();
|
|
11515
|
-
DEFAULT_FINAL_SUMMARY_MAX_CHARS =
|
|
11588
|
+
DEFAULT_FINAL_SUMMARY_MAX_CHARS = 16e3;
|
|
11516
11589
|
BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
|
|
11517
11590
|
CHAT_MESSAGE_VISIBILITIES = ["user", "debug", "internal", "hidden"];
|
|
11518
11591
|
CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES = ["visible", "chat", "user", "debug", "internal", "hidden"];
|
|
@@ -12920,6 +12993,18 @@ function isWeakTerminalLedgerPayload(payload) {
|
|
|
12920
12993
|
const diag = readRecord4(payload.completionDiagnostic);
|
|
12921
12994
|
return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
|
|
12922
12995
|
}
|
|
12996
|
+
function supersedesTruncatedTerminalSummary(args) {
|
|
12997
|
+
if (!args.terminalTaskId || !args.eventTaskId || args.terminalTaskId !== args.eventTaskId) return false;
|
|
12998
|
+
if (!isGenuineCompletionEvidence(args.metadataEvent)) return false;
|
|
12999
|
+
const terminalSummary = readNonEmptyString2(args.terminalPayload.finalSummary);
|
|
13000
|
+
const eventSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
|
|
13001
|
+
if (!eventSummary) return false;
|
|
13002
|
+
if (terminalSummary === eventSummary) return false;
|
|
13003
|
+
if (isWeakTerminalLedgerPayload(args.terminalPayload)) return false;
|
|
13004
|
+
if (!terminalSummary) return true;
|
|
13005
|
+
if (eventSummary.startsWith(terminalSummary)) return true;
|
|
13006
|
+
return eventSummary.length > terminalSummary.length + 32;
|
|
13007
|
+
}
|
|
12923
13008
|
function resolveActiveDirectDispatchTaskId(meshId, sessionId) {
|
|
12924
13009
|
try {
|
|
12925
13010
|
const matches = getActiveDirectDispatches(meshId).filter((d) => d.sessionId === sessionId);
|
|
@@ -13029,6 +13114,23 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
13029
13114
|
if (!task) {
|
|
13030
13115
|
return false;
|
|
13031
13116
|
}
|
|
13117
|
+
const terminal = findTerminalLedgerEvidenceForTask({
|
|
13118
|
+
meshId,
|
|
13119
|
+
taskId: task.id
|
|
13120
|
+
});
|
|
13121
|
+
if (terminal) {
|
|
13122
|
+
const status = terminal.kind === "task_completed" ? "completed" : "failed";
|
|
13123
|
+
updateTaskStatus(meshId, task.id, status);
|
|
13124
|
+
LOG.info("MeshQueue", `Skipped dispatch for terminal task ${task.id} on mesh ${meshId}; ${terminal.kind} ledger evidence already exists`);
|
|
13125
|
+
traceMeshEventDrop("dispatch_terminal_ledger", {
|
|
13126
|
+
taskId: task.id,
|
|
13127
|
+
sessionId,
|
|
13128
|
+
nodeId,
|
|
13129
|
+
meshId,
|
|
13130
|
+
event: "agent_command"
|
|
13131
|
+
}, terminal.kind);
|
|
13132
|
+
return false;
|
|
13133
|
+
}
|
|
13032
13134
|
LOG.info("MeshQueue", `Node ${nodeId} (${sessionId}) pulled task ${task.id}`);
|
|
13033
13135
|
if (node?.daemonId && components.dispatchMeshCommand) {
|
|
13034
13136
|
const isLocalNode = components.cliManager.adapters.has(sessionId);
|
|
@@ -13819,7 +13921,13 @@ function evaluateMeshEventSuppression(args, ctx) {
|
|
|
13819
13921
|
const terminalTaskId = readNonEmptyString2(terminal.payload.taskId);
|
|
13820
13922
|
const eventTaskId = readNonEmptyString2(args.metadataEvent.taskId);
|
|
13821
13923
|
const distinctTaskCompletion = !!eventTaskId && !!terminalTaskId && eventTaskId !== terminalTaskId;
|
|
13822
|
-
|
|
13924
|
+
const supersedesTruncatedTerminal = supersedesTruncatedTerminalSummary({
|
|
13925
|
+
terminalPayload: terminal.payload,
|
|
13926
|
+
metadataEvent: args.metadataEvent,
|
|
13927
|
+
terminalTaskId,
|
|
13928
|
+
eventTaskId
|
|
13929
|
+
});
|
|
13930
|
+
if (!newDispatchAfterTerminal && !supersedesWeakTerminal && !distinctTaskCompletion && !supersedesTruncatedTerminal) {
|
|
13823
13931
|
const terminalProviderSessionId = readNonEmptyString2(terminal.payload.providerSessionId);
|
|
13824
13932
|
const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
|
|
13825
13933
|
const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
|
|
@@ -14565,20 +14673,24 @@ function daemonHostsMesh(mesh, daemonIds) {
|
|
|
14565
14673
|
if (host.role && host.role !== "host") return false;
|
|
14566
14674
|
const hostDaemonId = readNonEmptyString2(host.hostDaemonId);
|
|
14567
14675
|
if (!hostDaemonId) return true;
|
|
14568
|
-
return daemonIds
|
|
14676
|
+
return daemonIdListIncludes(daemonIds, hostDaemonId);
|
|
14677
|
+
}
|
|
14678
|
+
function daemonIdListIncludes(ids, id) {
|
|
14679
|
+
if (!id) return false;
|
|
14680
|
+
return ids.some((candidate) => candidate === id || daemonIdsEquivalent(candidate, id));
|
|
14569
14681
|
}
|
|
14570
14682
|
function resolveCoordinatorSelfIds(mesh, drainDaemonIds) {
|
|
14571
14683
|
const ids = new Set(drainDaemonIds);
|
|
14572
14684
|
for (const node of mesh.nodes) {
|
|
14573
14685
|
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
14574
14686
|
const nodeMachineId = readNonEmptyString2(node.machineId);
|
|
14575
|
-
const isSelf = nodeDaemonId && drainDaemonIds
|
|
14687
|
+
const isSelf = nodeDaemonId && daemonIdListIncludes(drainDaemonIds, nodeDaemonId) || nodeMachineId && daemonIdListIncludes(drainDaemonIds, nodeMachineId);
|
|
14576
14688
|
if (!isSelf) continue;
|
|
14577
14689
|
if (nodeDaemonId) ids.add(nodeDaemonId);
|
|
14578
14690
|
if (nodeMachineId) ids.add(nodeMachineId);
|
|
14579
14691
|
}
|
|
14580
14692
|
const hostDaemonId = readNonEmptyString2(mesh.meshHost?.hostDaemonId);
|
|
14581
|
-
if (hostDaemonId && ids
|
|
14693
|
+
if (hostDaemonId && daemonIdListIncludes([...ids], hostDaemonId)) ids.add(hostDaemonId);
|
|
14582
14694
|
return [...ids];
|
|
14583
14695
|
}
|
|
14584
14696
|
function findLiveCoordinators(components) {
|
|
@@ -14591,6 +14703,16 @@ function findLiveCoordinators(components) {
|
|
|
14591
14703
|
const status = readNonEmptyString2(state.status).toLowerCase();
|
|
14592
14704
|
const modalParked = status === "waiting_choice" || status === "waiting_approval";
|
|
14593
14705
|
const sessionId = readNonEmptyString2(state.instanceId);
|
|
14706
|
+
const stateKey = `${meshId}::${sessionId || "?"}`;
|
|
14707
|
+
const prevParked = coordinatorModalParkState.get(stateKey);
|
|
14708
|
+
if (prevParked !== modalParked) {
|
|
14709
|
+
coordinatorModalParkState.set(stateKey, modalParked);
|
|
14710
|
+
if (modalParked) {
|
|
14711
|
+
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`);
|
|
14712
|
+
} else if (prevParked === true) {
|
|
14713
|
+
LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) left modal-park (status=${status}) \u2014 held events will drain on this/next tick`);
|
|
14714
|
+
}
|
|
14715
|
+
}
|
|
14594
14716
|
out.push({ meshId, instance: inst, sessionId, idle: status === "idle", modalParked });
|
|
14595
14717
|
}
|
|
14596
14718
|
return out;
|
|
@@ -14656,6 +14778,23 @@ function recoverStrandedAssignedDispatches(meshId, store) {
|
|
|
14656
14778
|
const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
|
|
14657
14779
|
if (!Number.isFinite(dispatchedAtMs)) continue;
|
|
14658
14780
|
if (nowMs - dispatchedAtMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
|
|
14781
|
+
const terminal = findTerminalLedgerEvidenceForTask({
|
|
14782
|
+
meshId,
|
|
14783
|
+
taskId: row.id
|
|
14784
|
+
});
|
|
14785
|
+
if (terminal) {
|
|
14786
|
+
const status = terminal.kind === "task_completed" ? "completed" : "failed";
|
|
14787
|
+
updateTaskStatus(meshId, row.id, status);
|
|
14788
|
+
LOG.warn("MeshReconcile", `Skipped stranded reclaim redispatch for terminal task ${row.id} on mesh ${meshId}; ${terminal.kind} ledger evidence already exists`);
|
|
14789
|
+
traceMeshEventDrop("assigned_stranded_terminal_ledger", {
|
|
14790
|
+
taskId: row.id,
|
|
14791
|
+
sessionId: row.assignedSessionId,
|
|
14792
|
+
nodeId: row.assignedNodeId,
|
|
14793
|
+
meshId,
|
|
14794
|
+
event: "agent:generating_completed"
|
|
14795
|
+
}, terminal.kind);
|
|
14796
|
+
continue;
|
|
14797
|
+
}
|
|
14659
14798
|
if (store.taskHasConfirmedDelivery(meshId, row.id)) continue;
|
|
14660
14799
|
const reclaimed = reclaimStrandedAssignedTask(meshId, row.id, {
|
|
14661
14800
|
reason: "assigned_stranded_dispatch_unconfirmed",
|
|
@@ -14767,7 +14906,55 @@ async function runMeshReconcileTick(components) {
|
|
|
14767
14906
|
const forceOnly = idleCoordinators.length === 0;
|
|
14768
14907
|
if (targetCoordinators.length === 0) {
|
|
14769
14908
|
if (modalParkedCoordinators.length > 0) {
|
|
14770
|
-
|
|
14909
|
+
const liveSessionIds = new Set(
|
|
14910
|
+
meshCoordinators.map((c) => readNonEmptyString2(c.sessionId)).filter(Boolean)
|
|
14911
|
+
);
|
|
14912
|
+
let orphanEscaped = 0;
|
|
14913
|
+
const hasPendingForOrphanPeek = !store || (() => {
|
|
14914
|
+
try {
|
|
14915
|
+
return store.pendingEventCount(meshId) > 0;
|
|
14916
|
+
} catch {
|
|
14917
|
+
return true;
|
|
14918
|
+
}
|
|
14919
|
+
})();
|
|
14920
|
+
if (hasPendingForOrphanPeek) {
|
|
14921
|
+
let peeked = [];
|
|
14922
|
+
try {
|
|
14923
|
+
peeked = getPendingMeshCoordinatorEvents(meshId, drainDaemonIds.length > 0 ? drainDaemonIds : void 0);
|
|
14924
|
+
} catch {
|
|
14925
|
+
peeked = [];
|
|
14926
|
+
}
|
|
14927
|
+
const isOrphan = (e) => {
|
|
14928
|
+
const want = readNonEmptyString2(e.targetCoordinatorSessionId);
|
|
14929
|
+
return !!want && !liveSessionIds.has(want);
|
|
14930
|
+
};
|
|
14931
|
+
const orphanEventNames = new Set(peeked.filter(isOrphan).map((e) => e.event));
|
|
14932
|
+
if (orphanEventNames.size > 0) {
|
|
14933
|
+
let drained = [];
|
|
14934
|
+
try {
|
|
14935
|
+
drained = drainPendingMeshCoordinatorEvents(
|
|
14936
|
+
meshId,
|
|
14937
|
+
drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId,
|
|
14938
|
+
{ onlyEvents: orphanEventNames }
|
|
14939
|
+
);
|
|
14940
|
+
} catch (e) {
|
|
14941
|
+
LOG.warn("MeshReconcile", `Orphan-escape drain failed for mesh ${meshId}: ${e?.message || e}`);
|
|
14942
|
+
drained = [];
|
|
14943
|
+
}
|
|
14944
|
+
for (const pending of drained) {
|
|
14945
|
+
if (isOrphan(pending)) {
|
|
14946
|
+
holdOrExpireStrictUnmatchedEvent(pending, readNonEmptyString2(pending.targetCoordinatorSessionId), meshId);
|
|
14947
|
+
orphanEscaped++;
|
|
14948
|
+
} else {
|
|
14949
|
+
try {
|
|
14950
|
+
queuePendingMeshCoordinatorEvent(pending);
|
|
14951
|
+
} catch {
|
|
14952
|
+
}
|
|
14953
|
+
}
|
|
14954
|
+
}
|
|
14955
|
+
}
|
|
14956
|
+
}
|
|
14957
|
+
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` : ""})`);
|
|
14771
14958
|
let hasPending = true;
|
|
14772
14959
|
if (store) {
|
|
14773
14960
|
try {
|
|
@@ -14952,7 +15139,7 @@ async function pullRemoteNodeQueues(components, mesh, localDaemonId, candidateDa
|
|
|
14952
15139
|
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
14953
15140
|
if (!nodeDaemonId) continue;
|
|
14954
15141
|
if (daemonIdsEquivalent(nodeDaemonId, localDaemonId)) continue;
|
|
14955
|
-
if (candidateDaemonIds
|
|
15142
|
+
if (daemonIdListIncludes(candidateDaemonIds, nodeDaemonId)) continue;
|
|
14956
15143
|
for (const pendingEventArgs of pulls) {
|
|
14957
15144
|
let events;
|
|
14958
15145
|
try {
|
|
@@ -15008,7 +15195,7 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
15008
15195
|
if (!sessionId || !nodeId || !taskId) continue;
|
|
15009
15196
|
const node = nodeById.get(nodeId);
|
|
15010
15197
|
const nodeDaemonId = readNonEmptyString2(node?.daemonId);
|
|
15011
|
-
const isLocalNode = !nodeDaemonId || selfIds
|
|
15198
|
+
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId) || !!components.instanceManager.getInstance(sessionId);
|
|
15012
15199
|
const providerType = readNonEmptyString2(dispatch.providerType);
|
|
15013
15200
|
const readArgs = {
|
|
15014
15201
|
sessionId,
|
|
@@ -15038,6 +15225,19 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
|
|
|
15038
15225
|
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
15039
15226
|
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
15040
15227
|
if (!evidence.finalSummary) continue;
|
|
15228
|
+
const dispatchedAtMs = Date.parse(readNonEmptyString2(dispatch.dispatchedAt));
|
|
15229
|
+
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
|
|
15230
|
+
if (Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs < dispatchedAtMs) {
|
|
15231
|
+
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`);
|
|
15232
|
+
traceMeshEventDrop("reconcile_stale_summary_before_dispatch", {
|
|
15233
|
+
taskId,
|
|
15234
|
+
sessionId,
|
|
15235
|
+
nodeId,
|
|
15236
|
+
meshId: mesh.id,
|
|
15237
|
+
event: "agent:generating_completed"
|
|
15238
|
+
}, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
|
|
15239
|
+
continue;
|
|
15240
|
+
}
|
|
15041
15241
|
const providerSessionId = readNonEmptyString2(payload.providerSessionId);
|
|
15042
15242
|
const coordinatorDaemonId = selfIds.find((id) => !!id);
|
|
15043
15243
|
try {
|
|
@@ -15083,7 +15283,7 @@ async function collectLiveNodesWithSessions(components, mesh, selfIds, localDaem
|
|
|
15083
15283
|
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
15084
15284
|
return Promise.all(mesh.nodes.map(async (node) => {
|
|
15085
15285
|
const nodeDaemonId = readNonEmptyString2(node.daemonId);
|
|
15086
|
-
const isLocalNode = !nodeDaemonId || selfIds
|
|
15286
|
+
const isLocalNode = !nodeDaemonId || daemonIdListIncludes(selfIds, nodeDaemonId) || daemonIdsEquivalent(nodeDaemonId, localDaemonId);
|
|
15087
15287
|
let statusResult;
|
|
15088
15288
|
try {
|
|
15089
15289
|
if (isLocalNode) {
|
|
@@ -15165,7 +15365,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
15165
15365
|
}
|
|
15166
15366
|
};
|
|
15167
15367
|
}
|
|
15168
|
-
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;
|
|
15368
|
+
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;
|
|
15169
15369
|
var init_mesh_reconcile_loop = __esm({
|
|
15170
15370
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
15171
15371
|
"use strict";
|
|
@@ -15187,6 +15387,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
15187
15387
|
init_chat_message_normalization();
|
|
15188
15388
|
DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
|
|
15189
15389
|
DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
|
|
15390
|
+
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
15190
15391
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
15191
15392
|
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
15192
15393
|
STRICT_SESSION_MATCH_TTL_MS = 6e4;
|
|
@@ -37756,6 +37957,8 @@ function getMessageTime(message) {
|
|
|
37756
37957
|
}
|
|
37757
37958
|
var COMPLETED_FINALIZATION_RETRY_MS = 1e3;
|
|
37758
37959
|
var COMPLETED_FINALIZATION_MAX_WAIT_MS = 3e4;
|
|
37960
|
+
var NATIVE_HISTORY_MESH_IDLE_SETTLE_MS = 1500;
|
|
37961
|
+
var USER_INPUT_ACK_DEDUP_WINDOW_MS = 6e4;
|
|
37759
37962
|
var TERMINAL_MESH_EVENTS = /* @__PURE__ */ new Set([
|
|
37760
37963
|
"agent:generating_completed",
|
|
37761
37964
|
"agent:stopped",
|
|
@@ -38027,6 +38230,14 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
38027
38230
|
runtimeMessages = [];
|
|
38028
38231
|
lastPersistedHistoryMessages = [];
|
|
38029
38232
|
lastAcknowledgedUserInputAt = 0;
|
|
38233
|
+
// TASKBUBBLE-DUP: per-content last-ack timestamps so the same dispatched
|
|
38234
|
+
// prompt acked twice in quick succession (the worker buffers the first
|
|
38235
|
+
// send during bootstrap/busy, then a redelivery — dispatch-confirm-timeout
|
|
38236
|
+
// requeue or a reconcile re-dispatch — fires a SECOND send_chat before the
|
|
38237
|
+
// outbound queue drains) collapses to ONE user bubble. Keyed on the trimmed
|
|
38238
|
+
// content; an entry older than USER_INPUT_ACK_DEDUP_WINDOW_MS is treated as
|
|
38239
|
+
// a fresh, intentional resend and is NOT suppressed.
|
|
38240
|
+
recentUserInputAcks = /* @__PURE__ */ new Map();
|
|
38030
38241
|
lastNativeSourceCanonicalCheckAt = 0;
|
|
38031
38242
|
lastNativeSourceCanonicalCacheKey = void 0;
|
|
38032
38243
|
cachedSqliteDb = null;
|
|
@@ -38461,6 +38672,15 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
38461
38672
|
const content = typeof input === "string" ? input.trim() : buildCliStructuredInputPrompt(input).trim();
|
|
38462
38673
|
if (!content) return;
|
|
38463
38674
|
const receivedAt = Date.now();
|
|
38675
|
+
const ackContentKey = shortHash(`${this.instanceId}:${content}`, 24);
|
|
38676
|
+
const lastAckAt = this.recentUserInputAcks.get(ackContentKey);
|
|
38677
|
+
if (lastAckAt !== void 0 && receivedAt - lastAckAt <= USER_INPUT_ACK_DEDUP_WINDOW_MS) {
|
|
38678
|
+
this.recentUserInputAcks.set(ackContentKey, receivedAt);
|
|
38679
|
+
this.pruneRecentUserInputAcks(receivedAt);
|
|
38680
|
+
return;
|
|
38681
|
+
}
|
|
38682
|
+
this.recentUserInputAcks.set(ackContentKey, receivedAt);
|
|
38683
|
+
this.pruneRecentUserInputAcks(receivedAt);
|
|
38464
38684
|
this.lastAcknowledgedUserInputAt = receivedAt;
|
|
38465
38685
|
const dedupKey = `user_input_ack:${shortHash(`${this.instanceId}:${content}:${receivedAt}`, 24)}`;
|
|
38466
38686
|
this.appendRuntimeMessage(buildChatMessage({
|
|
@@ -38478,6 +38698,13 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
38478
38698
|
}
|
|
38479
38699
|
}), dedupKey);
|
|
38480
38700
|
}
|
|
38701
|
+
/** Drop user-input ack entries older than the dedup window so the map can't grow unbounded. */
|
|
38702
|
+
pruneRecentUserInputAcks(now) {
|
|
38703
|
+
if (this.recentUserInputAcks.size <= 1) return;
|
|
38704
|
+
for (const [key, at] of this.recentUserInputAcks) {
|
|
38705
|
+
if (now - at > USER_INPUT_ACK_DEDUP_WINDOW_MS) this.recentUserInputAcks.delete(key);
|
|
38706
|
+
}
|
|
38707
|
+
}
|
|
38481
38708
|
dispose() {
|
|
38482
38709
|
this.adapter.shutdown();
|
|
38483
38710
|
this.monitor.reset();
|
|
@@ -39167,8 +39394,9 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
39167
39394
|
previousStatus: this.lastStatus
|
|
39168
39395
|
};
|
|
39169
39396
|
const ownsExternalHistory = !!this.adapter?.chatMessagesOwnedExternally;
|
|
39170
|
-
const
|
|
39171
|
-
|
|
39397
|
+
const meshWorkerSession = this.isMeshWorkerSession();
|
|
39398
|
+
const flushDelay = ownsExternalHistory ? meshWorkerSession ? NATIVE_HISTORY_MESH_IDLE_SETTLE_MS : 0 : 3e3;
|
|
39399
|
+
LOG.debug("CLI", `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} meshWorker=${meshWorkerSession} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
|
|
39172
39400
|
this.scheduleCompletedDebounceFlush(flushDelay);
|
|
39173
39401
|
}
|
|
39174
39402
|
} else if (newStatus === "idle" && this.lastStatus === "starting") {
|
|
@@ -42228,11 +42456,11 @@ var cliAgentHandlers = {
|
|
|
42228
42456
|
}
|
|
42229
42457
|
}
|
|
42230
42458
|
}
|
|
42231
|
-
const agentResult = await ctx.deps.cliManager.handleCliCommand("agent_command", args);
|
|
42232
42459
|
const meshCtx = args?.meshContext;
|
|
42233
42460
|
const dispatchNodeId = readStringValue(meshCtx?.nodeId);
|
|
42234
42461
|
const dispatchMeshId = readStringValue(meshCtx?.meshId);
|
|
42235
|
-
|
|
42462
|
+
const isSendChat = args?.action === "send_chat";
|
|
42463
|
+
if (isSendChat && dispatchNodeId && dispatchMeshId) {
|
|
42236
42464
|
try {
|
|
42237
42465
|
const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
42238
42466
|
const meshObj = getMesh2(dispatchMeshId) ?? ctx.getCachedInlineMesh(dispatchMeshId);
|
|
@@ -42240,17 +42468,22 @@ var cliAgentHandlers = {
|
|
|
42240
42468
|
const bootstrapStatus = readStringValue(nodeObj?.worktreeBootstrap?.status);
|
|
42241
42469
|
if (bootstrapStatus === "running") {
|
|
42242
42470
|
return {
|
|
42243
|
-
success:
|
|
42244
|
-
|
|
42245
|
-
|
|
42246
|
-
|
|
42247
|
-
|
|
42471
|
+
success: false,
|
|
42472
|
+
recoverable: true,
|
|
42473
|
+
dispatched: false,
|
|
42474
|
+
code: "mesh_node_bootstrap_pending",
|
|
42475
|
+
reason: "bootstrap_still_running",
|
|
42476
|
+
nodeId: dispatchNodeId,
|
|
42477
|
+
meshId: dispatchMeshId,
|
|
42478
|
+
...readStringValue(meshCtx?.taskId) ? { taskId: readStringValue(meshCtx?.taskId) } : {},
|
|
42479
|
+
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.`,
|
|
42480
|
+
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."
|
|
42248
42481
|
};
|
|
42249
42482
|
}
|
|
42250
42483
|
} catch {
|
|
42251
42484
|
}
|
|
42252
42485
|
}
|
|
42253
|
-
return
|
|
42486
|
+
return ctx.deps.cliManager.handleCliCommand("agent_command", args);
|
|
42254
42487
|
},
|
|
42255
42488
|
// ─── Logs ───
|
|
42256
42489
|
list_saved_sessions: async (ctx, args) => {
|
|
@@ -46502,7 +46735,7 @@ var meshCrudHandlers = {
|
|
|
46502
46735
|
return "";
|
|
46503
46736
|
}
|
|
46504
46737
|
})();
|
|
46505
|
-
const isCoordinatorBaseNode = !!selfDaemonId && (nodeDaemonId
|
|
46738
|
+
const isCoordinatorBaseNode = !!selfDaemonId && (daemonIdsEquivalent(nodeDaemonId, selfDaemonId) || daemonIdsEquivalent(nodeMachineId, selfDaemonId)) || !!selfMachineId && (daemonIdsEquivalent(nodeDaemonId, selfMachineId) || daemonIdsEquivalent(nodeMachineId, selfMachineId));
|
|
46506
46739
|
if (isCoordinatorBaseNode) {
|
|
46507
46740
|
return {
|
|
46508
46741
|
success: false,
|
|
@@ -47372,49 +47605,72 @@ var fastForwardHandlers = {
|
|
|
47372
47605
|
};
|
|
47373
47606
|
},
|
|
47374
47607
|
fast_forward_mesh_node: async (ctx, args) => {
|
|
47375
|
-
const
|
|
47376
|
-
const
|
|
47377
|
-
|
|
47378
|
-
|
|
47379
|
-
|
|
47380
|
-
|
|
47381
|
-
|
|
47382
|
-
|
|
47383
|
-
|
|
47384
|
-
|
|
47385
|
-
if (
|
|
47386
|
-
|
|
47608
|
+
const workspaceForError = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
47609
|
+
const meshIdForError = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
47610
|
+
const nodeIdForError = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
47611
|
+
try {
|
|
47612
|
+
const meshId = meshIdForError;
|
|
47613
|
+
const nodeId = nodeIdForError;
|
|
47614
|
+
let workspace = workspaceForError;
|
|
47615
|
+
let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
|
|
47616
|
+
let nodeDaemonId;
|
|
47617
|
+
let allowAutoPublishSubmoduleMainCommits = false;
|
|
47618
|
+
if (meshId && nodeId) {
|
|
47619
|
+
const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
47620
|
+
const mesh = meshRecord?.mesh;
|
|
47621
|
+
const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
47622
|
+
if (!workspace) {
|
|
47623
|
+
workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
|
|
47624
|
+
}
|
|
47625
|
+
if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
|
|
47626
|
+
submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
|
|
47627
|
+
}
|
|
47628
|
+
allowAutoPublishSubmoduleMainCommits = mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true;
|
|
47629
|
+
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
47387
47630
|
}
|
|
47388
|
-
|
|
47389
|
-
|
|
47631
|
+
const selfDaemonId = ctx.deps.statusInstanceId;
|
|
47632
|
+
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
47633
|
+
if (isRemote && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
47634
|
+
const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
47635
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
47636
|
+
workspace,
|
|
47637
|
+
_meshDirectDispatch: true
|
|
47638
|
+
});
|
|
47639
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
47390
47640
|
}
|
|
47391
|
-
|
|
47392
|
-
|
|
47393
|
-
|
|
47394
|
-
const selfDaemonId = ctx.deps.statusInstanceId;
|
|
47395
|
-
const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
|
|
47396
|
-
if (isRemote && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
47397
|
-
const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
|
|
47398
|
-
...typeof args === "object" && args !== null ? args : {},
|
|
47641
|
+
const result = await fastForwardMeshNode({
|
|
47642
|
+
meshId: meshId || void 0,
|
|
47643
|
+
nodeId: nodeId || void 0,
|
|
47399
47644
|
workspace,
|
|
47400
|
-
|
|
47645
|
+
branch: typeof args?.branch === "string" ? args.branch : void 0,
|
|
47646
|
+
execute: args?.execute === true,
|
|
47647
|
+
dryRun: args?.dryRun === true,
|
|
47648
|
+
updateSubmodules: args?.updateSubmodules === true,
|
|
47649
|
+
submoduleIgnorePaths,
|
|
47650
|
+
mode: args?.mode === "push" ? "push" : "merge",
|
|
47651
|
+
pushSubmodules: args?.pushSubmodules === true,
|
|
47652
|
+
allowAutoPublishSubmoduleMainCommits
|
|
47401
47653
|
});
|
|
47402
|
-
return
|
|
47654
|
+
return result;
|
|
47655
|
+
} catch (e) {
|
|
47656
|
+
const errorMessage = e?.message || String(e);
|
|
47657
|
+
return {
|
|
47658
|
+
success: false,
|
|
47659
|
+
code: "fast_forward_safety_gate_error",
|
|
47660
|
+
...meshIdForError ? { meshId: meshIdForError } : {},
|
|
47661
|
+
...nodeIdForError ? { nodeId: nodeIdForError } : {},
|
|
47662
|
+
workspace: workspaceForError,
|
|
47663
|
+
mode: args?.mode === "push" ? "push" : "merge",
|
|
47664
|
+
allowed: false,
|
|
47665
|
+
willRun: false,
|
|
47666
|
+
executed: false,
|
|
47667
|
+
// Surface the throw as a blocking reason instead of an opaque IPC crash
|
|
47668
|
+
// so the coordinator gets the same structured shape a clean node returns.
|
|
47669
|
+
blockingReasons: ["fast_forward_safety_gate_error"],
|
|
47670
|
+
operationError: errorMessage,
|
|
47671
|
+
error: errorMessage
|
|
47672
|
+
};
|
|
47403
47673
|
}
|
|
47404
|
-
const result = await fastForwardMeshNode({
|
|
47405
|
-
meshId: meshId || void 0,
|
|
47406
|
-
nodeId: nodeId || void 0,
|
|
47407
|
-
workspace,
|
|
47408
|
-
branch: typeof args?.branch === "string" ? args.branch : void 0,
|
|
47409
|
-
execute: args?.execute === true,
|
|
47410
|
-
dryRun: args?.dryRun === true,
|
|
47411
|
-
updateSubmodules: args?.updateSubmodules === true,
|
|
47412
|
-
submoduleIgnorePaths,
|
|
47413
|
-
mode: args?.mode === "push" ? "push" : "merge",
|
|
47414
|
-
pushSubmodules: args?.pushSubmodules === true,
|
|
47415
|
-
allowAutoPublishSubmoduleMainCommits
|
|
47416
|
-
});
|
|
47417
|
-
return result;
|
|
47418
47674
|
},
|
|
47419
47675
|
refine_mesh_node: async (ctx, args) => {
|
|
47420
47676
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
@@ -47571,6 +47827,56 @@ var meshCoordinatorLaunchHandlers = {
|
|
|
47571
47827
|
return "";
|
|
47572
47828
|
}
|
|
47573
47829
|
};
|
|
47830
|
+
const buildRecentActivityBestEffort = async (id) => {
|
|
47831
|
+
try {
|
|
47832
|
+
const { getLedgerSummary: getLedgerSummary2, readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
47833
|
+
const { getMeshQueueStats: getMeshQueueStats2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
47834
|
+
const summary = getLedgerSummary2(id);
|
|
47835
|
+
const queue = getMeshQueueStats2(id);
|
|
47836
|
+
const failureEntries = readLedgerEntries2(id, { kind: ["task_failed"], tail: 5 });
|
|
47837
|
+
const recentFailures = failureEntries.map((e) => {
|
|
47838
|
+
const p = e.payload || {};
|
|
47839
|
+
const raw = typeof p.taskSummary === "string" ? p.taskSummary : typeof p.message === "string" ? p.message : typeof p.error === "string" ? p.error : "";
|
|
47840
|
+
const summaryText = raw.length > 160 ? `${raw.slice(0, 160)}\u2026` : raw;
|
|
47841
|
+
return {
|
|
47842
|
+
timestamp: e.timestamp,
|
|
47843
|
+
nodeId: e.nodeId,
|
|
47844
|
+
summary: summaryText
|
|
47845
|
+
};
|
|
47846
|
+
});
|
|
47847
|
+
return {
|
|
47848
|
+
recentFailures,
|
|
47849
|
+
recentFailureCount: summary.recentFailures,
|
|
47850
|
+
pendingTasks: queue.pending,
|
|
47851
|
+
assignedTasks: queue.assigned,
|
|
47852
|
+
stalledTasks: summary.taskStalled,
|
|
47853
|
+
lastActivityAt: summary.lastActivityAt
|
|
47854
|
+
};
|
|
47855
|
+
} catch {
|
|
47856
|
+
return void 0;
|
|
47857
|
+
}
|
|
47858
|
+
};
|
|
47859
|
+
const buildOperatingNotesBestEffort = async (id) => {
|
|
47860
|
+
try {
|
|
47861
|
+
const { readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
47862
|
+
const noteEntries = readLedgerEntries2(id, { kind: ["coordinator_operating_note"], tail: 20 });
|
|
47863
|
+
const notes = noteEntries.map((e) => {
|
|
47864
|
+
const p = e.payload || {};
|
|
47865
|
+
const text = typeof p.text === "string" ? p.text.trim() : "";
|
|
47866
|
+
if (!text) return null;
|
|
47867
|
+
const category = p.category === "provider_quirk" || p.category === "pattern_to_avoid" || p.category === "recovery_lesson" ? p.category : void 0;
|
|
47868
|
+
return {
|
|
47869
|
+
text,
|
|
47870
|
+
category,
|
|
47871
|
+
createdAt: typeof p.createdAt === "string" ? p.createdAt : e.timestamp,
|
|
47872
|
+
sourceCoordinator: typeof p.sourceCoordinator === "string" ? p.sourceCoordinator : void 0
|
|
47873
|
+
};
|
|
47874
|
+
}).filter((n) => n !== null);
|
|
47875
|
+
return notes.length ? notes : void 0;
|
|
47876
|
+
} catch {
|
|
47877
|
+
return void 0;
|
|
47878
|
+
}
|
|
47879
|
+
};
|
|
47574
47880
|
let mesh;
|
|
47575
47881
|
if (args?.inlineMesh && typeof args.inlineMesh === "object") {
|
|
47576
47882
|
mesh = args.inlineMesh;
|
|
@@ -47661,7 +47967,7 @@ var meshCoordinatorLaunchHandlers = {
|
|
|
47661
47967
|
if (coordinatorSetup.kind === "cli_command") {
|
|
47662
47968
|
let cliCmdSystemPrompt = "";
|
|
47663
47969
|
try {
|
|
47664
|
-
cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id) });
|
|
47970
|
+
cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildOperatingNotesBestEffort(mesh.id) });
|
|
47665
47971
|
} catch (error) {
|
|
47666
47972
|
const message = error?.message || String(error);
|
|
47667
47973
|
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
@@ -47838,7 +48144,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
47838
48144
|
}
|
|
47839
48145
|
let systemPrompt = "";
|
|
47840
48146
|
try {
|
|
47841
|
-
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id) });
|
|
48147
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildOperatingNotesBestEffort(mesh.id) });
|
|
47842
48148
|
} catch (error) {
|
|
47843
48149
|
const message = error?.message || String(error);
|
|
47844
48150
|
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|