@adhdev/daemon-standalone 0.9.76 → 0.9.77-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31227,7 +31227,8 @@ var require_dist2 = __commonJS({
31227
31227
  dirtyWorkspaceBehavior: "warn",
31228
31228
  maxParallelTasks: 2,
31229
31229
  spawnedSessionVisibility: "visible",
31230
- sessionCleanupOnNodeRemove: "preserve"
31230
+ sessionCleanupOnNodeRemove: "preserve",
31231
+ maxTaskRetries: 1
31231
31232
  };
31232
31233
  }
31233
31234
  });
@@ -31866,12 +31867,13 @@ ${rules.join("\n")}`;
31866
31867
  return `## Rules
31867
31868
 
31868
31869
  - **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
31869
- - **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
31870
+ - **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to the queue or a node. Do not do it yourself.
31870
31871
  - **Respect explicit provider requests.** If the user names an agent/provider, pass the matching provider type to \`mesh_launch_session\`: Hermes \u2192 \`hermes-cli\`, Claude Code/Claude \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`. Never substitute \`claude-cli\` just because the coordinator itself is Claude Code.
31871
- - **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
31872
+ - **Front-load the task message.** When calling \`mesh_enqueue_task\` or \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
31872
31873
  - **Don't inspect code.** Treat delegated agent summaries as self-reports, not verification. Verify side effects via \`mesh_git_status\` (including related repo freshness when configured), not by reading source files.
31873
31874
  - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed. Never launch a duplicate session or second worker solely because \`mesh_read_chat\` has no final assistant message while the delegated session is still showing tool/terminal activity.
31874
- - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
31875
+ - **Handle failures with context.** If a task fails, check \`mesh_task_history\` first to see if this task was attempted before and how it failed. Read the chat to understand why, then decide: retry on the same node, reassign to a different node, or escalate to the user.
31876
+ - **Check history before starting.** At the beginning of a coordination session, call \`mesh_task_history\` to understand what was previously delegated and its outcomes. This prevents duplicate work and informs recovery decisions.
31875
31877
  - **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
31876
31878
  - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
31877
31879
  - **Never fabricate tool results.** Always call the actual tool; never pretend you did.
@@ -31894,6 +31896,7 @@ ${rules.join("\n")}`;
31894
31896
  | \`mesh_launch_session\` | Start a new agent session on a node |
31895
31897
  | \`mesh_send_task\` | Send a task (natural language) to a running agent |
31896
31898
  | \`mesh_read_chat\` | Read an agent's recent messages to check progress |
31899
+ | \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
31897
31900
  | \`mesh_git_status\` | Check git status on a specific node |
31898
31901
  | \`mesh_checkpoint\` | Create a git checkpoint on a node |
31899
31902
  | \`mesh_approve\` | Approve/reject a pending agent action |
@@ -31904,18 +31907,371 @@ ${rules.join("\n")}`;
31904
31907
  Before doing any coordinator work, confirm that the actual callable tool list includes \`mesh_status\` and the other \`mesh_*\` tools from the table above. If this Repo Mesh coordinator prompt is present but the callable \`mesh_*\` tools are missing, the MCP server/tool manifest is stale or not injected yet. Do not substitute terminal/file/git tools, do not inspect or edit the repository directly, and do not continue as a non-mesh local coding agent. Stop immediately and tell the user to run \`/reload-mcp\` or start a fresh coordinator session so ADHDev can reconnect \`adhdev-mesh\`.`;
31905
31908
  WORKFLOW_SECTION = `## Orchestration Workflow
31906
31909
 
31907
- 1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
31908
- 2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
31909
- 3. **Delegate** \u2014 For each task:
31910
- a. Pick the best node (consider: health, dirty state, current workload).
31911
- b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
31912
- c. If no session exists, call \`mesh_launch_session\` to start one.
31913
- d. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
31914
- 4. **Monitor** \u2014 Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly just because the delegated session has not produced a final assistant message yet; tool/terminal activity means work may still be in progress. Do not call \`mesh_read_chat\` again within a few seconds for the same generating session; wait for the completion callback/status event instead unless you are debugging a real stall. Use at most one compact \`mesh_read_chat\` check after a completion/approval signal, an explicit user status request, or a real timeout/stall. Handle approvals via \`mesh_approve\`.
31910
+ 1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available. Check \`mesh_task_history\` to understand what has already been done in this mesh \u2014 previous delegations, completions, and failures.
31911
+ 2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist. If \`mesh_task_history\` shows a recent failure for a task, decide whether to retry or reassign.
31912
+ 3. **Queue / Delegate** \u2014 The Mesh uses an autonomous pull-based Work Queue:
31913
+ a. **General Tasks**: Enqueue tasks using \`mesh_enqueue_task\`. Idle node agents will automatically pull tasks from the queue and begin working.
31914
+ b. **Node Preparation**: Call \`mesh_launch_session\` to ensure enough agent sessions are active to handle the queue. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
31915
+ c. **Targeted Tasks**: Use \`mesh_send_task\` only when you need to bypass the queue and force a specific node to execute a task immediately.
31916
+ d. Always provide a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
31917
+ 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\`.
31915
31918
  5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
31916
31919
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
31917
31920
  7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
31918
- 8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
31921
+ 8. **Report** \u2014 Summarize what was done, what changed, and any issues.
31922
+
31923
+ ## Failure Recovery
31924
+
31925
+ When a node agent stops unexpectedly, the daemon automatically enriches the system message with **Recovery Context** that includes:
31926
+ - The number of consecutive failures on that node
31927
+ - The original task message (if recorded in the ledger)
31928
+ - A recommendation: **retry**, **reassign**, or **escalate**
31929
+
31930
+ Follow these recovery rules:
31931
+ 1. **If "Retry recommended"**: Re-launch the session on the same node (\`mesh_launch_session\`), then resend the original task (\`mesh_send_task\`). The system message includes the original task text.
31932
+ 2. **If "Max retries exceeded"**: Do NOT retry on the same node. Either reassign the task to a different node, or inform the user that the task requires manual intervention.
31933
+ 3. **If no recovery context**: The stop may be intentional (normal completion). Use \`mesh_read_chat\` once to verify, then move on.
31934
+ 4. **Always record what happened**: After handling a failure, briefly note the outcome in your report to the user.`;
31935
+ }
31936
+ });
31937
+ var mesh_ledger_exports = {};
31938
+ __export2(mesh_ledger_exports, {
31939
+ appendLedgerEntry: () => appendLedgerEntry,
31940
+ appendRemoteLedgerEntries: () => appendRemoteLedgerEntries,
31941
+ getLedgerDir: () => getLedgerDir,
31942
+ getLedgerSummary: () => getLedgerSummary,
31943
+ getSessionRecoveryContext: () => getSessionRecoveryContext,
31944
+ meshLedgerEvents: () => meshLedgerEvents,
31945
+ readLedgerEntries: () => readLedgerEntries
31946
+ });
31947
+ function getLedgerDir() {
31948
+ const dir = (0, import_path3.join)(getConfigDir(), LEDGER_DIR_NAME);
31949
+ if (!(0, import_fs3.existsSync)(dir)) {
31950
+ (0, import_fs3.mkdirSync)(dir, { recursive: true, mode: 448 });
31951
+ }
31952
+ return dir;
31953
+ }
31954
+ function getLedgerPath(meshId) {
31955
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
31956
+ return (0, import_path3.join)(getLedgerDir(), `${safe}.jsonl`);
31957
+ }
31958
+ function getRotatedPath(meshId, index) {
31959
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
31960
+ return (0, import_path3.join)(getLedgerDir(), `${safe}.${index}.jsonl`);
31961
+ }
31962
+ function appendLedgerEntry(meshId, partial2) {
31963
+ const entry = {
31964
+ id: (0, import_crypto4.randomUUID)(),
31965
+ meshId,
31966
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
31967
+ ...partial2
31968
+ };
31969
+ const filePath = getLedgerPath(meshId);
31970
+ if ((0, import_fs3.existsSync)(filePath)) {
31971
+ try {
31972
+ const stat2 = (0, import_fs3.statSync)(filePath);
31973
+ if (stat2.size >= MAX_FILE_SIZE_BYTES) {
31974
+ rotateLedgerFile(meshId, filePath);
31975
+ }
31976
+ } catch {
31977
+ }
31978
+ }
31979
+ try {
31980
+ const line = JSON.stringify(entry) + "\n";
31981
+ (0, import_fs3.appendFileSync)(filePath, line, { encoding: "utf-8", mode: 384 });
31982
+ meshLedgerEvents.emit("append", meshId, entry);
31983
+ return entry;
31984
+ } catch (e) {
31985
+ throw new Error(`Failed to append to ledger for mesh ${meshId}: ${e.message}`);
31986
+ }
31987
+ }
31988
+ function appendRemoteLedgerEntries(meshId, entries) {
31989
+ if (entries.length === 0) return;
31990
+ const ledgerPath = getLedgerPath(meshId);
31991
+ const existing = new Set(readLedgerEntries(meshId).map((e) => e.id));
31992
+ const newEntries = entries.filter((e) => !existing.has(e.id));
31993
+ if (newEntries.length === 0) return;
31994
+ try {
31995
+ const lines = newEntries.map((e) => JSON.stringify(e)).join("\n") + "\n";
31996
+ (0, import_fs3.appendFileSync)(ledgerPath, lines, { encoding: "utf-8", mode: 384 });
31997
+ } catch (e) {
31998
+ throw new Error(`Failed to append remote ledger entries for mesh ${meshId}: ${e.message}`);
31999
+ }
32000
+ }
32001
+ function readLedgerEntries(meshId, opts) {
32002
+ const filePath = getLedgerPath(meshId);
32003
+ if (!(0, import_fs3.existsSync)(filePath)) return [];
32004
+ let content;
32005
+ try {
32006
+ content = (0, import_fs3.readFileSync)(filePath, "utf-8");
32007
+ } catch {
32008
+ return [];
32009
+ }
32010
+ const lines = content.split("\n").filter((line) => line.trim());
32011
+ let entries = [];
32012
+ for (const line of lines) {
32013
+ try {
32014
+ const entry = JSON.parse(line);
32015
+ if (!entry.id || !entry.kind) continue;
32016
+ entries.push(entry);
32017
+ } catch {
32018
+ }
32019
+ }
32020
+ if (opts?.since) {
32021
+ const sinceDate = new Date(opts.since).getTime();
32022
+ if (!isNaN(sinceDate)) {
32023
+ entries = entries.filter((e) => new Date(e.timestamp).getTime() >= sinceDate);
32024
+ }
32025
+ }
32026
+ if (opts?.kind?.length) {
32027
+ const kindSet = new Set(opts.kind);
32028
+ entries = entries.filter((e) => kindSet.has(e.kind));
32029
+ }
32030
+ if (opts?.tail && opts.tail > 0 && entries.length > opts.tail) {
32031
+ entries = entries.slice(-opts.tail);
32032
+ }
32033
+ return entries;
32034
+ }
32035
+ function getLedgerSummary(meshId) {
32036
+ const entries = readLedgerEntries(meshId);
32037
+ const now = Date.now();
32038
+ const recentFailureCutoff = now - RECENT_FAILURE_WINDOW_MS;
32039
+ const summary = {
32040
+ meshId,
32041
+ totalEntries: entries.length,
32042
+ taskDispatched: 0,
32043
+ taskCompleted: 0,
32044
+ taskFailed: 0,
32045
+ taskStalled: 0,
32046
+ sessionLaunched: 0,
32047
+ checkpointCreated: 0,
32048
+ lastActivityAt: null,
32049
+ recentFailures: 0
32050
+ };
32051
+ for (const entry of entries) {
32052
+ switch (entry.kind) {
32053
+ case "task_dispatched":
32054
+ summary.taskDispatched++;
32055
+ break;
32056
+ case "task_completed":
32057
+ summary.taskCompleted++;
32058
+ break;
32059
+ case "task_failed": {
32060
+ summary.taskFailed++;
32061
+ if (new Date(entry.timestamp).getTime() >= recentFailureCutoff) {
32062
+ summary.recentFailures++;
32063
+ }
32064
+ break;
32065
+ }
32066
+ case "task_stalled":
32067
+ summary.taskStalled++;
32068
+ break;
32069
+ case "session_launched":
32070
+ summary.sessionLaunched++;
32071
+ break;
32072
+ case "checkpoint_created":
32073
+ summary.checkpointCreated++;
32074
+ break;
32075
+ }
32076
+ }
32077
+ if (entries.length > 0) {
32078
+ summary.lastActivityAt = entries[entries.length - 1].timestamp;
32079
+ }
32080
+ return summary;
32081
+ }
32082
+ function getSessionRecoveryContext(meshId, opts) {
32083
+ const maxRetries = opts.maxRetries ?? 1;
32084
+ const entries = readLedgerEntries(meshId);
32085
+ let lastDispatch = null;
32086
+ for (let i = entries.length - 1; i >= 0; i--) {
32087
+ const e = entries[i];
32088
+ if (e.kind !== "task_dispatched") continue;
32089
+ if (opts.sessionId && e.sessionId === opts.sessionId) {
32090
+ lastDispatch = e;
32091
+ break;
32092
+ }
32093
+ if (opts.nodeId && e.nodeId === opts.nodeId) {
32094
+ lastDispatch = e;
32095
+ break;
32096
+ }
32097
+ }
32098
+ const lastTaskMessage = typeof lastDispatch?.payload?.message === "string" ? lastDispatch.payload.message : null;
32099
+ const now = Date.now();
32100
+ const recentWindow = now - RECENT_FAILURE_WINDOW_MS;
32101
+ let consecutiveNodeFailures = 0;
32102
+ for (let i = entries.length - 1; i >= 0; i--) {
32103
+ const e = entries[i];
32104
+ if (new Date(e.timestamp).getTime() < recentWindow) break;
32105
+ if (opts.nodeId && e.nodeId !== opts.nodeId) continue;
32106
+ if (e.kind === "task_failed") {
32107
+ consecutiveNodeFailures++;
32108
+ } else if (e.kind === "task_completed" || e.kind === "task_dispatched") {
32109
+ break;
32110
+ }
32111
+ }
32112
+ let taskAttemptCount = 0;
32113
+ if (lastTaskMessage) {
32114
+ const prefix = lastTaskMessage.slice(0, 200);
32115
+ for (const e of entries) {
32116
+ if (e.kind === "task_dispatched" && typeof e.payload?.message === "string") {
32117
+ if (e.payload.message.startsWith(prefix)) {
32118
+ taskAttemptCount++;
32119
+ }
32120
+ }
32121
+ }
32122
+ }
32123
+ const retryRecommended = consecutiveNodeFailures <= maxRetries;
32124
+ let advice;
32125
+ if (consecutiveNodeFailures === 0) {
32126
+ advice = "No recent failures detected. This may be a normal stop.";
32127
+ } else if (retryRecommended) {
32128
+ const remaining = maxRetries - consecutiveNodeFailures + 1;
32129
+ advice = `Retry recommended (${consecutiveNodeFailures}/${maxRetries + 1} attempts used, ${remaining} remaining). ` + (lastTaskMessage ? `Re-launch the session and resend the original task.` : `Re-launch the session. Original task message not found in ledger.`);
32130
+ } else {
32131
+ advice = `Max retries exceeded (${consecutiveNodeFailures} consecutive failures). Consider: (1) reassigning to a different node, (2) simplifying the task, or (3) escalating to the user.`;
32132
+ }
32133
+ return {
32134
+ lastTaskMessage,
32135
+ failedNodeId: opts.nodeId || null,
32136
+ failedSessionId: opts.sessionId || null,
32137
+ failedProviderType: null,
32138
+ // filled by caller if available
32139
+ consecutiveNodeFailures,
32140
+ taskAttemptCount,
32141
+ retryRecommended,
32142
+ advice
32143
+ };
32144
+ }
32145
+ function rotateLedgerFile(meshId, currentPath) {
32146
+ let index = 1;
32147
+ while ((0, import_fs3.existsSync)(getRotatedPath(meshId, index))) {
32148
+ index++;
32149
+ if (index > 10) break;
32150
+ }
32151
+ if (index > 10) index = 10;
32152
+ try {
32153
+ (0, import_fs3.renameSync)(currentPath, getRotatedPath(meshId, index));
32154
+ } catch {
32155
+ }
32156
+ }
32157
+ var import_fs3;
32158
+ var import_path3;
32159
+ var import_crypto4;
32160
+ var import_events;
32161
+ var LEDGER_DIR_NAME;
32162
+ var MAX_FILE_SIZE_BYTES;
32163
+ var RECENT_FAILURE_WINDOW_MS;
32164
+ var meshLedgerEvents;
32165
+ var init_mesh_ledger = __esm2({
32166
+ "src/mesh/mesh-ledger.ts"() {
32167
+ "use strict";
32168
+ import_fs3 = require("fs");
32169
+ import_path3 = require("path");
32170
+ import_crypto4 = require("crypto");
32171
+ init_config();
32172
+ import_events = require("events");
32173
+ LEDGER_DIR_NAME = "mesh-ledger";
32174
+ MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024;
32175
+ RECENT_FAILURE_WINDOW_MS = 30 * 60 * 1e3;
32176
+ meshLedgerEvents = new import_events.EventEmitter();
32177
+ }
32178
+ });
32179
+ function getQueuePath(meshId) {
32180
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
32181
+ return (0, import_path4.join)(getLedgerDir(), `${safe}.queue.json`);
32182
+ }
32183
+ function readQueue(meshId) {
32184
+ const path28 = getQueuePath(meshId);
32185
+ if (!(0, import_fs4.existsSync)(path28)) return [];
32186
+ try {
32187
+ const content = (0, import_fs4.readFileSync)(path28, "utf-8");
32188
+ return JSON.parse(content);
32189
+ } catch {
32190
+ return [];
32191
+ }
32192
+ }
32193
+ function writeQueue(meshId, queue) {
32194
+ const path28 = getQueuePath(meshId);
32195
+ (0, import_fs4.writeFileSync)(path28, JSON.stringify(queue, null, 2), "utf-8");
32196
+ }
32197
+ function enqueueTask(meshId, message, opts) {
32198
+ const queue = readQueue(meshId);
32199
+ const entry = {
32200
+ id: (0, import_crypto5.randomUUID)(),
32201
+ meshId,
32202
+ message,
32203
+ status: "pending",
32204
+ targetNodeId: opts?.targetNodeId,
32205
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
32206
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
32207
+ };
32208
+ queue.push(entry);
32209
+ writeQueue(meshId, queue);
32210
+ return entry;
32211
+ }
32212
+ function getQueue(meshId, opts) {
32213
+ let queue = readQueue(meshId);
32214
+ if (opts?.status?.length) {
32215
+ const statuses = new Set(opts.status);
32216
+ queue = queue.filter((q2) => statuses.has(q2.status));
32217
+ }
32218
+ return queue;
32219
+ }
32220
+ function claimNextTask(meshId, nodeId, sessionId) {
32221
+ const queue = readQueue(meshId);
32222
+ let targetIdx = queue.findIndex((q2) => q2.status === "pending" && q2.targetNodeId === nodeId);
32223
+ if (targetIdx === -1) {
32224
+ targetIdx = queue.findIndex((q2) => q2.status === "pending" && !q2.targetNodeId);
32225
+ }
32226
+ if (targetIdx === -1) return null;
32227
+ const entry = queue[targetIdx];
32228
+ entry.status = "assigned";
32229
+ entry.assignedNodeId = nodeId;
32230
+ entry.assignedSessionId = sessionId;
32231
+ entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
32232
+ writeQueue(meshId, queue);
32233
+ return entry;
32234
+ }
32235
+ function updateTaskStatus(meshId, taskId, status) {
32236
+ const queue = readQueue(meshId);
32237
+ const idx = queue.findIndex((q2) => q2.id === taskId);
32238
+ if (idx === -1) return null;
32239
+ queue[idx].status = status;
32240
+ queue[idx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
32241
+ writeQueue(meshId, queue);
32242
+ return queue[idx];
32243
+ }
32244
+ function updateSessionTaskStatus(meshId, sessionId, status) {
32245
+ const queue = readQueue(meshId);
32246
+ for (let i = queue.length - 1; i >= 0; i--) {
32247
+ if (queue[i].assignedSessionId === sessionId && queue[i].status === "assigned") {
32248
+ queue[i].status = status;
32249
+ queue[i].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
32250
+ writeQueue(meshId, queue);
32251
+ return queue[i];
32252
+ }
32253
+ }
32254
+ return null;
32255
+ }
32256
+ function getMeshQueueStats(meshId) {
32257
+ const queue = readQueue(meshId);
32258
+ return {
32259
+ pending: queue.filter((q2) => q2.status === "pending").length,
32260
+ assigned: queue.filter((q2) => q2.status === "assigned").length,
32261
+ completed: queue.filter((q2) => q2.status === "completed").length,
32262
+ failed: queue.filter((q2) => q2.status === "failed").length
32263
+ };
32264
+ }
32265
+ var import_fs4;
32266
+ var import_path4;
32267
+ var import_crypto5;
32268
+ var init_mesh_work_queue = __esm2({
32269
+ "src/mesh/mesh-work-queue.ts"() {
32270
+ "use strict";
32271
+ import_fs4 = require("fs");
32272
+ import_path4 = require("path");
32273
+ import_crypto5 = require("crypto");
32274
+ init_mesh_ledger();
31919
32275
  }
31920
32276
  });
31921
32277
  function setLogLevel(level) {
@@ -31932,13 +32288,13 @@ Before doing any coordinator work, confirm that the actual callable tool list in
31932
32288
  return LOG_DIR;
31933
32289
  }
31934
32290
  function getCurrentDaemonLogPath(date5 = /* @__PURE__ */ new Date()) {
31935
- return path10.join(LOG_DIR, `daemon-${date5.toISOString().slice(0, 10)}.log`);
32291
+ return path8.join(LOG_DIR, `daemon-${date5.toISOString().slice(0, 10)}.log`);
31936
32292
  }
31937
32293
  function checkDateRotation() {
31938
32294
  const today = getDateStr();
31939
32295
  if (today !== currentDate) {
31940
32296
  currentDate = today;
31941
- currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
32297
+ currentLogFile = path8.join(LOG_DIR, `daemon-${currentDate}.log`);
31942
32298
  cleanOldLogs();
31943
32299
  }
31944
32300
  }
@@ -31952,7 +32308,7 @@ Before doing any coordinator work, confirm that the actual callable tool list in
31952
32308
  const dateMatch = file2.match(/daemon-(\d{4}-\d{2}-\d{2})/);
31953
32309
  if (dateMatch && dateMatch[1] < cutoffStr) {
31954
32310
  try {
31955
- fs22.unlinkSync(path10.join(LOG_DIR, file2));
32311
+ fs22.unlinkSync(path8.join(LOG_DIR, file2));
31956
32312
  } catch {
31957
32313
  }
31958
32314
  }
@@ -32069,8 +32425,8 @@ Before doing any coordinator work, confirm that the actual callable tool list in
32069
32425
  writeToFile(`Log level: ${currentLevel}`);
32070
32426
  }
32071
32427
  var fs22;
32072
- var path10;
32073
- var os42;
32428
+ var path8;
32429
+ var os22;
32074
32430
  var LEVEL_NUM;
32075
32431
  var LEVEL_LABEL;
32076
32432
  var currentLevel;
@@ -32092,12 +32448,12 @@ Before doing any coordinator work, confirm that the actual callable tool list in
32092
32448
  "src/logging/logger.ts"() {
32093
32449
  "use strict";
32094
32450
  fs22 = __toESM2(require("fs"));
32095
- path10 = __toESM2(require("path"));
32096
- os42 = __toESM2(require("os"));
32451
+ path8 = __toESM2(require("path"));
32452
+ os22 = __toESM2(require("os"));
32097
32453
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
32098
32454
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
32099
32455
  currentLevel = "info";
32100
- LOG_DIR = process.platform === "win32" ? path10.join(process.env.LOCALAPPDATA || process.env.APPDATA || path10.join(os42.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path10.join(os42.homedir(), "Library", "Logs", "adhdev") : path10.join(os42.homedir(), ".local", "share", "adhdev", "logs");
32456
+ LOG_DIR = process.platform === "win32" ? path8.join(process.env.LOCALAPPDATA || process.env.APPDATA || path8.join(os22.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path8.join(os22.homedir(), "Library", "Logs", "adhdev") : path8.join(os22.homedir(), ".local", "share", "adhdev", "logs");
32101
32457
  MAX_LOG_SIZE = 5 * 1024 * 1024;
32102
32458
  MAX_LOG_DAYS = 7;
32103
32459
  try {
@@ -32105,16 +32461,16 @@ Before doing any coordinator work, confirm that the actual callable tool list in
32105
32461
  } catch {
32106
32462
  }
32107
32463
  currentDate = getDateStr();
32108
- currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
32464
+ currentLogFile = path8.join(LOG_DIR, `daemon-${currentDate}.log`);
32109
32465
  cleanOldLogs();
32110
32466
  try {
32111
- const oldLog = path10.join(LOG_DIR, "daemon.log");
32467
+ const oldLog = path8.join(LOG_DIR, "daemon.log");
32112
32468
  if (fs22.existsSync(oldLog)) {
32113
32469
  const stat2 = fs22.statSync(oldLog);
32114
32470
  const oldDate = stat2.mtime.toISOString().slice(0, 10);
32115
- fs22.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
32471
+ fs22.renameSync(oldLog, path8.join(LOG_DIR, `daemon-${oldDate}.log`));
32116
32472
  }
32117
- const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
32473
+ const oldLogBackup = path8.join(LOG_DIR, "daemon.log.old");
32118
32474
  if (fs22.existsSync(oldLogBackup)) {
32119
32475
  fs22.unlinkSync(oldLogBackup);
32120
32476
  }
@@ -32146,7 +32502,314 @@ Before doing any coordinator work, confirm that the actual callable tool list in
32146
32502
  }
32147
32503
  };
32148
32504
  interceptorInstalled = false;
32149
- LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
32505
+ LOG_PATH = path8.join(LOG_DIR, `daemon-${getDateStr()}.log`);
32506
+ }
32507
+ });
32508
+ var mesh_events_exports = {};
32509
+ __export2(mesh_events_exports, {
32510
+ drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
32511
+ handleMeshForwardEvent: () => handleMeshForwardEvent,
32512
+ setupMeshEventForwarding: () => setupMeshEventForwarding,
32513
+ triggerMeshQueue: () => triggerMeshQueue,
32514
+ tryAssignQueueTask: () => tryAssignQueueTask
32515
+ });
32516
+ function drainPendingMeshCoordinatorEvents() {
32517
+ return pendingMeshCoordinatorEvents.splice(0);
32518
+ }
32519
+ function readNonEmptyString(value) {
32520
+ return typeof value === "string" && value.trim() ? value.trim() : "";
32521
+ }
32522
+ function isMeshCoordinatorEvent(eventName) {
32523
+ return typeof eventName === "string" && MESH_COORDINATOR_EVENTS.has(eventName);
32524
+ }
32525
+ function formatCompletionMetadata(event) {
32526
+ const parts = [
32527
+ readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
32528
+ readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
32529
+ readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
32530
+ ].filter(Boolean);
32531
+ return parts.length > 0 ? ` (${parts.join("; ")})` : "";
32532
+ }
32533
+ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
32534
+ const task = claimNextTask(meshId, nodeId, sessionId);
32535
+ if (!task) return false;
32536
+ LOG2.info("MeshQueue", `Node ${nodeId} (${sessionId}) pulled task ${task.id}`);
32537
+ components.cliManager.handleCliCommand("agent_command", {
32538
+ targetSessionId: sessionId,
32539
+ cliType: providerType,
32540
+ action: "send_chat",
32541
+ input: task.message
32542
+ }).catch((e) => {
32543
+ LOG2.error("MeshQueue", `Failed to dispatch task to node ${nodeId}: ${e?.message}`);
32544
+ });
32545
+ return true;
32546
+ }
32547
+ function triggerMeshQueue(components, meshId) {
32548
+ const mesh = getMesh(meshId);
32549
+ if (!mesh) return;
32550
+ const cliInstances = components.instanceManager.getByCategory("cli");
32551
+ for (const inst of cliInstances) {
32552
+ const state = inst.getState();
32553
+ const settings = state.settings || {};
32554
+ const instMeshId = readNonEmptyString(settings.meshNodeFor);
32555
+ if (instMeshId !== meshId && !settings.launchedByCoordinator) continue;
32556
+ const nodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
32557
+ if (!nodeId) continue;
32558
+ if (state.status !== "idle" && state.status !== "stopped" && state.activeChat?.status !== "waiting_input") continue;
32559
+ const sessionId = state.instanceId;
32560
+ const providerType = state.type || readNonEmptyString(settings.providerType);
32561
+ if (providerType) {
32562
+ tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType);
32563
+ }
32564
+ }
32565
+ }
32566
+ function buildMeshSystemMessage(args) {
32567
+ const metadata = formatCompletionMetadata(args.metadataEvent);
32568
+ if (args.event === "agent:generating_completed") {
32569
+ return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path; use mesh_read_chat once to review its final progress, but do not poll repeatedly.`;
32570
+ }
32571
+ if (args.event === "agent:waiting_approval") {
32572
+ return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
32573
+ }
32574
+ if (args.event === "agent:stopped") {
32575
+ const rc = args.recoveryContext;
32576
+ if (rc && rc.consecutiveNodeFailures > 0) {
32577
+ const parts = [
32578
+ `[System] ${args.nodeLabel} has stopped unexpectedly${metadata}.`,
32579
+ `
32580
+
32581
+ **Recovery Context:**`,
32582
+ `- Consecutive failures on this node: ${rc.consecutiveNodeFailures}`,
32583
+ rc.taskAttemptCount > 0 ? `- This task has been attempted ${rc.taskAttemptCount} time(s)` : "",
32584
+ `- Recommendation: ${rc.advice}`
32585
+ ];
32586
+ if (rc.retryRecommended && rc.lastTaskMessage) {
32587
+ parts.push(
32588
+ `
32589
+
32590
+ **Original task to retry:**`,
32591
+ `> ${rc.lastTaskMessage.length > 300 ? rc.lastTaskMessage.slice(0, 300) + "..." : rc.lastTaskMessage}`,
32592
+ `
32593
+ To retry: call \`mesh_launch_session\` for this node, then \`mesh_send_task\` with the original task.`
32594
+ );
32595
+ } else if (!rc.retryRecommended) {
32596
+ parts.push(
32597
+ `
32598
+ Do NOT retry on this node. Consider reassigning to a different node or asking the user for guidance.`
32599
+ );
32600
+ }
32601
+ return parts.filter(Boolean).join("\n");
32602
+ }
32603
+ return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
32604
+ }
32605
+ if (args.event === "monitor:long_generating") {
32606
+ return `[System] ${args.nodeLabel} has been generating for a long time${metadata}. Use mesh_read_chat once for a status check, but do not poll repeatedly.`;
32607
+ }
32608
+ return "";
32609
+ }
32610
+ function injectMeshSystemMessage(components, args) {
32611
+ if (args.event === "agent:generating_completed") {
32612
+ const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
32613
+ const nodeId = readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
32614
+ const providerType = readNonEmptyString(args.metadataEvent.providerType);
32615
+ if (sessionId) {
32616
+ updateSessionTaskStatus(args.meshId, sessionId, "completed");
32617
+ if (nodeId && providerType) {
32618
+ setTimeout(() => {
32619
+ tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
32620
+ }, 500);
32621
+ }
32622
+ }
32623
+ } else if (args.event === "agent:stopped") {
32624
+ const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
32625
+ if (sessionId) {
32626
+ updateSessionTaskStatus(args.meshId, sessionId, "failed");
32627
+ }
32628
+ }
32629
+ const ledgerKind = EVENT_TO_LEDGER_KIND[args.event];
32630
+ if (ledgerKind) {
32631
+ try {
32632
+ appendLedgerEntry(args.meshId, {
32633
+ kind: ledgerKind,
32634
+ nodeId: readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
32635
+ sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || void 0,
32636
+ providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
32637
+ payload: {
32638
+ event: args.event,
32639
+ nodeLabel: args.nodeLabel,
32640
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0
32641
+ }
32642
+ });
32643
+ } catch (e) {
32644
+ LOG2.warn("MeshLedger", `Failed to record ${ledgerKind}: ${e?.message || e}`);
32645
+ }
32646
+ }
32647
+ let recoveryContext = null;
32648
+ if (args.event === "agent:stopped") {
32649
+ try {
32650
+ const mesh = getMesh(args.meshId);
32651
+ const maxRetries = mesh?.policy?.maxTaskRetries ?? 1;
32652
+ recoveryContext = getSessionRecoveryContext(args.meshId, {
32653
+ sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || void 0,
32654
+ nodeId: readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
32655
+ maxRetries
32656
+ });
32657
+ recoveryContext.failedProviderType = readNonEmptyString(args.metadataEvent.providerType) || null;
32658
+ if (recoveryContext.retryRecommended && recoveryContext.consecutiveNodeFailures > 0) {
32659
+ appendLedgerEntry(args.meshId, {
32660
+ kind: "recovery_attempted",
32661
+ nodeId: recoveryContext.failedNodeId || void 0,
32662
+ sessionId: recoveryContext.failedSessionId || void 0,
32663
+ providerType: recoveryContext.failedProviderType || void 0,
32664
+ payload: {
32665
+ consecutiveFailures: recoveryContext.consecutiveNodeFailures,
32666
+ taskAttemptCount: recoveryContext.taskAttemptCount,
32667
+ retryRecommended: recoveryContext.retryRecommended,
32668
+ advice: recoveryContext.advice
32669
+ }
32670
+ });
32671
+ if (recoveryContext.lastTaskMessage && recoveryContext.failedNodeId && recoveryContext.failedProviderType) {
32672
+ const autoNodeId = recoveryContext.failedNodeId;
32673
+ try {
32674
+ const task = enqueueTask(args.meshId, recoveryContext.lastTaskMessage, {
32675
+ targetNodeId: autoNodeId
32676
+ });
32677
+ LOG2.info("MeshRecovery", `Auto-requeued failed task: ${task.id} for node ${autoNodeId}`);
32678
+ const node = mesh?.nodes.find((n) => n.id === autoNodeId);
32679
+ if (node) {
32680
+ components.cliManager.handleCliCommand("launch_cli", {
32681
+ cliType: recoveryContext.failedProviderType,
32682
+ dir: node.workspace,
32683
+ settings: {
32684
+ meshNodeFor: args.meshId,
32685
+ meshNodeId: node.id,
32686
+ spawnedSessionVisibility: mesh?.policy?.spawnedSessionVisibility || "hidden",
32687
+ launchedByCoordinator: true
32688
+ }
32689
+ }).catch((e) => LOG2.error("MeshRecovery", `Failed to auto-relaunch session for ${node.id}: ${e?.message}`));
32690
+ }
32691
+ } catch (e) {
32692
+ LOG2.warn("MeshRecovery", `Failed to execute auto-recovery: ${e?.message}`);
32693
+ }
32694
+ }
32695
+ }
32696
+ LOG2.info("MeshRecovery", `Recovery context for ${args.nodeLabel}: ${recoveryContext.advice}`);
32697
+ } catch (e) {
32698
+ LOG2.warn("MeshRecovery", `Failed to build recovery context: ${e?.message || e}`);
32699
+ }
32700
+ }
32701
+ const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
32702
+ const instState = inst.getState();
32703
+ if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
32704
+ if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
32705
+ return true;
32706
+ });
32707
+ if (coordinatorInstances.length === 0) {
32708
+ if (pendingMeshCoordinatorEvents.length < MAX_PENDING_EVENTS) {
32709
+ pendingMeshCoordinatorEvents.push({
32710
+ event: args.event,
32711
+ meshId: args.meshId,
32712
+ nodeLabel: args.nodeLabel,
32713
+ metadataEvent: {
32714
+ ...args.metadataEvent,
32715
+ ...recoveryContext ? { recoveryContext } : {}
32716
+ },
32717
+ queuedAt: Date.now()
32718
+ });
32719
+ LOG2.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
32720
+ }
32721
+ return { success: true, forwarded: 0 };
32722
+ }
32723
+ const messageText = buildMeshSystemMessage({
32724
+ event: args.event,
32725
+ nodeLabel: args.nodeLabel,
32726
+ metadataEvent: args.metadataEvent,
32727
+ recoveryContext
32728
+ });
32729
+ if (!messageText) return { success: false, error: "unsupported mesh event" };
32730
+ for (const coord of coordinatorInstances) {
32731
+ const coordState = coord.getState();
32732
+ LOG2.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
32733
+ coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
32734
+ }
32735
+ return { success: true, forwarded: coordinatorInstances.length };
32736
+ }
32737
+ function handleMeshForwardEvent(components, payload) {
32738
+ const eventName = readNonEmptyString(payload.event);
32739
+ if (!isMeshCoordinatorEvent(eventName)) {
32740
+ return { success: false, error: "unsupported mesh event" };
32741
+ }
32742
+ const meshId = readNonEmptyString(payload.meshId);
32743
+ if (!meshId) return { success: false, error: "meshId required" };
32744
+ const nodeId = readNonEmptyString(payload.nodeId);
32745
+ const workspace = readNonEmptyString(payload.workspace);
32746
+ const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
32747
+ return injectMeshSystemMessage(components, {
32748
+ meshId,
32749
+ nodeLabel,
32750
+ event: eventName,
32751
+ metadataEvent: {
32752
+ targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
32753
+ providerType: readNonEmptyString(payload.providerType),
32754
+ providerSessionId: readNonEmptyString(payload.providerSessionId)
32755
+ }
32756
+ });
32757
+ }
32758
+ function setupMeshEventForwarding(components) {
32759
+ components.instanceManager.onEvent((event) => {
32760
+ if (!isMeshCoordinatorEvent(event.event)) return;
32761
+ const instanceId = readNonEmptyString(event.instanceId);
32762
+ if (!instanceId) return;
32763
+ const sourceInstance = components.instanceManager.getInstance(instanceId);
32764
+ if (!sourceInstance || sourceInstance.category !== "cli") return;
32765
+ const state = sourceInstance.getState();
32766
+ const workspace = readNonEmptyString(state.workspace);
32767
+ if (!workspace) return;
32768
+ const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
32769
+ if (readNonEmptyString(settings.meshCoordinatorFor)) return;
32770
+ const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
32771
+ const isMeshDelegate = Boolean(meshIdFromRuntime || settings.launchedByCoordinator);
32772
+ if (!isMeshDelegate) return;
32773
+ const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
32774
+ const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
32775
+ if (!meshId) return;
32776
+ const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
32777
+ const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
32778
+ const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
32779
+ injectMeshSystemMessage(components, {
32780
+ meshId,
32781
+ sourceInstanceId: instanceId,
32782
+ nodeLabel,
32783
+ event: event.event,
32784
+ metadataEvent: event
32785
+ });
32786
+ });
32787
+ }
32788
+ var MAX_PENDING_EVENTS;
32789
+ var pendingMeshCoordinatorEvents;
32790
+ var MESH_COORDINATOR_EVENTS;
32791
+ var EVENT_TO_LEDGER_KIND;
32792
+ var init_mesh_events = __esm2({
32793
+ "src/mesh/mesh-events.ts"() {
32794
+ "use strict";
32795
+ init_mesh_config();
32796
+ init_logger();
32797
+ init_mesh_ledger();
32798
+ init_mesh_work_queue();
32799
+ MAX_PENDING_EVENTS = 50;
32800
+ pendingMeshCoordinatorEvents = [];
32801
+ MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
32802
+ "agent:generating_completed",
32803
+ "agent:waiting_approval",
32804
+ "agent:stopped",
32805
+ "monitor:long_generating"
32806
+ ]);
32807
+ EVENT_TO_LEDGER_KIND = {
32808
+ "agent:generating_completed": "task_completed",
32809
+ "agent:waiting_approval": "task_approval_needed",
32810
+ "agent:stopped": "task_failed",
32811
+ "monitor:long_generating": "task_stalled"
32812
+ };
32150
32813
  }
32151
32814
  });
32152
32815
  function normalizeCategories(categories) {
@@ -35254,6 +35917,7 @@ ${lastSnapshot}`;
35254
35917
  TurnSnapshotTracker: () => TurnSnapshotTracker,
35255
35918
  VersionArchive: () => VersionArchive,
35256
35919
  addNode: () => addNode,
35920
+ appendLedgerEntry: () => appendLedgerEntry,
35257
35921
  appendRecentActivity: () => appendRecentActivity,
35258
35922
  buildAssistantChatMessage: () => buildAssistantChatMessage,
35259
35923
  buildChatMessage: () => buildChatMessage,
@@ -35271,6 +35935,7 @@ ${lastSnapshot}`;
35271
35935
  buildThoughtChatMessage: () => buildThoughtChatMessage,
35272
35936
  buildToolChatMessage: () => buildToolChatMessage,
35273
35937
  buildUserChatMessage: () => buildUserChatMessage,
35938
+ claimNextTask: () => claimNextTask,
35274
35939
  classifyChatMessageVisibility: () => classifyChatMessageVisibility,
35275
35940
  classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush2,
35276
35941
  clearDebugTrace: () => clearDebugTrace,
@@ -35289,6 +35954,7 @@ ${lastSnapshot}`;
35289
35954
  detectAllVersions: () => detectAllVersions,
35290
35955
  detectCLIs: () => detectCLIs,
35291
35956
  detectIDEs: () => detectIDEs,
35957
+ enqueueTask: () => enqueueTask,
35292
35958
  ensureSessionHostReady: () => ensureSessionHostReady2,
35293
35959
  execNpmCommandSync: () => execNpmCommandSync,
35294
35960
  filterActivityChatMessages: () => filterActivityChatMessages,
@@ -35307,10 +35973,13 @@ ${lastSnapshot}`;
35307
35973
  getGitFileDiff: () => getGitFileDiff,
35308
35974
  getGitRepoStatus: () => getGitRepoStatus,
35309
35975
  getHostMemorySnapshot: () => getHostMemorySnapshot,
35976
+ getLedgerDir: () => getLedgerDir,
35977
+ getLedgerSummary: () => getLedgerSummary,
35310
35978
  getLogLevel: () => getLogLevel,
35311
35979
  getMesh: () => getMesh,
35312
35980
  getMeshByRepo: () => getMeshByRepo,
35313
35981
  getNpmExecOptions: () => getNpmExecOptions,
35982
+ getQueue: () => getQueue,
35314
35983
  getRecentActivity: () => getRecentActivity,
35315
35984
  getRecentCommands: () => getRecentCommands,
35316
35985
  getRecentDebugTrace: () => getRecentDebugTrace,
@@ -35318,6 +35987,7 @@ ${lastSnapshot}`;
35318
35987
  getSavedProviderSessions: () => getSavedProviderSessions,
35319
35988
  getSessionHostRecoveryLabel: () => getSessionHostRecoveryLabel,
35320
35989
  getSessionHostSurfaceKind: () => getSessionHostSurfaceKind,
35990
+ getSessionRecoveryContext: () => getSessionRecoveryContext,
35321
35991
  getWorkspaceState: () => getWorkspaceState2,
35322
35992
  handleGitCommand: () => handleGitCommand,
35323
35993
  hasCdpManager: () => hasCdpManager,
@@ -35371,6 +36041,7 @@ ${lastSnapshot}`;
35371
36041
  prepareSessionModalUpdate: () => prepareSessionModalUpdate2,
35372
36042
  probeCdpPort: () => probeCdpPort,
35373
36043
  readChatHistory: () => readChatHistory,
36044
+ readLedgerEntries: () => readLedgerEntries,
35374
36045
  recordDebugTrace: () => recordDebugTrace,
35375
36046
  registerExtensionProviders: () => registerExtensionProviders,
35376
36047
  removeNode: () => removeNode,
@@ -35399,9 +36070,12 @@ ${lastSnapshot}`;
35399
36070
  startDaemonDevSupport: () => startDaemonDevSupport2,
35400
36071
  summarizeGitStatus: () => summarizeGitStatus,
35401
36072
  syncMeshes: () => syncMeshes,
36073
+ triggerMeshQueue: () => triggerMeshQueue,
35402
36074
  updateConfig: () => updateConfig,
35403
36075
  updateMesh: () => updateMesh,
35404
36076
  updateNode: () => updateNode,
36077
+ updateSessionTaskStatus: () => updateSessionTaskStatus,
36078
+ updateTaskStatus: () => updateTaskStatus,
35405
36079
  upsertSavedProviderSession: () => upsertSavedProviderSession
35406
36080
  });
35407
36081
  module2.exports = __toCommonJS2(index_exports);
@@ -37234,10 +37908,31 @@ ${lastSnapshot}`;
37234
37908
  }
37235
37909
  }
37236
37910
  }
37911
+ if (transport.syncMeshLedger) {
37912
+ for (const local of localMeshes) {
37913
+ try {
37914
+ await syncMeshLedger(local.id, transport);
37915
+ } catch (e) {
37916
+ result.errors.push(`Ledger sync failed for "${local.name}": ${e.message}`);
37917
+ }
37918
+ }
37919
+ }
37237
37920
  return result;
37238
37921
  }
37239
- var import_fs3 = require("fs");
37240
- var import_path3 = require("path");
37922
+ async function syncMeshLedger(meshId, transport) {
37923
+ if (!transport.syncMeshLedger) return;
37924
+ const { readLedgerEntries: readLedgerEntries2, appendRemoteLedgerEntries: appendRemoteLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
37925
+ const localEntries = readLedgerEntries2(meshId);
37926
+ const res = await transport.syncMeshLedger(meshId, { newEntries: localEntries });
37927
+ if (res.missingEntries && res.missingEntries.length > 0) {
37928
+ appendRemoteLedgerEntries2(meshId, res.missingEntries);
37929
+ }
37930
+ }
37931
+ init_mesh_ledger();
37932
+ init_mesh_work_queue();
37933
+ init_mesh_events();
37934
+ var import_fs5 = require("fs");
37935
+ var import_path5 = require("path");
37241
37936
  init_config();
37242
37937
  var DEFAULT_STATE = {
37243
37938
  recentActivity: [],
@@ -37251,7 +37946,7 @@ ${lastSnapshot}`;
37251
37946
  return !!value && typeof value === "object" && !Array.isArray(value);
37252
37947
  }
37253
37948
  function getStatePath() {
37254
- return (0, import_path3.join)(getConfigDir(), "state.json");
37949
+ return (0, import_path5.join)(getConfigDir(), "state.json");
37255
37950
  }
37256
37951
  function normalizeState(raw) {
37257
37952
  const parsed = isPlainObject22(raw) ? raw : {};
@@ -37287,11 +37982,11 @@ ${lastSnapshot}`;
37287
37982
  }
37288
37983
  function loadState() {
37289
37984
  const statePath = getStatePath();
37290
- if (!(0, import_fs3.existsSync)(statePath)) {
37985
+ if (!(0, import_fs5.existsSync)(statePath)) {
37291
37986
  return { ...DEFAULT_STATE };
37292
37987
  }
37293
37988
  try {
37294
- const raw = (0, import_fs3.readFileSync)(statePath, "utf-8");
37989
+ const raw = (0, import_fs5.readFileSync)(statePath, "utf-8");
37295
37990
  return normalizeState(JSON.parse(raw));
37296
37991
  } catch {
37297
37992
  return { ...DEFAULT_STATE };
@@ -37300,15 +37995,15 @@ ${lastSnapshot}`;
37300
37995
  function saveState(state) {
37301
37996
  const statePath = getStatePath();
37302
37997
  const normalized = normalizeState(state);
37303
- (0, import_fs3.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
37998
+ (0, import_fs5.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
37304
37999
  }
37305
38000
  function resetState() {
37306
38001
  saveState({ ...DEFAULT_STATE });
37307
38002
  }
37308
38003
  var import_child_process = require("child_process");
37309
- var import_fs4 = require("fs");
38004
+ var import_fs6 = require("fs");
37310
38005
  var import_os22 = require("os");
37311
- var path8 = __toESM2(require("path"));
38006
+ var path9 = __toESM2(require("path"));
37312
38007
  var BUILTIN_IDE_DEFINITIONS = [];
37313
38008
  var registeredIDEs = /* @__PURE__ */ new Map();
37314
38009
  function registerIDEDefinition(def) {
@@ -37327,10 +38022,10 @@ ${lastSnapshot}`;
37327
38022
  function findCliCommand(command) {
37328
38023
  const trimmed = String(command || "").trim();
37329
38024
  if (!trimmed) return null;
37330
- if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
37331
- const candidate = trimmed.startsWith("~") ? path8.join((0, import_os22.homedir)(), trimmed.slice(1)) : trimmed;
37332
- const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
37333
- return (0, import_fs4.existsSync)(resolved) ? resolved : null;
38025
+ if (path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
38026
+ const candidate = trimmed.startsWith("~") ? path9.join((0, import_os22.homedir)(), trimmed.slice(1)) : trimmed;
38027
+ const resolved = path9.isAbsolute(candidate) ? candidate : path9.resolve(candidate);
38028
+ return (0, import_fs6.existsSync)(resolved) ? resolved : null;
37334
38029
  }
37335
38030
  try {
37336
38031
  const result = (0, import_child_process.execSync)(
@@ -37357,13 +38052,13 @@ ${lastSnapshot}`;
37357
38052
  function checkPathExists(paths) {
37358
38053
  const home = (0, import_os22.homedir)();
37359
38054
  for (const p of paths) {
37360
- const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
38055
+ const normalized = p.startsWith("~") ? path9.join(home, p.slice(1)) : p;
37361
38056
  if (normalized.includes("*")) {
37362
38057
  const username = home.split(/[\\/]/).pop() || "";
37363
38058
  const resolved = normalized.replace("*", username);
37364
- if ((0, import_fs4.existsSync)(resolved)) return resolved;
38059
+ if ((0, import_fs6.existsSync)(resolved)) return resolved;
37365
38060
  } else {
37366
- if ((0, import_fs4.existsSync)(normalized)) return normalized;
38061
+ if ((0, import_fs6.existsSync)(normalized)) return normalized;
37367
38062
  }
37368
38063
  }
37369
38064
  return null;
@@ -37377,7 +38072,7 @@ ${lastSnapshot}`;
37377
38072
  let resolvedCli = cliPath;
37378
38073
  if (!resolvedCli && appPath && os222 === "darwin") {
37379
38074
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
37380
- if ((0, import_fs4.existsSync)(bundledCli)) resolvedCli = bundledCli;
38075
+ if ((0, import_fs6.existsSync)(bundledCli)) resolvedCli = bundledCli;
37381
38076
  }
37382
38077
  if (!resolvedCli && appPath && os222 === "win32") {
37383
38078
  const { dirname: dirname9 } = await import("path");
@@ -37390,7 +38085,7 @@ ${lastSnapshot}`;
37390
38085
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
37391
38086
  ];
37392
38087
  for (const c of candidates) {
37393
- if ((0, import_fs4.existsSync)(c)) {
38088
+ if ((0, import_fs6.existsSync)(c)) {
37394
38089
  resolvedCli = c;
37395
38090
  break;
37396
38091
  }
@@ -37412,9 +38107,9 @@ ${lastSnapshot}`;
37412
38107
  return results;
37413
38108
  }
37414
38109
  var import_child_process2 = require("child_process");
37415
- var os22 = __toESM2(require("os"));
37416
- var path9 = __toESM2(require("path"));
37417
- var import_fs5 = require("fs");
38110
+ var os32 = __toESM2(require("os"));
38111
+ var path10 = __toESM2(require("path"));
38112
+ var import_fs7 = require("fs");
37418
38113
  function parseVersion(raw) {
37419
38114
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
37420
38115
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
@@ -37426,19 +38121,19 @@ ${lastSnapshot}`;
37426
38121
  function expandHome(value) {
37427
38122
  const trimmed = value.trim();
37428
38123
  if (!trimmed.startsWith("~")) return trimmed;
37429
- return path9.join(os22.homedir(), trimmed.slice(1));
38124
+ return path10.join(os32.homedir(), trimmed.slice(1));
37430
38125
  }
37431
38126
  function isExplicitCommandPath(command) {
37432
38127
  const trimmed = command.trim();
37433
- return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
38128
+ return path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
37434
38129
  }
37435
38130
  function resolveCommandPath(command) {
37436
38131
  const trimmed = command.trim();
37437
38132
  if (!trimmed) return null;
37438
38133
  if (isExplicitCommandPath(trimmed)) {
37439
38134
  const expanded = expandHome(trimmed);
37440
- const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
37441
- return (0, import_fs5.existsSync)(candidate) ? candidate : null;
38135
+ const candidate = path10.isAbsolute(expanded) ? expanded : path10.resolve(expanded);
38136
+ return (0, import_fs7.existsSync)(candidate) ? candidate : null;
37442
38137
  }
37443
38138
  return null;
37444
38139
  }
@@ -37459,7 +38154,7 @@ ${lastSnapshot}`;
37459
38154
  });
37460
38155
  }
37461
38156
  async function detectCLIs(providerLoader, options) {
37462
- const platform10 = os22.platform();
38157
+ const platform10 = os32.platform();
37463
38158
  const whichCmd = platform10 === "win32" ? "where" : "which";
37464
38159
  const includeVersion = options?.includeVersion !== false;
37465
38160
  const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
@@ -37503,7 +38198,7 @@ ${lastSnapshot}`;
37503
38198
  const cliList = providerLoader.getCliDetectionList();
37504
38199
  const target = cliList.find((c) => c.id === resolvedId);
37505
38200
  if (target) {
37506
- const platform10 = os22.platform();
38201
+ const platform10 = os32.platform();
37507
38202
  const whichCmd = platform10 === "win32" ? "where" : "which";
37508
38203
  try {
37509
38204
  const explicitPath = resolveCommandPath(target.command);
@@ -37538,10 +38233,10 @@ ${lastSnapshot}`;
37538
38233
  const all = await detectCLIs(providerLoader, options);
37539
38234
  return all.find((c) => c.id === resolvedId && c.installed) || null;
37540
38235
  }
37541
- var os32 = __toESM2(require("os"));
38236
+ var os42 = __toESM2(require("os"));
37542
38237
  var import_child_process3 = require("child_process");
37543
38238
  function parseDarwinAvailableBytes(totalMem) {
37544
- if (os32.platform() !== "darwin") return null;
38239
+ if (os42.platform() !== "darwin") return null;
37545
38240
  try {
37546
38241
  const out = (0, import_child_process3.execSync)("vm_stat", {
37547
38242
  encoding: "utf-8",
@@ -37572,8 +38267,8 @@ ${lastSnapshot}`;
37572
38267
  }
37573
38268
  }
37574
38269
  function getHostMemorySnapshot() {
37575
- const totalMem = os32.totalmem();
37576
- const freeMem = os32.freemem();
38270
+ const totalMem = os42.totalmem();
38271
+ const freeMem = os42.freemem();
37577
38272
  const darwinAvail = parseDarwinAvailableBytes(totalMem);
37578
38273
  const availableMem = darwinAvail != null ? darwinAvail : freeMem;
37579
38274
  return { totalMem, freeMem, availableMem };
@@ -42894,6 +43589,7 @@ ${effect.notification.body || ""}`.trim();
42894
43589
  }
42895
43590
  return normalized;
42896
43591
  }
43592
+ init_mesh_work_queue();
42897
43593
  var VALID_INPUT_MEDIA_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "video", "resource"]);
42898
43594
  var VALID_INPUT_STRATEGIES = /* @__PURE__ */ new Set(["native", "native_acp", "resource_link", "text_fallback", "paste", "upload"]);
42899
43595
  var TEXT_ONLY_MESSAGE_INPUT_SUPPORT = Object.freeze({
@@ -43116,6 +43812,8 @@ ${effect.notification.body || ""}`.trim();
43116
43812
  const workspace = state.workspace || null;
43117
43813
  const git = getGitSummaryForWorkspace(workspace, options);
43118
43814
  const title = activeChat?.title || state.name;
43815
+ const meshCoordinatorFor = state.settings?.meshCoordinatorFor;
43816
+ const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
43119
43817
  return {
43120
43818
  id: state.instanceId || state.type,
43121
43819
  parentId: null,
@@ -43138,7 +43836,8 @@ ${effect.notification.body || ""}`.trim();
43138
43836
  errorMessage: state.errorMessage,
43139
43837
  errorReason: state.errorReason,
43140
43838
  lastUpdated: state.lastUpdated,
43141
- settings: state.settings
43839
+ settings: state.settings,
43840
+ ...meshQueueStats && { meshQueueStats }
43142
43841
  };
43143
43842
  }
43144
43843
  function buildExtensionAgentSession(parent, ext, options) {
@@ -43150,6 +43849,8 @@ ${effect.notification.body || ""}`.trim();
43150
43849
  const includeSessionControls = shouldIncludeSessionControls(profile);
43151
43850
  const workspace = parent.workspace || null;
43152
43851
  const git = getGitSummaryForWorkspace(workspace, options);
43852
+ const meshCoordinatorFor = ext.settings?.meshCoordinatorFor;
43853
+ const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
43153
43854
  return {
43154
43855
  id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
43155
43856
  parentId: parent.instanceId || parent.type,
@@ -43172,7 +43873,8 @@ ${effect.notification.body || ""}`.trim();
43172
43873
  errorMessage: ext.errorMessage,
43173
43874
  errorReason: ext.errorReason,
43174
43875
  lastUpdated: ext.lastUpdated,
43175
- settings: ext.settings
43876
+ settings: ext.settings,
43877
+ ...meshQueueStats && { meshQueueStats }
43176
43878
  };
43177
43879
  }
43178
43880
  function shouldIncludeExtensionSession(ext) {
@@ -43200,6 +43902,8 @@ ${effect.notification.body || ""}`.trim();
43200
43902
  const includeSessionControls = shouldIncludeSessionControls(profile);
43201
43903
  const workspace = state.workspace || null;
43202
43904
  const git = getGitSummaryForWorkspace(workspace, options);
43905
+ const meshCoordinatorFor = state.settings?.meshCoordinatorFor;
43906
+ const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
43203
43907
  return {
43204
43908
  id: state.instanceId,
43205
43909
  parentId: null,
@@ -43238,7 +43942,8 @@ ${effect.notification.body || ""}`.trim();
43238
43942
  errorMessage: state.errorMessage,
43239
43943
  errorReason: state.errorReason,
43240
43944
  lastUpdated: state.lastUpdated,
43241
- settings: state.settings
43945
+ settings: state.settings,
43946
+ ...meshQueueStats && { meshQueueStats }
43242
43947
  };
43243
43948
  }
43244
43949
  function buildAcpSession(state, options) {
@@ -43250,6 +43955,8 @@ ${effect.notification.body || ""}`.trim();
43250
43955
  const includeSessionControls = shouldIncludeSessionControls(profile);
43251
43956
  const workspace = state.workspace || null;
43252
43957
  const git = getGitSummaryForWorkspace(workspace, options);
43958
+ const meshCoordinatorFor = state.settings?.meshCoordinatorFor;
43959
+ const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
43253
43960
  return {
43254
43961
  id: state.instanceId,
43255
43962
  parentId: null,
@@ -43271,7 +43978,8 @@ ${effect.notification.body || ""}`.trim();
43271
43978
  errorMessage: state.errorMessage,
43272
43979
  errorReason: state.errorReason,
43273
43980
  lastUpdated: state.lastUpdated,
43274
- settings: state.settings
43981
+ settings: state.settings,
43982
+ ...meshQueueStats && { meshQueueStats }
43275
43983
  };
43276
43984
  }
43277
43985
  function buildSessionEntries(allStates, cdpManagers, options = {}) {
@@ -46542,7 +47250,7 @@ ${effect.notification.body || ""}`.trim();
46542
47250
  var os13 = __toESM2(require("os"));
46543
47251
  var path18 = __toESM2(require("path"));
46544
47252
  var crypto4 = __toESM2(require("crypto"));
46545
- var import_fs6 = require("fs");
47253
+ var import_fs8 = require("fs");
46546
47254
  var import_child_process6 = require("child_process");
46547
47255
  var import_chalk = __toESM2((init_source(), __toCommonJS(source_exports)));
46548
47256
  init_provider_cli_adapter();
@@ -48906,7 +49614,7 @@ ${rawInput}` : rawInput;
48906
49614
  const trimmed = command.trim();
48907
49615
  if (!trimmed) return false;
48908
49616
  if (isExplicitCommand(trimmed)) {
48909
- return (0, import_fs6.existsSync)(expandExecutable(trimmed));
49617
+ return (0, import_fs8.existsSync)(expandExecutable(trimmed));
48910
49618
  }
48911
49619
  try {
48912
49620
  (0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -48935,10 +49643,10 @@ ${rawInput}` : rawInput;
48935
49643
  }
48936
49644
  function ensureEmptyDelegatedMcpConfig(workspace) {
48937
49645
  const baseDir = path18.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
48938
- (0, import_fs6.mkdirSync)(baseDir, { recursive: true });
49646
+ (0, import_fs8.mkdirSync)(baseDir, { recursive: true });
48939
49647
  const workspaceHash = crypto4.createHash("sha256").update(path18.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
48940
49648
  const filePath = path18.join(baseDir, `${workspaceHash}.json`);
48941
- (0, import_fs6.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
49649
+ (0, import_fs8.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
48942
49650
  return filePath;
48943
49651
  }
48944
49652
  function buildCoordinatorDelegatedCliLaunchOptions(input) {
@@ -52411,133 +53119,7 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
52411
53119
  return null;
52412
53120
  }
52413
53121
  }
52414
- init_mesh_config();
52415
- init_logger();
52416
- var MAX_PENDING_EVENTS = 50;
52417
- var pendingMeshCoordinatorEvents = [];
52418
- function drainPendingMeshCoordinatorEvents() {
52419
- return pendingMeshCoordinatorEvents.splice(0);
52420
- }
52421
- function readNonEmptyString(value) {
52422
- return typeof value === "string" && value.trim() ? value.trim() : "";
52423
- }
52424
- var MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
52425
- "agent:generating_completed",
52426
- "agent:waiting_approval",
52427
- "agent:stopped",
52428
- "monitor:long_generating"
52429
- ]);
52430
- function isMeshCoordinatorEvent(eventName) {
52431
- return typeof eventName === "string" && MESH_COORDINATOR_EVENTS.has(eventName);
52432
- }
52433
- function formatCompletionMetadata(event) {
52434
- const parts = [
52435
- readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
52436
- readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
52437
- readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
52438
- ].filter(Boolean);
52439
- return parts.length > 0 ? ` (${parts.join("; ")})` : "";
52440
- }
52441
- function buildMeshSystemMessage(args) {
52442
- const metadata = formatCompletionMetadata(args.metadataEvent);
52443
- if (args.event === "agent:generating_completed") {
52444
- return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path; use mesh_read_chat once to review its final progress, but do not poll repeatedly.`;
52445
- }
52446
- if (args.event === "agent:waiting_approval") {
52447
- return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
52448
- }
52449
- if (args.event === "agent:stopped") {
52450
- return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
52451
- }
52452
- if (args.event === "monitor:long_generating") {
52453
- return `[System] ${args.nodeLabel} has been generating for a long time${metadata}. Use mesh_read_chat once for a status check, but do not poll repeatedly.`;
52454
- }
52455
- return "";
52456
- }
52457
- function injectMeshSystemMessage(components, args) {
52458
- const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
52459
- const instState = inst.getState();
52460
- if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
52461
- if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
52462
- return true;
52463
- });
52464
- if (coordinatorInstances.length === 0) {
52465
- if (pendingMeshCoordinatorEvents.length < MAX_PENDING_EVENTS) {
52466
- pendingMeshCoordinatorEvents.push({
52467
- event: args.event,
52468
- meshId: args.meshId,
52469
- nodeLabel: args.nodeLabel,
52470
- metadataEvent: args.metadataEvent,
52471
- queuedAt: Date.now()
52472
- });
52473
- LOG2.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
52474
- }
52475
- return { success: true, forwarded: 0 };
52476
- }
52477
- const messageText = buildMeshSystemMessage({
52478
- event: args.event,
52479
- nodeLabel: args.nodeLabel,
52480
- metadataEvent: args.metadataEvent
52481
- });
52482
- if (!messageText) return { success: false, error: "unsupported mesh event" };
52483
- for (const coord of coordinatorInstances) {
52484
- const coordState = coord.getState();
52485
- LOG2.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
52486
- coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
52487
- }
52488
- return { success: true, forwarded: coordinatorInstances.length };
52489
- }
52490
- function handleMeshForwardEvent(components, payload) {
52491
- const eventName = readNonEmptyString(payload.event);
52492
- if (!isMeshCoordinatorEvent(eventName)) {
52493
- return { success: false, error: "unsupported mesh event" };
52494
- }
52495
- const meshId = readNonEmptyString(payload.meshId);
52496
- if (!meshId) return { success: false, error: "meshId required" };
52497
- const nodeId = readNonEmptyString(payload.nodeId);
52498
- const workspace = readNonEmptyString(payload.workspace);
52499
- const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
52500
- return injectMeshSystemMessage(components, {
52501
- meshId,
52502
- nodeLabel,
52503
- event: eventName,
52504
- metadataEvent: {
52505
- targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
52506
- providerType: readNonEmptyString(payload.providerType),
52507
- providerSessionId: readNonEmptyString(payload.providerSessionId)
52508
- }
52509
- });
52510
- }
52511
- function setupMeshEventForwarding(components) {
52512
- components.instanceManager.onEvent((event) => {
52513
- if (!isMeshCoordinatorEvent(event.event)) return;
52514
- const instanceId = readNonEmptyString(event.instanceId);
52515
- if (!instanceId) return;
52516
- const sourceInstance = components.instanceManager.getInstance(instanceId);
52517
- if (!sourceInstance || sourceInstance.category !== "cli") return;
52518
- const state = sourceInstance.getState();
52519
- const workspace = readNonEmptyString(state.workspace);
52520
- if (!workspace) return;
52521
- const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
52522
- if (readNonEmptyString(settings.meshCoordinatorFor)) return;
52523
- const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
52524
- const isMeshDelegate = Boolean(meshIdFromRuntime || settings.launchedByCoordinator);
52525
- if (!isMeshDelegate) return;
52526
- const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
52527
- const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
52528
- if (!meshId) return;
52529
- const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
52530
- const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
52531
- const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
52532
- injectMeshSystemMessage(components, {
52533
- meshId,
52534
- sourceInstanceId: instanceId,
52535
- nodeLabel,
52536
- event: event.event,
52537
- metadataEvent: event
52538
- });
52539
- });
52540
- }
53122
+ init_mesh_events();
52541
53123
  var os18 = __toESM2(require("os"));
52542
53124
  init_config();
52543
53125
  init_terminal_screen();
@@ -53186,7 +53768,7 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
53186
53768
  }
53187
53769
  }
53188
53770
  var import_os3 = require("os");
53189
- var import_path4 = require("path");
53771
+ var import_path6 = require("path");
53190
53772
  var fs10 = __toESM2(require("fs"));
53191
53773
  var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
53192
53774
  var CHANNEL_SERVER_URL = {
@@ -53255,22 +53837,22 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
53255
53837
  }
53256
53838
  function resolveHermesUserHome() {
53257
53839
  const explicitHome = process.env.HERMES_HOME?.trim();
53258
- return explicitHome || (0, import_path4.join)((0, import_os3.homedir)(), ".hermes");
53840
+ return explicitHome || (0, import_path6.join)((0, import_os3.homedir)(), ".hermes");
53259
53841
  }
53260
53842
  function loadHermesCoordinatorBaseConfig(targetConfigPath) {
53261
53843
  const sourceHome = resolveHermesUserHome();
53262
- const sourceConfigPath = (0, import_path4.join)(sourceHome, "config.yaml");
53844
+ const sourceConfigPath = (0, import_path6.join)(sourceHome, "config.yaml");
53263
53845
  if (!fs10.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
53264
- if ((0, import_path4.resolve)(sourceConfigPath) === (0, import_path4.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
53846
+ if ((0, import_path6.resolve)(sourceConfigPath) === (0, import_path6.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
53265
53847
  const parsed = parseMeshCoordinatorMcpConfig(fs10.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
53266
53848
  const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
53267
53849
  return { config: baseConfig, sourceHome, sourceConfigPath };
53268
53850
  }
53269
53851
  function copyHermesCoordinatorCredentialFiles(sourceHome, targetHome) {
53270
- if ((0, import_path4.resolve)(sourceHome) === (0, import_path4.resolve)(targetHome)) return;
53852
+ if ((0, import_path6.resolve)(sourceHome) === (0, import_path6.resolve)(targetHome)) return;
53271
53853
  for (const fileName of [".env", "auth.json"]) {
53272
- const sourcePath = (0, import_path4.join)(sourceHome, fileName);
53273
- const targetPath = (0, import_path4.join)(targetHome, fileName);
53854
+ const sourcePath = (0, import_path6.join)(sourceHome, fileName);
53855
+ const targetPath = (0, import_path6.join)(targetHome, fileName);
53274
53856
  if (!fs10.existsSync(sourcePath)) continue;
53275
53857
  try {
53276
53858
  fs10.copyFileSync(sourcePath, targetPath);
@@ -54231,6 +54813,21 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
54231
54813
  return { success: false, error: e.message };
54232
54814
  }
54233
54815
  }
54816
+ case "get_mesh_ledger": {
54817
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
54818
+ if (!meshId) return { success: false, error: "meshId required" };
54819
+ try {
54820
+ const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
54821
+ const tail = typeof args?.tail === "number" ? args.tail : 20;
54822
+ const since = typeof args?.since === "string" ? args.since : void 0;
54823
+ const kind = Array.isArray(args?.kind) ? args.kind.filter((k) => typeof k === "string") : void 0;
54824
+ const entries = readLedgerEntries2(meshId, { tail, since, kind });
54825
+ const summary = getLedgerSummary2(meshId);
54826
+ return { success: true, entries, summary };
54827
+ } catch (e) {
54828
+ return { success: false, error: e.message };
54829
+ }
54830
+ }
54234
54831
  case "add_mesh_node": {
54235
54832
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
54236
54833
  const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
@@ -54299,6 +54896,54 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
54299
54896
  return { success: false, error: e.message };
54300
54897
  }
54301
54898
  }
54899
+ case "refine_mesh_node": {
54900
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
54901
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
54902
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
54903
+ try {
54904
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
54905
+ const mesh = meshRecord?.mesh;
54906
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
54907
+ if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
54908
+ if (!node.isLocalWorktree || !node.workspace) {
54909
+ return { success: false, error: `Refinery requires a local worktree node` };
54910
+ }
54911
+ const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
54912
+ const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
54913
+ if (!repoRoot) return { success: false, error: "Source node repoRoot not found" };
54914
+ const { execFile: execFile3 } = await import("child_process");
54915
+ const { promisify: promisify3 } = await import("util");
54916
+ const execFileAsync3 = promisify3(execFile3);
54917
+ const { stdout: branchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: node.workspace, encoding: "utf8" });
54918
+ const branch = branchStdout.trim();
54919
+ if (!branch) return { success: false, error: "Could not determine branch of the worktree node" };
54920
+ const { stdout: baseBranchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
54921
+ const baseBranch = baseBranchStdout.trim();
54922
+ try {
54923
+ await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
54924
+ } catch (e) {
54925
+ return { success: false, error: `Merge failed (conflicts?): ${e.message}` };
54926
+ }
54927
+ const removeResult = await this.execute("remove_mesh_node", {
54928
+ meshId,
54929
+ nodeId,
54930
+ sessionCleanupMode: "kill",
54931
+ inlineMesh: args?.inlineMesh
54932
+ });
54933
+ try {
54934
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
54935
+ appendLedgerEntry2(meshId, {
54936
+ kind: "node_removed",
54937
+ nodeId,
54938
+ payload: { refined: true, mergedBranch: branch, into: baseBranch }
54939
+ });
54940
+ } catch {
54941
+ }
54942
+ return { success: true, merged: true, branch, into: baseBranch, removeResult };
54943
+ } catch (e) {
54944
+ return { success: false, error: e.message };
54945
+ }
54946
+ }
54302
54947
  case "remove_mesh_node": {
54303
54948
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
54304
54949
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
@@ -54334,6 +54979,17 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
54334
54979
  const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
54335
54980
  removed = removeNode3(meshId, nodeId);
54336
54981
  }
54982
+ if (removed) {
54983
+ try {
54984
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
54985
+ appendLedgerEntry2(meshId, {
54986
+ kind: "node_removed",
54987
+ nodeId,
54988
+ payload: { worktree: !!node?.isLocalWorktree, sessionCleanupMode }
54989
+ });
54990
+ } catch {
54991
+ }
54992
+ }
54337
54993
  return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
54338
54994
  } catch (e) {
54339
54995
  return { success: false, error: e.message };
@@ -54363,9 +55019,9 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
54363
55019
  });
54364
55020
  let node;
54365
55021
  if (meshRecord.inline) {
54366
- const { randomUUID: randomUUID8 } = await import("crypto");
55022
+ const { randomUUID: randomUUID10 } = await import("crypto");
54367
55023
  node = {
54368
- id: `node_${randomUUID8().replace(/-/g, "")}`,
55024
+ id: `node_${randomUUID10().replace(/-/g, "")}`,
54369
55025
  workspace: result.worktreePath,
54370
55026
  repoRoot: result.worktreePath,
54371
55027
  daemonId: sourceNode.daemonId,
@@ -54390,6 +55046,15 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
54390
55046
  });
54391
55047
  if (!node) return { success: false, error: "Failed to register worktree node" };
54392
55048
  }
55049
+ try {
55050
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
55051
+ appendLedgerEntry2(meshId, {
55052
+ kind: "node_cloned",
55053
+ nodeId: node.id,
55054
+ payload: { sourceNodeId, branch: result.branch, worktreePath: result.worktreePath }
55055
+ });
55056
+ } catch {
55057
+ }
54393
55058
  return {
54394
55059
  success: true,
54395
55060
  node,
@@ -54400,6 +55065,19 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
54400
55065
  return { success: false, error: e.message };
54401
55066
  }
54402
55067
  }
55068
+ case "trigger_mesh_queue": {
55069
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
55070
+ if (!meshId) return { success: false, error: "meshId required" };
55071
+ try {
55072
+ const { triggerMeshQueue: triggerMeshQueue2 } = await Promise.resolve().then(() => (init_mesh_events(), mesh_events_exports));
55073
+ if (meshId) {
55074
+ triggerMeshQueue2(this.deps, meshId);
55075
+ }
55076
+ return { success: true };
55077
+ } catch (e) {
55078
+ return { success: false, error: e.message };
55079
+ }
55080
+ }
54403
55081
  // ─── Mesh Coordinator Launch ───
54404
55082
  case "launch_mesh_coordinator": {
54405
55083
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
@@ -54504,7 +55182,7 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
54504
55182
  workspace
54505
55183
  };
54506
55184
  }
54507
- const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync14, copyFileSync: copyFileSync4, mkdirSync: mkdirSync16 } = await import("fs");
55185
+ const { existsSync: existsSync25, readFileSync: readFileSync17, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
54508
55186
  const { dirname: dirname9 } = await import("path");
54509
55187
  const mcpConfigPath = coordinatorSetup.configPath;
54510
55188
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
@@ -54538,21 +55216,21 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
54538
55216
  };
54539
55217
  }
54540
55218
  try {
54541
- mkdirSync16(dirname9(mcpConfigPath), { recursive: true });
55219
+ mkdirSync17(dirname9(mcpConfigPath), { recursive: true });
54542
55220
  } catch (error48) {
54543
55221
  const message = `Could not prepare MCP config path for automatic setup: ${error48?.message || error48}`;
54544
55222
  LOG2.error("MeshCoordinator", message);
54545
55223
  if (hermesManualFallback) return returnManualFallback(message);
54546
55224
  return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
54547
55225
  }
54548
- const hadExistingMcpConfig = existsSync23(mcpConfigPath);
55226
+ const hadExistingMcpConfig = existsSync25(mcpConfigPath);
54549
55227
  let existingMcpConfig = hermesBaseConfig?.config || {};
54550
55228
  if (hermesBaseConfig) {
54551
55229
  copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
54552
55230
  }
54553
55231
  if (hadExistingMcpConfig) {
54554
55232
  try {
54555
- const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
55233
+ const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync17(mcpConfigPath, "utf-8"), configFormat);
54556
55234
  existingMcpConfig = { ...existingMcpConfig, ...parsedExistingMcpConfig };
54557
55235
  copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
54558
55236
  } catch (error48) {
@@ -54574,7 +55252,7 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
54574
55252
  }
54575
55253
  };
54576
55254
  try {
54577
- writeFileSync14(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
55255
+ writeFileSync15(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
54578
55256
  } catch (error48) {
54579
55257
  const message = `Could not write MCP config for automatic setup: ${error48?.message || error48}`;
54580
55258
  LOG2.error("MeshCoordinator", message);
@@ -54611,6 +55289,16 @@ ${(0, import_node_path.resolve)(workspace || os17.tmpdir())}`;
54611
55289
  return { success: false, error: launchResult?.error || "Failed to launch CLI session" };
54612
55290
  }
54613
55291
  LOG2.info("MeshCoordinator", `Launched ${cliType} coordinator for mesh ${meshId} in ${workspace}`);
55292
+ try {
55293
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
55294
+ appendLedgerEntry2(meshId, {
55295
+ kind: "coordinator_started",
55296
+ sessionId: launchResult.sessionId || launchResult.id,
55297
+ providerType: cliType,
55298
+ payload: { workspace }
55299
+ });
55300
+ } catch {
55301
+ }
54614
55302
  return {
54615
55303
  success: true,
54616
55304
  meshId,
@@ -62344,6 +63032,7 @@ data: ${JSON.stringify(msg.data)}
62344
63032
  };
62345
63033
  init_logger();
62346
63034
  init_config();
63035
+ init_mesh_events();
62347
63036
  async function initDaemonComponents2(config2) {
62348
63037
  installGlobalInterceptor();
62349
63038
  const appConfig = loadConfig2();