@adhdev/daemon-core 0.9.77-rc.1 → 0.9.77-rc.11

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
@@ -43,7 +43,8 @@ var init_repo_mesh_types = __esm({
43
43
  dirtyWorkspaceBehavior: "warn",
44
44
  maxParallelTasks: 2,
45
45
  spawnedSessionVisibility: "visible",
46
- sessionCleanupOnNodeRemove: "preserve"
46
+ sessionCleanupOnNodeRemove: "preserve",
47
+ maxTaskRetries: 1
47
48
  };
48
49
  }
49
50
  });
@@ -673,12 +674,13 @@ function buildRulesSection(coordinatorCliType) {
673
674
  return `## Rules
674
675
 
675
676
  - **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.
676
- - **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.
677
+ - **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.
677
678
  - **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.
678
- - **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.
679
+ - **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.
679
680
  - **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.
680
681
  - **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.
681
- - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
682
+ - **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.
683
+ - **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.
682
684
  - **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
683
685
  - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
684
686
  - **Never fabricate tool results.** Always call the actual tool; never pretend you did.
@@ -699,6 +701,7 @@ var init_coordinator_prompt = __esm({
699
701
  | \`mesh_launch_session\` | Start a new agent session on a node |
700
702
  | \`mesh_send_task\` | Send a task (natural language) to a running agent |
701
703
  | \`mesh_read_chat\` | Read an agent's recent messages to check progress |
704
+ | \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
702
705
  | \`mesh_git_status\` | Check git status on a specific node |
703
706
  | \`mesh_checkpoint\` | Create a git checkpoint on a node |
704
707
  | \`mesh_approve\` | Approve/reject a pending agent action |
@@ -709,18 +712,366 @@ var init_coordinator_prompt = __esm({
709
712
  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\`.`;
710
713
  WORKFLOW_SECTION = `## Orchestration Workflow
711
714
 
712
- 1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
713
- 2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
714
- 3. **Delegate** \u2014 For each task:
715
- a. Pick the best node (consider: health, dirty state, current workload).
716
- b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
717
- c. If no session exists, call \`mesh_launch_session\` to start one.
718
- 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.
719
- 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\`.
715
+ 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.
716
+ 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.
717
+ 3. **Queue / Delegate** \u2014 The Mesh uses an autonomous pull-based Work Queue:
718
+ a. **General Tasks**: Enqueue tasks using \`mesh_enqueue_task\`. Idle node agents will automatically pull tasks from the queue and begin working.
719
+ 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.
720
+ 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.
721
+ 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.
722
+ 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\`.
720
723
  5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
721
724
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
722
725
  7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
723
- 8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
726
+ 8. **Report** \u2014 Summarize what was done, what changed, and any issues.
727
+
728
+ ## Failure Recovery
729
+
730
+ When a node agent stops unexpectedly, the daemon automatically enriches the system message with **Recovery Context** that includes:
731
+ - The number of consecutive failures on that node
732
+ - The original task message (if recorded in the ledger)
733
+ - A recommendation: **retry**, **reassign**, or **escalate**
734
+
735
+ Follow these recovery rules:
736
+ 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.
737
+ 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.
738
+ 3. **If no recovery context**: The stop may be intentional (normal completion). Use \`mesh_read_chat\` once to verify, then move on.
739
+ 4. **Always record what happened**: After handling a failure, briefly note the outcome in your report to the user.`;
740
+ }
741
+ });
742
+
743
+ // src/mesh/mesh-ledger.ts
744
+ var mesh_ledger_exports = {};
745
+ __export(mesh_ledger_exports, {
746
+ appendLedgerEntry: () => appendLedgerEntry,
747
+ appendRemoteLedgerEntries: () => appendRemoteLedgerEntries,
748
+ getLedgerDir: () => getLedgerDir,
749
+ getLedgerSummary: () => getLedgerSummary,
750
+ getSessionRecoveryContext: () => getSessionRecoveryContext,
751
+ meshLedgerEvents: () => meshLedgerEvents,
752
+ readLedgerEntries: () => readLedgerEntries
753
+ });
754
+ function getLedgerDir() {
755
+ const dir = (0, import_path3.join)(getConfigDir(), LEDGER_DIR_NAME);
756
+ if (!(0, import_fs3.existsSync)(dir)) {
757
+ (0, import_fs3.mkdirSync)(dir, { recursive: true, mode: 448 });
758
+ }
759
+ return dir;
760
+ }
761
+ function getLedgerPath(meshId) {
762
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
763
+ return (0, import_path3.join)(getLedgerDir(), `${safe}.jsonl`);
764
+ }
765
+ function getRotatedPath(meshId, index) {
766
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
767
+ return (0, import_path3.join)(getLedgerDir(), `${safe}.${index}.jsonl`);
768
+ }
769
+ function appendLedgerEntry(meshId, partial) {
770
+ const entry = {
771
+ id: (0, import_crypto4.randomUUID)(),
772
+ meshId,
773
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
774
+ ...partial
775
+ };
776
+ const filePath = getLedgerPath(meshId);
777
+ if ((0, import_fs3.existsSync)(filePath)) {
778
+ try {
779
+ const stat2 = (0, import_fs3.statSync)(filePath);
780
+ if (stat2.size >= MAX_FILE_SIZE_BYTES) {
781
+ rotateLedgerFile(meshId, filePath);
782
+ }
783
+ } catch {
784
+ }
785
+ }
786
+ try {
787
+ const line = JSON.stringify(entry) + "\n";
788
+ (0, import_fs3.appendFileSync)(filePath, line, { encoding: "utf-8", mode: 384 });
789
+ meshLedgerEvents.emit("append", meshId, entry);
790
+ return entry;
791
+ } catch (e) {
792
+ throw new Error(`Failed to append to ledger for mesh ${meshId}: ${e.message}`);
793
+ }
794
+ }
795
+ function appendRemoteLedgerEntries(meshId, entries) {
796
+ if (entries.length === 0) return;
797
+ const ledgerPath = getLedgerPath(meshId);
798
+ const existing = new Set(readLedgerEntries(meshId).map((e) => e.id));
799
+ const newEntries = entries.filter((e) => !existing.has(e.id));
800
+ if (newEntries.length === 0) return;
801
+ try {
802
+ const lines = newEntries.map((e) => JSON.stringify(e)).join("\n") + "\n";
803
+ (0, import_fs3.appendFileSync)(ledgerPath, lines, { encoding: "utf-8", mode: 384 });
804
+ } catch (e) {
805
+ throw new Error(`Failed to append remote ledger entries for mesh ${meshId}: ${e.message}`);
806
+ }
807
+ }
808
+ function readLedgerEntries(meshId, opts) {
809
+ const filePath = getLedgerPath(meshId);
810
+ if (!(0, import_fs3.existsSync)(filePath)) return [];
811
+ let content;
812
+ try {
813
+ content = (0, import_fs3.readFileSync)(filePath, "utf-8");
814
+ } catch {
815
+ return [];
816
+ }
817
+ const lines = content.split("\n").filter((line) => line.trim());
818
+ let entries = [];
819
+ for (const line of lines) {
820
+ try {
821
+ const entry = JSON.parse(line);
822
+ if (!entry.id || !entry.kind) continue;
823
+ entries.push(entry);
824
+ } catch {
825
+ }
826
+ }
827
+ if (opts?.since) {
828
+ const sinceDate = new Date(opts.since).getTime();
829
+ if (!isNaN(sinceDate)) {
830
+ entries = entries.filter((e) => new Date(e.timestamp).getTime() >= sinceDate);
831
+ }
832
+ }
833
+ if (opts?.kind?.length) {
834
+ const kindSet = new Set(opts.kind);
835
+ entries = entries.filter((e) => kindSet.has(e.kind));
836
+ }
837
+ if (opts?.tail && opts.tail > 0 && entries.length > opts.tail) {
838
+ entries = entries.slice(-opts.tail);
839
+ }
840
+ return entries;
841
+ }
842
+ function getLedgerSummary(meshId) {
843
+ const entries = readLedgerEntries(meshId);
844
+ const now = Date.now();
845
+ const recentFailureCutoff = now - RECENT_FAILURE_WINDOW_MS;
846
+ const summary = {
847
+ meshId,
848
+ totalEntries: entries.length,
849
+ taskDispatched: 0,
850
+ taskCompleted: 0,
851
+ taskFailed: 0,
852
+ taskStalled: 0,
853
+ sessionLaunched: 0,
854
+ checkpointCreated: 0,
855
+ lastActivityAt: null,
856
+ recentFailures: 0
857
+ };
858
+ for (const entry of entries) {
859
+ switch (entry.kind) {
860
+ case "task_dispatched":
861
+ summary.taskDispatched++;
862
+ break;
863
+ case "task_completed":
864
+ summary.taskCompleted++;
865
+ break;
866
+ case "task_failed": {
867
+ summary.taskFailed++;
868
+ if (new Date(entry.timestamp).getTime() >= recentFailureCutoff) {
869
+ summary.recentFailures++;
870
+ }
871
+ break;
872
+ }
873
+ case "task_stalled":
874
+ summary.taskStalled++;
875
+ break;
876
+ case "session_launched":
877
+ summary.sessionLaunched++;
878
+ break;
879
+ case "checkpoint_created":
880
+ summary.checkpointCreated++;
881
+ break;
882
+ }
883
+ }
884
+ if (entries.length > 0) {
885
+ summary.lastActivityAt = entries[entries.length - 1].timestamp;
886
+ }
887
+ return summary;
888
+ }
889
+ function getSessionRecoveryContext(meshId, opts) {
890
+ const maxRetries = opts.maxRetries ?? 1;
891
+ const entries = readLedgerEntries(meshId);
892
+ let lastDispatch = null;
893
+ for (let i = entries.length - 1; i >= 0; i--) {
894
+ const e = entries[i];
895
+ if (e.kind !== "task_dispatched") continue;
896
+ if (opts.sessionId && e.sessionId === opts.sessionId) {
897
+ lastDispatch = e;
898
+ break;
899
+ }
900
+ if (opts.nodeId && e.nodeId === opts.nodeId) {
901
+ lastDispatch = e;
902
+ break;
903
+ }
904
+ }
905
+ const lastTaskMessage = typeof lastDispatch?.payload?.message === "string" ? lastDispatch.payload.message : null;
906
+ const now = Date.now();
907
+ const recentWindow = now - RECENT_FAILURE_WINDOW_MS;
908
+ let consecutiveNodeFailures = 0;
909
+ for (let i = entries.length - 1; i >= 0; i--) {
910
+ const e = entries[i];
911
+ if (new Date(e.timestamp).getTime() < recentWindow) break;
912
+ if (opts.nodeId && e.nodeId !== opts.nodeId) continue;
913
+ if (e.kind === "task_failed") {
914
+ consecutiveNodeFailures++;
915
+ } else if (e.kind === "task_completed" || e.kind === "task_dispatched") {
916
+ break;
917
+ }
918
+ }
919
+ let taskAttemptCount = 0;
920
+ if (lastTaskMessage) {
921
+ const prefix = lastTaskMessage.slice(0, 200);
922
+ for (const e of entries) {
923
+ if (e.kind === "task_dispatched" && typeof e.payload?.message === "string") {
924
+ if (e.payload.message.startsWith(prefix)) {
925
+ taskAttemptCount++;
926
+ }
927
+ }
928
+ }
929
+ }
930
+ const retryRecommended = consecutiveNodeFailures <= maxRetries;
931
+ let advice;
932
+ if (consecutiveNodeFailures === 0) {
933
+ advice = "No recent failures detected. This may be a normal stop.";
934
+ } else if (retryRecommended) {
935
+ const remaining = maxRetries - consecutiveNodeFailures + 1;
936
+ 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.`);
937
+ } else {
938
+ advice = `Max retries exceeded (${consecutiveNodeFailures} consecutive failures). Consider: (1) reassigning to a different node, (2) simplifying the task, or (3) escalating to the user.`;
939
+ }
940
+ return {
941
+ lastTaskMessage,
942
+ failedNodeId: opts.nodeId || null,
943
+ failedSessionId: opts.sessionId || null,
944
+ failedProviderType: null,
945
+ // filled by caller if available
946
+ consecutiveNodeFailures,
947
+ taskAttemptCount,
948
+ retryRecommended,
949
+ advice
950
+ };
951
+ }
952
+ function rotateLedgerFile(meshId, currentPath) {
953
+ let index = 1;
954
+ while ((0, import_fs3.existsSync)(getRotatedPath(meshId, index))) {
955
+ index++;
956
+ if (index > 10) break;
957
+ }
958
+ if (index > 10) index = 10;
959
+ try {
960
+ (0, import_fs3.renameSync)(currentPath, getRotatedPath(meshId, index));
961
+ } catch {
962
+ }
963
+ }
964
+ var import_fs3, import_path3, import_crypto4, import_events, LEDGER_DIR_NAME, MAX_FILE_SIZE_BYTES, RECENT_FAILURE_WINDOW_MS, meshLedgerEvents;
965
+ var init_mesh_ledger = __esm({
966
+ "src/mesh/mesh-ledger.ts"() {
967
+ "use strict";
968
+ import_fs3 = require("fs");
969
+ import_path3 = require("path");
970
+ import_crypto4 = require("crypto");
971
+ init_config();
972
+ import_events = require("events");
973
+ LEDGER_DIR_NAME = "mesh-ledger";
974
+ MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024;
975
+ RECENT_FAILURE_WINDOW_MS = 30 * 60 * 1e3;
976
+ meshLedgerEvents = new import_events.EventEmitter();
977
+ }
978
+ });
979
+
980
+ // src/mesh/mesh-work-queue.ts
981
+ function getQueuePath(meshId) {
982
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
983
+ return (0, import_path4.join)(getLedgerDir(), `${safe}.queue.json`);
984
+ }
985
+ function readQueue(meshId) {
986
+ const path28 = getQueuePath(meshId);
987
+ if (!(0, import_fs4.existsSync)(path28)) return [];
988
+ try {
989
+ const content = (0, import_fs4.readFileSync)(path28, "utf-8");
990
+ return JSON.parse(content);
991
+ } catch {
992
+ return [];
993
+ }
994
+ }
995
+ function writeQueue(meshId, queue) {
996
+ const path28 = getQueuePath(meshId);
997
+ (0, import_fs4.writeFileSync)(path28, JSON.stringify(queue, null, 2), "utf-8");
998
+ }
999
+ function enqueueTask(meshId, message, opts) {
1000
+ const queue = readQueue(meshId);
1001
+ const entry = {
1002
+ id: (0, import_crypto5.randomUUID)(),
1003
+ meshId,
1004
+ message,
1005
+ status: "pending",
1006
+ targetNodeId: opts?.targetNodeId,
1007
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1008
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1009
+ };
1010
+ queue.push(entry);
1011
+ writeQueue(meshId, queue);
1012
+ return entry;
1013
+ }
1014
+ function getQueue(meshId, opts) {
1015
+ let queue = readQueue(meshId);
1016
+ if (opts?.status?.length) {
1017
+ const statuses = new Set(opts.status);
1018
+ queue = queue.filter((q) => statuses.has(q.status));
1019
+ }
1020
+ return queue;
1021
+ }
1022
+ function claimNextTask(meshId, nodeId, sessionId) {
1023
+ const queue = readQueue(meshId);
1024
+ let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId);
1025
+ if (targetIdx === -1) {
1026
+ targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId);
1027
+ }
1028
+ if (targetIdx === -1) return null;
1029
+ const entry = queue[targetIdx];
1030
+ entry.status = "assigned";
1031
+ entry.assignedNodeId = nodeId;
1032
+ entry.assignedSessionId = sessionId;
1033
+ entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1034
+ writeQueue(meshId, queue);
1035
+ return entry;
1036
+ }
1037
+ function updateTaskStatus(meshId, taskId, status) {
1038
+ const queue = readQueue(meshId);
1039
+ const idx = queue.findIndex((q) => q.id === taskId);
1040
+ if (idx === -1) return null;
1041
+ queue[idx].status = status;
1042
+ queue[idx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1043
+ writeQueue(meshId, queue);
1044
+ return queue[idx];
1045
+ }
1046
+ function updateSessionTaskStatus(meshId, sessionId, status) {
1047
+ const queue = readQueue(meshId);
1048
+ for (let i = queue.length - 1; i >= 0; i--) {
1049
+ if (queue[i].assignedSessionId === sessionId && queue[i].status === "assigned") {
1050
+ queue[i].status = status;
1051
+ queue[i].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1052
+ writeQueue(meshId, queue);
1053
+ return queue[i];
1054
+ }
1055
+ }
1056
+ return null;
1057
+ }
1058
+ function getMeshQueueStats(meshId) {
1059
+ const queue = readQueue(meshId);
1060
+ return {
1061
+ pending: queue.filter((q) => q.status === "pending").length,
1062
+ assigned: queue.filter((q) => q.status === "assigned").length,
1063
+ completed: queue.filter((q) => q.status === "completed").length,
1064
+ failed: queue.filter((q) => q.status === "failed").length
1065
+ };
1066
+ }
1067
+ var import_fs4, import_path4, import_crypto5;
1068
+ var init_mesh_work_queue = __esm({
1069
+ "src/mesh/mesh-work-queue.ts"() {
1070
+ "use strict";
1071
+ import_fs4 = require("fs");
1072
+ import_path4 = require("path");
1073
+ import_crypto5 = require("crypto");
1074
+ init_mesh_ledger();
724
1075
  }
725
1076
  });
726
1077
 
@@ -739,13 +1090,13 @@ function getDaemonLogDir() {
739
1090
  return LOG_DIR;
740
1091
  }
741
1092
  function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
742
- return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
1093
+ return path8.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
743
1094
  }
744
1095
  function checkDateRotation() {
745
1096
  const today = getDateStr();
746
1097
  if (today !== currentDate) {
747
1098
  currentDate = today;
748
- currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
1099
+ currentLogFile = path8.join(LOG_DIR, `daemon-${currentDate}.log`);
749
1100
  cleanOldLogs();
750
1101
  }
751
1102
  }
@@ -759,7 +1110,7 @@ function cleanOldLogs() {
759
1110
  const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
760
1111
  if (dateMatch && dateMatch[1] < cutoffStr) {
761
1112
  try {
762
- fs2.unlinkSync(path10.join(LOG_DIR, file));
1113
+ fs2.unlinkSync(path8.join(LOG_DIR, file));
763
1114
  } catch {
764
1115
  }
765
1116
  }
@@ -875,17 +1226,17 @@ function installGlobalInterceptor() {
875
1226
  writeToFile(`Log file: ${currentLogFile}`);
876
1227
  writeToFile(`Log level: ${currentLevel}`);
877
1228
  }
878
- var fs2, path10, os4, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
1229
+ var fs2, path8, os2, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
879
1230
  var init_logger = __esm({
880
1231
  "src/logging/logger.ts"() {
881
1232
  "use strict";
882
1233
  fs2 = __toESM(require("fs"));
883
- path10 = __toESM(require("path"));
884
- os4 = __toESM(require("os"));
1234
+ path8 = __toESM(require("path"));
1235
+ os2 = __toESM(require("os"));
885
1236
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
886
1237
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
887
1238
  currentLevel = "info";
888
- LOG_DIR = process.platform === "win32" ? path10.join(process.env.LOCALAPPDATA || process.env.APPDATA || path10.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path10.join(os4.homedir(), "Library", "Logs", "adhdev") : path10.join(os4.homedir(), ".local", "share", "adhdev", "logs");
1239
+ LOG_DIR = process.platform === "win32" ? path8.join(process.env.LOCALAPPDATA || process.env.APPDATA || path8.join(os2.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path8.join(os2.homedir(), "Library", "Logs", "adhdev") : path8.join(os2.homedir(), ".local", "share", "adhdev", "logs");
889
1240
  MAX_LOG_SIZE = 5 * 1024 * 1024;
890
1241
  MAX_LOG_DAYS = 7;
891
1242
  try {
@@ -893,16 +1244,16 @@ var init_logger = __esm({
893
1244
  } catch {
894
1245
  }
895
1246
  currentDate = getDateStr();
896
- currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
1247
+ currentLogFile = path8.join(LOG_DIR, `daemon-${currentDate}.log`);
897
1248
  cleanOldLogs();
898
1249
  try {
899
- const oldLog = path10.join(LOG_DIR, "daemon.log");
1250
+ const oldLog = path8.join(LOG_DIR, "daemon.log");
900
1251
  if (fs2.existsSync(oldLog)) {
901
1252
  const stat2 = fs2.statSync(oldLog);
902
1253
  const oldDate = stat2.mtime.toISOString().slice(0, 10);
903
- fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
1254
+ fs2.renameSync(oldLog, path8.join(LOG_DIR, `daemon-${oldDate}.log`));
904
1255
  }
905
- const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
1256
+ const oldLogBackup = path8.join(LOG_DIR, "daemon.log.old");
906
1257
  if (fs2.existsSync(oldLogBackup)) {
907
1258
  fs2.unlinkSync(oldLogBackup);
908
1259
  }
@@ -934,7 +1285,313 @@ var init_logger = __esm({
934
1285
  }
935
1286
  };
936
1287
  interceptorInstalled = false;
937
- LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
1288
+ LOG_PATH = path8.join(LOG_DIR, `daemon-${getDateStr()}.log`);
1289
+ }
1290
+ });
1291
+
1292
+ // src/mesh/mesh-events.ts
1293
+ var mesh_events_exports = {};
1294
+ __export(mesh_events_exports, {
1295
+ drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
1296
+ handleMeshForwardEvent: () => handleMeshForwardEvent,
1297
+ setupMeshEventForwarding: () => setupMeshEventForwarding,
1298
+ triggerMeshQueue: () => triggerMeshQueue,
1299
+ tryAssignQueueTask: () => tryAssignQueueTask
1300
+ });
1301
+ function drainPendingMeshCoordinatorEvents() {
1302
+ return pendingMeshCoordinatorEvents.splice(0);
1303
+ }
1304
+ function readNonEmptyString(value) {
1305
+ return typeof value === "string" && value.trim() ? value.trim() : "";
1306
+ }
1307
+ function isMeshCoordinatorEvent(eventName) {
1308
+ return typeof eventName === "string" && MESH_COORDINATOR_EVENTS.has(eventName);
1309
+ }
1310
+ function formatCompletionMetadata(event) {
1311
+ const parts = [
1312
+ readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
1313
+ readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
1314
+ readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
1315
+ ].filter(Boolean);
1316
+ return parts.length > 0 ? ` (${parts.join("; ")})` : "";
1317
+ }
1318
+ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
1319
+ const task = claimNextTask(meshId, nodeId, sessionId);
1320
+ if (!task) return false;
1321
+ LOG.info("MeshQueue", `Node ${nodeId} (${sessionId}) pulled task ${task.id}`);
1322
+ components.cliManager.handleCliCommand("agent_command", {
1323
+ targetSessionId: sessionId,
1324
+ cliType: providerType,
1325
+ action: "send_chat",
1326
+ message: task.message
1327
+ }).catch((e) => {
1328
+ LOG.error("MeshQueue", `Failed to dispatch task to node ${nodeId}: ${e?.message}`);
1329
+ });
1330
+ return true;
1331
+ }
1332
+ function triggerMeshQueue(components, meshId) {
1333
+ const mesh = getMesh(meshId);
1334
+ if (!mesh) return;
1335
+ const cliInstances = components.instanceManager.getByCategory("cli");
1336
+ for (const inst of cliInstances) {
1337
+ const state = inst.getState();
1338
+ const settings = state.settings || {};
1339
+ const instMeshId = readNonEmptyString(settings.meshNodeFor);
1340
+ if (instMeshId !== meshId && !settings.launchedByCoordinator) continue;
1341
+ const nodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
1342
+ if (!nodeId) continue;
1343
+ if (state.status !== "idle" && state.status !== "stopped" && state.activeChat?.status !== "waiting_input") continue;
1344
+ const sessionId = state.instanceId;
1345
+ const providerType = state.type || readNonEmptyString(settings.providerType);
1346
+ if (providerType) {
1347
+ tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType);
1348
+ }
1349
+ }
1350
+ }
1351
+ function buildMeshSystemMessage(args) {
1352
+ const metadata = formatCompletionMetadata(args.metadataEvent);
1353
+ if (args.event === "agent:generating_completed") {
1354
+ 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.`;
1355
+ }
1356
+ if (args.event === "agent:waiting_approval") {
1357
+ return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
1358
+ }
1359
+ if (args.event === "agent:stopped") {
1360
+ const rc = args.recoveryContext;
1361
+ if (rc && rc.consecutiveNodeFailures > 0) {
1362
+ const parts = [
1363
+ `[System] ${args.nodeLabel} has stopped unexpectedly${metadata}.`,
1364
+ `
1365
+
1366
+ **Recovery Context:**`,
1367
+ `- Consecutive failures on this node: ${rc.consecutiveNodeFailures}`,
1368
+ rc.taskAttemptCount > 0 ? `- This task has been attempted ${rc.taskAttemptCount} time(s)` : "",
1369
+ `- Recommendation: ${rc.advice}`
1370
+ ];
1371
+ if (rc.retryRecommended && rc.lastTaskMessage) {
1372
+ parts.push(
1373
+ `
1374
+
1375
+ **Original task to retry:**`,
1376
+ `> ${rc.lastTaskMessage.length > 300 ? rc.lastTaskMessage.slice(0, 300) + "..." : rc.lastTaskMessage}`,
1377
+ `
1378
+ To retry: call \`mesh_launch_session\` for this node, then \`mesh_send_task\` with the original task.`
1379
+ );
1380
+ } else if (!rc.retryRecommended) {
1381
+ parts.push(
1382
+ `
1383
+ Do NOT retry on this node. Consider reassigning to a different node or asking the user for guidance.`
1384
+ );
1385
+ }
1386
+ return parts.filter(Boolean).join("\n");
1387
+ }
1388
+ return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
1389
+ }
1390
+ if (args.event === "monitor:long_generating") {
1391
+ 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.`;
1392
+ }
1393
+ return "";
1394
+ }
1395
+ function injectMeshSystemMessage(components, args) {
1396
+ if (args.event === "agent:generating_completed") {
1397
+ const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
1398
+ const nodeId = readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
1399
+ const providerType = readNonEmptyString(args.metadataEvent.providerType);
1400
+ if (sessionId) {
1401
+ updateSessionTaskStatus(args.meshId, sessionId, "completed");
1402
+ if (nodeId && providerType) {
1403
+ setTimeout(() => {
1404
+ tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
1405
+ }, 500);
1406
+ }
1407
+ }
1408
+ } else if (args.event === "agent:stopped") {
1409
+ const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
1410
+ if (sessionId) {
1411
+ updateSessionTaskStatus(args.meshId, sessionId, "failed");
1412
+ }
1413
+ }
1414
+ const ledgerKind = EVENT_TO_LEDGER_KIND[args.event];
1415
+ if (ledgerKind) {
1416
+ try {
1417
+ appendLedgerEntry(args.meshId, {
1418
+ kind: ledgerKind,
1419
+ nodeId: readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
1420
+ sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || void 0,
1421
+ providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
1422
+ payload: {
1423
+ event: args.event,
1424
+ nodeLabel: args.nodeLabel,
1425
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0
1426
+ }
1427
+ });
1428
+ } catch (e) {
1429
+ LOG.warn("MeshLedger", `Failed to record ${ledgerKind}: ${e?.message || e}`);
1430
+ }
1431
+ }
1432
+ let recoveryContext = null;
1433
+ if (args.event === "agent:stopped") {
1434
+ try {
1435
+ const mesh = getMesh(args.meshId);
1436
+ const maxRetries = mesh?.policy?.maxTaskRetries ?? 1;
1437
+ recoveryContext = getSessionRecoveryContext(args.meshId, {
1438
+ sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || void 0,
1439
+ nodeId: readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
1440
+ maxRetries
1441
+ });
1442
+ recoveryContext.failedProviderType = readNonEmptyString(args.metadataEvent.providerType) || null;
1443
+ if (recoveryContext.retryRecommended && recoveryContext.consecutiveNodeFailures > 0) {
1444
+ appendLedgerEntry(args.meshId, {
1445
+ kind: "recovery_attempted",
1446
+ nodeId: recoveryContext.failedNodeId || void 0,
1447
+ sessionId: recoveryContext.failedSessionId || void 0,
1448
+ providerType: recoveryContext.failedProviderType || void 0,
1449
+ payload: {
1450
+ consecutiveFailures: recoveryContext.consecutiveNodeFailures,
1451
+ taskAttemptCount: recoveryContext.taskAttemptCount,
1452
+ retryRecommended: recoveryContext.retryRecommended,
1453
+ advice: recoveryContext.advice
1454
+ }
1455
+ });
1456
+ if (recoveryContext.lastTaskMessage && recoveryContext.failedNodeId && recoveryContext.failedProviderType) {
1457
+ const autoNodeId = recoveryContext.failedNodeId;
1458
+ try {
1459
+ const task = enqueueTask(args.meshId, recoveryContext.lastTaskMessage, {
1460
+ targetNodeId: autoNodeId
1461
+ });
1462
+ LOG.info("MeshRecovery", `Auto-requeued failed task: ${task.id} for node ${autoNodeId}`);
1463
+ const node = mesh?.nodes.find((n) => n.id === autoNodeId);
1464
+ if (node) {
1465
+ components.cliManager.handleCliCommand("launch_cli", {
1466
+ cliType: recoveryContext.failedProviderType,
1467
+ dir: node.workspace,
1468
+ settings: {
1469
+ meshNodeFor: args.meshId,
1470
+ meshNodeId: node.id,
1471
+ spawnedSessionVisibility: mesh?.policy?.spawnedSessionVisibility || "hidden",
1472
+ launchedByCoordinator: true
1473
+ }
1474
+ }).catch((e) => LOG.error("MeshRecovery", `Failed to auto-relaunch session for ${node.id}: ${e?.message}`));
1475
+ }
1476
+ } catch (e) {
1477
+ LOG.warn("MeshRecovery", `Failed to execute auto-recovery: ${e?.message}`);
1478
+ }
1479
+ }
1480
+ }
1481
+ LOG.info("MeshRecovery", `Recovery context for ${args.nodeLabel}: ${recoveryContext.advice}`);
1482
+ } catch (e) {
1483
+ LOG.warn("MeshRecovery", `Failed to build recovery context: ${e?.message || e}`);
1484
+ }
1485
+ }
1486
+ const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
1487
+ const instState = inst.getState();
1488
+ if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
1489
+ if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
1490
+ return true;
1491
+ });
1492
+ if (coordinatorInstances.length === 0) {
1493
+ if (pendingMeshCoordinatorEvents.length < MAX_PENDING_EVENTS) {
1494
+ pendingMeshCoordinatorEvents.push({
1495
+ event: args.event,
1496
+ meshId: args.meshId,
1497
+ nodeLabel: args.nodeLabel,
1498
+ metadataEvent: {
1499
+ ...args.metadataEvent,
1500
+ ...recoveryContext ? { recoveryContext } : {}
1501
+ },
1502
+ queuedAt: Date.now()
1503
+ });
1504
+ LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
1505
+ }
1506
+ return { success: true, forwarded: 0 };
1507
+ }
1508
+ const messageText = buildMeshSystemMessage({
1509
+ event: args.event,
1510
+ nodeLabel: args.nodeLabel,
1511
+ metadataEvent: args.metadataEvent,
1512
+ recoveryContext
1513
+ });
1514
+ if (!messageText) return { success: false, error: "unsupported mesh event" };
1515
+ for (const coord of coordinatorInstances) {
1516
+ const coordState = coord.getState();
1517
+ LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
1518
+ coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
1519
+ }
1520
+ return { success: true, forwarded: coordinatorInstances.length };
1521
+ }
1522
+ function handleMeshForwardEvent(components, payload) {
1523
+ const eventName = readNonEmptyString(payload.event);
1524
+ if (!isMeshCoordinatorEvent(eventName)) {
1525
+ return { success: false, error: "unsupported mesh event" };
1526
+ }
1527
+ const meshId = readNonEmptyString(payload.meshId);
1528
+ if (!meshId) return { success: false, error: "meshId required" };
1529
+ const nodeId = readNonEmptyString(payload.nodeId);
1530
+ const workspace = readNonEmptyString(payload.workspace);
1531
+ const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
1532
+ return injectMeshSystemMessage(components, {
1533
+ meshId,
1534
+ nodeLabel,
1535
+ event: eventName,
1536
+ metadataEvent: {
1537
+ targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
1538
+ providerType: readNonEmptyString(payload.providerType),
1539
+ providerSessionId: readNonEmptyString(payload.providerSessionId)
1540
+ }
1541
+ });
1542
+ }
1543
+ function setupMeshEventForwarding(components) {
1544
+ components.instanceManager.onEvent((event) => {
1545
+ if (!isMeshCoordinatorEvent(event.event)) return;
1546
+ const instanceId = readNonEmptyString(event.instanceId);
1547
+ if (!instanceId) return;
1548
+ const sourceInstance = components.instanceManager.getInstance(instanceId);
1549
+ if (!sourceInstance || sourceInstance.category !== "cli") return;
1550
+ const state = sourceInstance.getState();
1551
+ const workspace = readNonEmptyString(state.workspace);
1552
+ if (!workspace) return;
1553
+ const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
1554
+ if (readNonEmptyString(settings.meshCoordinatorFor)) return;
1555
+ const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
1556
+ const isMeshDelegate = Boolean(meshIdFromRuntime || settings.launchedByCoordinator);
1557
+ if (!isMeshDelegate) return;
1558
+ const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
1559
+ const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
1560
+ if (!meshId) return;
1561
+ const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
1562
+ const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
1563
+ const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
1564
+ injectMeshSystemMessage(components, {
1565
+ meshId,
1566
+ sourceInstanceId: instanceId,
1567
+ nodeLabel,
1568
+ event: event.event,
1569
+ metadataEvent: event
1570
+ });
1571
+ });
1572
+ }
1573
+ var MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND;
1574
+ var init_mesh_events = __esm({
1575
+ "src/mesh/mesh-events.ts"() {
1576
+ "use strict";
1577
+ init_mesh_config();
1578
+ init_logger();
1579
+ init_mesh_ledger();
1580
+ init_mesh_work_queue();
1581
+ MAX_PENDING_EVENTS = 50;
1582
+ pendingMeshCoordinatorEvents = [];
1583
+ MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
1584
+ "agent:generating_completed",
1585
+ "agent:waiting_approval",
1586
+ "agent:stopped",
1587
+ "monitor:long_generating"
1588
+ ]);
1589
+ EVENT_TO_LEDGER_KIND = {
1590
+ "agent:generating_completed": "task_completed",
1591
+ "agent:waiting_approval": "task_approval_needed",
1592
+ "agent:stopped": "task_failed",
1593
+ "monitor:long_generating": "task_stalled"
1594
+ };
938
1595
  }
939
1596
  });
940
1597
 
@@ -2042,6 +2699,8 @@ var init_provider_cli_adapter = __esm({
2042
2699
  statusHistory = [];
2043
2700
  // ─── CLI Scripts (script-based parsing) ───
2044
2701
  cliScripts;
2702
+ /** Per-session opaque state object created by cliScripts.createState(), reset on stop. */
2703
+ scriptState = null;
2045
2704
  runtimeSettings = {};
2046
2705
  /** Full accumulated rendered PTY transcript for parser/readback use */
2047
2706
  accumulatedBuffer = "";
@@ -2223,6 +2882,7 @@ ${lastSnapshot}`;
2223
2882
  this.cliScripts = scripts;
2224
2883
  this.parsedStatusCache = null;
2225
2884
  this.parseErrorMessage = null;
2885
+ this.scriptState = typeof scripts.createState === "function" ? scripts.createState() : null;
2226
2886
  const scriptNames = listCliScriptNames(scripts);
2227
2887
  LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
2228
2888
  }
@@ -2340,6 +3000,7 @@ ${lastSnapshot}`;
2340
3000
  this.ready = false;
2341
3001
  this.startupParseGate = false;
2342
3002
  this.spawnAt = 0;
3003
+ this.scriptState = null;
2343
3004
  this.onStatusChange?.();
2344
3005
  });
2345
3006
  this.spawnAt = Date.now();
@@ -3113,7 +3774,7 @@ ${lastSnapshot}`;
3113
3774
  scope: this.currentTurnScope,
3114
3775
  runtimeSettings: this.runtimeSettings
3115
3776
  });
3116
- const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
3777
+ const session = this.cliScripts.parseSession(this.scriptState, { ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
3117
3778
  this.parseErrorMessage = null;
3118
3779
  return session && typeof session === "object" ? session : null;
3119
3780
  } catch (e) {
@@ -3127,7 +3788,7 @@ ${lastSnapshot}`;
3127
3788
  if (!this.cliScripts?.detectStatus) return null;
3128
3789
  try {
3129
3790
  const screenText = this.terminalScreen.getText();
3130
- const status = this.cliScripts.detectStatus({
3791
+ const status = this.cliScripts.detectStatus(this.scriptState, {
3131
3792
  tail: text.slice(-500),
3132
3793
  screenText,
3133
3794
  rawBuffer: this.accumulatedRawBuffer,
@@ -3146,7 +3807,7 @@ ${lastSnapshot}`;
3146
3807
  try {
3147
3808
  const screenText = this.terminalScreen.getText();
3148
3809
  const buffer = screenText || this.accumulatedBuffer;
3149
- return this.cliScripts.parseApproval({
3810
+ return this.cliScripts.parseApproval(this.scriptState, {
3150
3811
  buffer,
3151
3812
  screenText,
3152
3813
  rawBuffer: this.accumulatedRawBuffer,
@@ -3254,7 +3915,7 @@ ${lastSnapshot}`;
3254
3915
  scope: this.currentTurnScope,
3255
3916
  runtimeSettings: this.runtimeSettings
3256
3917
  });
3257
- return await Promise.resolve(fn({
3918
+ return await Promise.resolve(fn(this.scriptState, {
3258
3919
  ...input,
3259
3920
  args: args && typeof args === "object" ? { ...args } : {}
3260
3921
  }));
@@ -4047,6 +4708,7 @@ __export(index_exports, {
4047
4708
  TurnSnapshotTracker: () => TurnSnapshotTracker,
4048
4709
  VersionArchive: () => VersionArchive,
4049
4710
  addNode: () => addNode,
4711
+ appendLedgerEntry: () => appendLedgerEntry,
4050
4712
  appendRecentActivity: () => appendRecentActivity,
4051
4713
  buildAssistantChatMessage: () => buildAssistantChatMessage,
4052
4714
  buildChatMessage: () => buildChatMessage,
@@ -4064,6 +4726,7 @@ __export(index_exports, {
4064
4726
  buildThoughtChatMessage: () => buildThoughtChatMessage,
4065
4727
  buildToolChatMessage: () => buildToolChatMessage,
4066
4728
  buildUserChatMessage: () => buildUserChatMessage,
4729
+ claimNextTask: () => claimNextTask,
4067
4730
  classifyChatMessageVisibility: () => classifyChatMessageVisibility,
4068
4731
  classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush,
4069
4732
  clearDebugTrace: () => clearDebugTrace,
@@ -4082,6 +4745,7 @@ __export(index_exports, {
4082
4745
  detectAllVersions: () => detectAllVersions,
4083
4746
  detectCLIs: () => detectCLIs,
4084
4747
  detectIDEs: () => detectIDEs,
4748
+ enqueueTask: () => enqueueTask,
4085
4749
  ensureSessionHostReady: () => ensureSessionHostReady,
4086
4750
  execNpmCommandSync: () => execNpmCommandSync,
4087
4751
  filterActivityChatMessages: () => filterActivityChatMessages,
@@ -4100,10 +4764,13 @@ __export(index_exports, {
4100
4764
  getGitFileDiff: () => getGitFileDiff,
4101
4765
  getGitRepoStatus: () => getGitRepoStatus,
4102
4766
  getHostMemorySnapshot: () => getHostMemorySnapshot,
4767
+ getLedgerDir: () => getLedgerDir,
4768
+ getLedgerSummary: () => getLedgerSummary,
4103
4769
  getLogLevel: () => getLogLevel,
4104
4770
  getMesh: () => getMesh,
4105
4771
  getMeshByRepo: () => getMeshByRepo,
4106
4772
  getNpmExecOptions: () => getNpmExecOptions,
4773
+ getQueue: () => getQueue,
4107
4774
  getRecentActivity: () => getRecentActivity,
4108
4775
  getRecentCommands: () => getRecentCommands,
4109
4776
  getRecentDebugTrace: () => getRecentDebugTrace,
@@ -4111,6 +4778,7 @@ __export(index_exports, {
4111
4778
  getSavedProviderSessions: () => getSavedProviderSessions,
4112
4779
  getSessionHostRecoveryLabel: () => getSessionHostRecoveryLabel,
4113
4780
  getSessionHostSurfaceKind: () => getSessionHostSurfaceKind,
4781
+ getSessionRecoveryContext: () => getSessionRecoveryContext,
4114
4782
  getWorkspaceState: () => getWorkspaceState,
4115
4783
  handleGitCommand: () => handleGitCommand,
4116
4784
  hasCdpManager: () => hasCdpManager,
@@ -4164,6 +4832,7 @@ __export(index_exports, {
4164
4832
  prepareSessionModalUpdate: () => prepareSessionModalUpdate,
4165
4833
  probeCdpPort: () => probeCdpPort,
4166
4834
  readChatHistory: () => readChatHistory,
4835
+ readLedgerEntries: () => readLedgerEntries,
4167
4836
  recordDebugTrace: () => recordDebugTrace,
4168
4837
  registerExtensionProviders: () => registerExtensionProviders,
4169
4838
  removeNode: () => removeNode,
@@ -4192,9 +4861,12 @@ __export(index_exports, {
4192
4861
  startDaemonDevSupport: () => startDaemonDevSupport,
4193
4862
  summarizeGitStatus: () => summarizeGitStatus,
4194
4863
  syncMeshes: () => syncMeshes,
4864
+ triggerMeshQueue: () => triggerMeshQueue,
4195
4865
  updateConfig: () => updateConfig,
4196
4866
  updateMesh: () => updateMesh,
4197
4867
  updateNode: () => updateNode,
4868
+ updateSessionTaskStatus: () => updateSessionTaskStatus,
4869
+ updateTaskStatus: () => updateTaskStatus,
4198
4870
  upsertSavedProviderSession: () => upsertSavedProviderSession
4199
4871
  });
4200
4872
  module.exports = __toCommonJS(index_exports);
@@ -6061,12 +6733,35 @@ async function syncMeshes(transport) {
6061
6733
  }
6062
6734
  }
6063
6735
  }
6736
+ if (transport.syncMeshLedger) {
6737
+ for (const local of localMeshes) {
6738
+ try {
6739
+ await syncMeshLedger(local.id, transport);
6740
+ } catch (e) {
6741
+ result.errors.push(`Ledger sync failed for "${local.name}": ${e.message}`);
6742
+ }
6743
+ }
6744
+ }
6064
6745
  return result;
6065
6746
  }
6747
+ async function syncMeshLedger(meshId, transport) {
6748
+ if (!transport.syncMeshLedger) return;
6749
+ const { readLedgerEntries: readLedgerEntries2, appendRemoteLedgerEntries: appendRemoteLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
6750
+ const localEntries = readLedgerEntries2(meshId);
6751
+ const res = await transport.syncMeshLedger(meshId, { newEntries: localEntries });
6752
+ if (res.missingEntries && res.missingEntries.length > 0) {
6753
+ appendRemoteLedgerEntries2(meshId, res.missingEntries);
6754
+ }
6755
+ }
6756
+
6757
+ // src/index.ts
6758
+ init_mesh_ledger();
6759
+ init_mesh_work_queue();
6760
+ init_mesh_events();
6066
6761
 
6067
6762
  // src/config/state-store.ts
6068
- var import_fs3 = require("fs");
6069
- var import_path3 = require("path");
6763
+ var import_fs5 = require("fs");
6764
+ var import_path5 = require("path");
6070
6765
  init_config();
6071
6766
  var DEFAULT_STATE = {
6072
6767
  recentActivity: [],
@@ -6080,7 +6775,7 @@ function isPlainObject2(value) {
6080
6775
  return !!value && typeof value === "object" && !Array.isArray(value);
6081
6776
  }
6082
6777
  function getStatePath() {
6083
- return (0, import_path3.join)(getConfigDir(), "state.json");
6778
+ return (0, import_path5.join)(getConfigDir(), "state.json");
6084
6779
  }
6085
6780
  function normalizeState(raw) {
6086
6781
  const parsed = isPlainObject2(raw) ? raw : {};
@@ -6116,11 +6811,11 @@ function normalizeState(raw) {
6116
6811
  }
6117
6812
  function loadState() {
6118
6813
  const statePath = getStatePath();
6119
- if (!(0, import_fs3.existsSync)(statePath)) {
6814
+ if (!(0, import_fs5.existsSync)(statePath)) {
6120
6815
  return { ...DEFAULT_STATE };
6121
6816
  }
6122
6817
  try {
6123
- const raw = (0, import_fs3.readFileSync)(statePath, "utf-8");
6818
+ const raw = (0, import_fs5.readFileSync)(statePath, "utf-8");
6124
6819
  return normalizeState(JSON.parse(raw));
6125
6820
  } catch {
6126
6821
  return { ...DEFAULT_STATE };
@@ -6129,7 +6824,7 @@ function loadState() {
6129
6824
  function saveState(state) {
6130
6825
  const statePath = getStatePath();
6131
6826
  const normalized = normalizeState(state);
6132
- (0, import_fs3.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
6827
+ (0, import_fs5.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
6133
6828
  }
6134
6829
  function resetState() {
6135
6830
  saveState({ ...DEFAULT_STATE });
@@ -6137,9 +6832,9 @@ function resetState() {
6137
6832
 
6138
6833
  // src/detection/ide-detector.ts
6139
6834
  var import_child_process = require("child_process");
6140
- var import_fs4 = require("fs");
6835
+ var import_fs6 = require("fs");
6141
6836
  var import_os2 = require("os");
6142
- var path8 = __toESM(require("path"));
6837
+ var path9 = __toESM(require("path"));
6143
6838
  var BUILTIN_IDE_DEFINITIONS = [];
6144
6839
  var registeredIDEs = /* @__PURE__ */ new Map();
6145
6840
  function registerIDEDefinition(def) {
@@ -6158,10 +6853,10 @@ function getMergedDefinitions() {
6158
6853
  function findCliCommand(command) {
6159
6854
  const trimmed = String(command || "").trim();
6160
6855
  if (!trimmed) return null;
6161
- if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
6162
- const candidate = trimmed.startsWith("~") ? path8.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
6163
- const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
6164
- return (0, import_fs4.existsSync)(resolved) ? resolved : null;
6856
+ if (path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
6857
+ const candidate = trimmed.startsWith("~") ? path9.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
6858
+ const resolved = path9.isAbsolute(candidate) ? candidate : path9.resolve(candidate);
6859
+ return (0, import_fs6.existsSync)(resolved) ? resolved : null;
6165
6860
  }
6166
6861
  try {
6167
6862
  const result = (0, import_child_process.execSync)(
@@ -6188,13 +6883,13 @@ function getIdeVersion(cliCommand) {
6188
6883
  function checkPathExists(paths) {
6189
6884
  const home = (0, import_os2.homedir)();
6190
6885
  for (const p of paths) {
6191
- const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
6886
+ const normalized = p.startsWith("~") ? path9.join(home, p.slice(1)) : p;
6192
6887
  if (normalized.includes("*")) {
6193
6888
  const username = home.split(/[\\/]/).pop() || "";
6194
6889
  const resolved = normalized.replace("*", username);
6195
- if ((0, import_fs4.existsSync)(resolved)) return resolved;
6890
+ if ((0, import_fs6.existsSync)(resolved)) return resolved;
6196
6891
  } else {
6197
- if ((0, import_fs4.existsSync)(normalized)) return normalized;
6892
+ if ((0, import_fs6.existsSync)(normalized)) return normalized;
6198
6893
  }
6199
6894
  }
6200
6895
  return null;
@@ -6208,7 +6903,7 @@ async function detectIDEs(providerLoader) {
6208
6903
  let resolvedCli = cliPath;
6209
6904
  if (!resolvedCli && appPath && os22 === "darwin") {
6210
6905
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
6211
- if ((0, import_fs4.existsSync)(bundledCli)) resolvedCli = bundledCli;
6906
+ if ((0, import_fs6.existsSync)(bundledCli)) resolvedCli = bundledCli;
6212
6907
  }
6213
6908
  if (!resolvedCli && appPath && os22 === "win32") {
6214
6909
  const { dirname: dirname9 } = await import("path");
@@ -6221,7 +6916,7 @@ async function detectIDEs(providerLoader) {
6221
6916
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
6222
6917
  ];
6223
6918
  for (const c of candidates) {
6224
- if ((0, import_fs4.existsSync)(c)) {
6919
+ if ((0, import_fs6.existsSync)(c)) {
6225
6920
  resolvedCli = c;
6226
6921
  break;
6227
6922
  }
@@ -6245,9 +6940,9 @@ async function detectIDEs(providerLoader) {
6245
6940
 
6246
6941
  // src/detection/cli-detector.ts
6247
6942
  var import_child_process2 = require("child_process");
6248
- var os2 = __toESM(require("os"));
6249
- var path9 = __toESM(require("path"));
6250
- var import_fs5 = require("fs");
6943
+ var os3 = __toESM(require("os"));
6944
+ var path10 = __toESM(require("path"));
6945
+ var import_fs7 = require("fs");
6251
6946
  function parseVersion(raw) {
6252
6947
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
6253
6948
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
@@ -6259,19 +6954,19 @@ function shellQuote(value) {
6259
6954
  function expandHome(value) {
6260
6955
  const trimmed = value.trim();
6261
6956
  if (!trimmed.startsWith("~")) return trimmed;
6262
- return path9.join(os2.homedir(), trimmed.slice(1));
6957
+ return path10.join(os3.homedir(), trimmed.slice(1));
6263
6958
  }
6264
6959
  function isExplicitCommandPath(command) {
6265
6960
  const trimmed = command.trim();
6266
- return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
6961
+ return path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
6267
6962
  }
6268
6963
  function resolveCommandPath(command) {
6269
6964
  const trimmed = command.trim();
6270
6965
  if (!trimmed) return null;
6271
6966
  if (isExplicitCommandPath(trimmed)) {
6272
6967
  const expanded = expandHome(trimmed);
6273
- const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
6274
- return (0, import_fs5.existsSync)(candidate) ? candidate : null;
6968
+ const candidate = path10.isAbsolute(expanded) ? expanded : path10.resolve(expanded);
6969
+ return (0, import_fs7.existsSync)(candidate) ? candidate : null;
6275
6970
  }
6276
6971
  return null;
6277
6972
  }
@@ -6292,7 +6987,7 @@ function execAsync(cmd, timeoutMs = 5e3) {
6292
6987
  });
6293
6988
  }
6294
6989
  async function detectCLIs(providerLoader, options) {
6295
- const platform10 = os2.platform();
6990
+ const platform10 = os3.platform();
6296
6991
  const whichCmd = platform10 === "win32" ? "where" : "which";
6297
6992
  const includeVersion = options?.includeVersion !== false;
6298
6993
  const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
@@ -6336,7 +7031,7 @@ async function detectCLI(cliId, providerLoader, options) {
6336
7031
  const cliList = providerLoader.getCliDetectionList();
6337
7032
  const target = cliList.find((c) => c.id === resolvedId);
6338
7033
  if (target) {
6339
- const platform10 = os2.platform();
7034
+ const platform10 = os3.platform();
6340
7035
  const whichCmd = platform10 === "win32" ? "where" : "which";
6341
7036
  try {
6342
7037
  const explicitPath = resolveCommandPath(target.command);
@@ -6373,10 +7068,10 @@ async function detectCLI(cliId, providerLoader, options) {
6373
7068
  }
6374
7069
 
6375
7070
  // src/system/host-memory.ts
6376
- var os3 = __toESM(require("os"));
7071
+ var os4 = __toESM(require("os"));
6377
7072
  var import_child_process3 = require("child_process");
6378
7073
  function parseDarwinAvailableBytes(totalMem) {
6379
- if (os3.platform() !== "darwin") return null;
7074
+ if (os4.platform() !== "darwin") return null;
6380
7075
  try {
6381
7076
  const out = (0, import_child_process3.execSync)("vm_stat", {
6382
7077
  encoding: "utf-8",
@@ -6407,8 +7102,8 @@ function parseDarwinAvailableBytes(totalMem) {
6407
7102
  }
6408
7103
  }
6409
7104
  function getHostMemorySnapshot() {
6410
- const totalMem = os3.totalmem();
6411
- const freeMem = os3.freemem();
7105
+ const totalMem = os4.totalmem();
7106
+ const freeMem = os4.freemem();
6412
7107
  const darwinAvail = parseDarwinAvailableBytes(totalMem);
6413
7108
  const availableMem = darwinAvail != null ? darwinAvail : freeMem;
6414
7109
  return { totalMem, freeMem, availableMem };
@@ -11778,6 +12473,9 @@ function normalizeActiveChatData(activeChat, options = FULL_STATUS_ACTIVE_CHAT_O
11778
12473
  return normalized;
11779
12474
  }
11780
12475
 
12476
+ // src/status/builders.ts
12477
+ init_mesh_work_queue();
12478
+
11781
12479
  // src/providers/provider-input-support.ts
11782
12480
  var VALID_INPUT_MEDIA_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "video", "resource"]);
11783
12481
  var VALID_INPUT_STRATEGIES = /* @__PURE__ */ new Set(["native", "native_acp", "resource_link", "text_fallback", "paste", "upload"]);
@@ -12003,6 +12701,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
12003
12701
  const workspace = state.workspace || null;
12004
12702
  const git = getGitSummaryForWorkspace(workspace, options);
12005
12703
  const title = activeChat?.title || state.name;
12704
+ const meshCoordinatorFor = state.settings?.meshCoordinatorFor;
12705
+ const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
12006
12706
  return {
12007
12707
  id: state.instanceId || state.type,
12008
12708
  parentId: null,
@@ -12025,7 +12725,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
12025
12725
  errorMessage: state.errorMessage,
12026
12726
  errorReason: state.errorReason,
12027
12727
  lastUpdated: state.lastUpdated,
12028
- settings: state.settings
12728
+ settings: state.settings,
12729
+ ...meshQueueStats && { meshQueueStats }
12029
12730
  };
12030
12731
  }
12031
12732
  function buildExtensionAgentSession(parent, ext, options) {
@@ -12037,6 +12738,8 @@ function buildExtensionAgentSession(parent, ext, options) {
12037
12738
  const includeSessionControls = shouldIncludeSessionControls(profile);
12038
12739
  const workspace = parent.workspace || null;
12039
12740
  const git = getGitSummaryForWorkspace(workspace, options);
12741
+ const meshCoordinatorFor = ext.settings?.meshCoordinatorFor;
12742
+ const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
12040
12743
  return {
12041
12744
  id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
12042
12745
  parentId: parent.instanceId || parent.type,
@@ -12059,7 +12762,8 @@ function buildExtensionAgentSession(parent, ext, options) {
12059
12762
  errorMessage: ext.errorMessage,
12060
12763
  errorReason: ext.errorReason,
12061
12764
  lastUpdated: ext.lastUpdated,
12062
- settings: ext.settings
12765
+ settings: ext.settings,
12766
+ ...meshQueueStats && { meshQueueStats }
12063
12767
  };
12064
12768
  }
12065
12769
  function shouldIncludeExtensionSession(ext) {
@@ -12087,6 +12791,8 @@ function buildCliSession(state, options) {
12087
12791
  const includeSessionControls = shouldIncludeSessionControls(profile);
12088
12792
  const workspace = state.workspace || null;
12089
12793
  const git = getGitSummaryForWorkspace(workspace, options);
12794
+ const meshCoordinatorFor = state.settings?.meshCoordinatorFor;
12795
+ const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
12090
12796
  return {
12091
12797
  id: state.instanceId,
12092
12798
  parentId: null,
@@ -12125,7 +12831,8 @@ function buildCliSession(state, options) {
12125
12831
  errorMessage: state.errorMessage,
12126
12832
  errorReason: state.errorReason,
12127
12833
  lastUpdated: state.lastUpdated,
12128
- settings: state.settings
12834
+ settings: state.settings,
12835
+ ...meshQueueStats && { meshQueueStats }
12129
12836
  };
12130
12837
  }
12131
12838
  function buildAcpSession(state, options) {
@@ -12137,6 +12844,8 @@ function buildAcpSession(state, options) {
12137
12844
  const includeSessionControls = shouldIncludeSessionControls(profile);
12138
12845
  const workspace = state.workspace || null;
12139
12846
  const git = getGitSummaryForWorkspace(workspace, options);
12847
+ const meshCoordinatorFor = state.settings?.meshCoordinatorFor;
12848
+ const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
12140
12849
  return {
12141
12850
  id: state.instanceId,
12142
12851
  parentId: null,
@@ -12158,7 +12867,8 @@ function buildAcpSession(state, options) {
12158
12867
  errorMessage: state.errorMessage,
12159
12868
  errorReason: state.errorReason,
12160
12869
  lastUpdated: state.lastUpdated,
12161
- settings: state.settings
12870
+ settings: state.settings,
12871
+ ...meshQueueStats && { meshQueueStats }
12162
12872
  };
12163
12873
  }
12164
12874
  function buildSessionEntries(allStates, cdpManagers, options = {}) {
@@ -14499,11 +15209,13 @@ async function handleOpenPanel(h, args) {
14499
15209
  async function handlePtyInput(h, args) {
14500
15210
  const { cliType, data, targetSessionId } = args || {};
14501
15211
  if (!data) return { success: false, error: "data required" };
15212
+ const cleanData = typeof data === "string" ? data.replace(/\x1b\[\?[0-9;]*c/g, "") : data;
15213
+ if (!cleanData) return { success: true };
14502
15214
  const adapter = h.getCliAdapter(targetSessionId || cliType);
14503
15215
  if (!adapter || typeof adapter.writeRaw !== "function") {
14504
15216
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
14505
15217
  }
14506
- await adapter.writeRaw(data);
15218
+ await adapter.writeRaw(cleanData);
14507
15219
  return { success: true };
14508
15220
  }
14509
15221
  function handlePtyResize(_h, args) {
@@ -15459,7 +16171,7 @@ var DaemonCommandHandler = class {
15459
16171
  var os13 = __toESM(require("os"));
15460
16172
  var path18 = __toESM(require("path"));
15461
16173
  var crypto4 = __toESM(require("crypto"));
15462
- var import_fs6 = require("fs");
16174
+ var import_fs8 = require("fs");
15463
16175
  var import_child_process6 = require("child_process");
15464
16176
  var import_chalk = __toESM(require("chalk"));
15465
16177
  init_provider_cli_adapter();
@@ -17837,7 +18549,7 @@ function commandExists(command) {
17837
18549
  const trimmed = command.trim();
17838
18550
  if (!trimmed) return false;
17839
18551
  if (isExplicitCommand(trimmed)) {
17840
- return (0, import_fs6.existsSync)(expandExecutable(trimmed));
18552
+ return (0, import_fs8.existsSync)(expandExecutable(trimmed));
17841
18553
  }
17842
18554
  try {
17843
18555
  (0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -17866,10 +18578,10 @@ function hasCliArg(args, flag) {
17866
18578
  }
17867
18579
  function ensureEmptyDelegatedMcpConfig(workspace) {
17868
18580
  const baseDir = path18.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
17869
- (0, import_fs6.mkdirSync)(baseDir, { recursive: true });
18581
+ (0, import_fs8.mkdirSync)(baseDir, { recursive: true });
17870
18582
  const workspaceHash = crypto4.createHash("sha256").update(path18.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
17871
18583
  const filePath = path18.join(baseDir, `${workspaceHash}.json`);
17872
- (0, import_fs6.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
18584
+ (0, import_fs8.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
17873
18585
  return filePath;
17874
18586
  }
17875
18587
  function buildCoordinatorDelegatedCliLaunchOptions(input) {
@@ -21213,6 +21925,22 @@ function resolveMeshCoordinatorSetup(options) {
21213
21925
  if (!instructions || !template?.trim()) {
21214
21926
  return { kind: "unsupported", reason: "Provider manual MCP setup is missing instructions or template" };
21215
21927
  }
21928
+ const renderedTemplate = renderMeshCoordinatorTemplate(template, {
21929
+ meshId,
21930
+ workspace,
21931
+ serverName,
21932
+ adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND
21933
+ });
21934
+ const isCliCommand = !renderedTemplate.trim().includes("\n") && !renderedTemplate.trim().startsWith("{");
21935
+ if (isCliCommand) {
21936
+ return {
21937
+ kind: "cli_command",
21938
+ serverName,
21939
+ command: renderedTemplate.trim(),
21940
+ requiresRestart: mcpConfig.requiresRestart === true,
21941
+ instructions
21942
+ };
21943
+ }
21216
21944
  return {
21217
21945
  kind: "manual",
21218
21946
  serverName,
@@ -21220,12 +21948,7 @@ function resolveMeshCoordinatorSetup(options) {
21220
21948
  configPathCommand: mcpConfig.configPathCommand,
21221
21949
  requiresRestart: mcpConfig.requiresRestart === true,
21222
21950
  instructions,
21223
- template: renderMeshCoordinatorTemplate(template, {
21224
- meshId,
21225
- workspace,
21226
- serverName,
21227
- adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND
21228
- })
21951
+ template: renderedTemplate
21229
21952
  };
21230
21953
  }
21231
21954
  return {
@@ -21363,134 +22086,8 @@ function normalizeExistingPath(filePath) {
21363
22086
  }
21364
22087
  }
21365
22088
 
21366
- // src/mesh/mesh-events.ts
21367
- init_mesh_config();
21368
- init_logger();
21369
- var MAX_PENDING_EVENTS = 50;
21370
- var pendingMeshCoordinatorEvents = [];
21371
- function drainPendingMeshCoordinatorEvents() {
21372
- return pendingMeshCoordinatorEvents.splice(0);
21373
- }
21374
- function readNonEmptyString(value) {
21375
- return typeof value === "string" && value.trim() ? value.trim() : "";
21376
- }
21377
- var MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
21378
- "agent:generating_completed",
21379
- "agent:waiting_approval",
21380
- "agent:stopped",
21381
- "monitor:long_generating"
21382
- ]);
21383
- function isMeshCoordinatorEvent(eventName) {
21384
- return typeof eventName === "string" && MESH_COORDINATOR_EVENTS.has(eventName);
21385
- }
21386
- function formatCompletionMetadata(event) {
21387
- const parts = [
21388
- readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
21389
- readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
21390
- readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
21391
- ].filter(Boolean);
21392
- return parts.length > 0 ? ` (${parts.join("; ")})` : "";
21393
- }
21394
- function buildMeshSystemMessage(args) {
21395
- const metadata = formatCompletionMetadata(args.metadataEvent);
21396
- if (args.event === "agent:generating_completed") {
21397
- 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.`;
21398
- }
21399
- if (args.event === "agent:waiting_approval") {
21400
- return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
21401
- }
21402
- if (args.event === "agent:stopped") {
21403
- return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
21404
- }
21405
- if (args.event === "monitor:long_generating") {
21406
- 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.`;
21407
- }
21408
- return "";
21409
- }
21410
- function injectMeshSystemMessage(components, args) {
21411
- const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
21412
- const instState = inst.getState();
21413
- if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
21414
- if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
21415
- return true;
21416
- });
21417
- if (coordinatorInstances.length === 0) {
21418
- if (pendingMeshCoordinatorEvents.length < MAX_PENDING_EVENTS) {
21419
- pendingMeshCoordinatorEvents.push({
21420
- event: args.event,
21421
- meshId: args.meshId,
21422
- nodeLabel: args.nodeLabel,
21423
- metadataEvent: args.metadataEvent,
21424
- queuedAt: Date.now()
21425
- });
21426
- LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
21427
- }
21428
- return { success: true, forwarded: 0 };
21429
- }
21430
- const messageText = buildMeshSystemMessage({
21431
- event: args.event,
21432
- nodeLabel: args.nodeLabel,
21433
- metadataEvent: args.metadataEvent
21434
- });
21435
- if (!messageText) return { success: false, error: "unsupported mesh event" };
21436
- for (const coord of coordinatorInstances) {
21437
- const coordState = coord.getState();
21438
- LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
21439
- coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
21440
- }
21441
- return { success: true, forwarded: coordinatorInstances.length };
21442
- }
21443
- function handleMeshForwardEvent(components, payload) {
21444
- const eventName = readNonEmptyString(payload.event);
21445
- if (!isMeshCoordinatorEvent(eventName)) {
21446
- return { success: false, error: "unsupported mesh event" };
21447
- }
21448
- const meshId = readNonEmptyString(payload.meshId);
21449
- if (!meshId) return { success: false, error: "meshId required" };
21450
- const nodeId = readNonEmptyString(payload.nodeId);
21451
- const workspace = readNonEmptyString(payload.workspace);
21452
- const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
21453
- return injectMeshSystemMessage(components, {
21454
- meshId,
21455
- nodeLabel,
21456
- event: eventName,
21457
- metadataEvent: {
21458
- targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
21459
- providerType: readNonEmptyString(payload.providerType),
21460
- providerSessionId: readNonEmptyString(payload.providerSessionId)
21461
- }
21462
- });
21463
- }
21464
- function setupMeshEventForwarding(components) {
21465
- components.instanceManager.onEvent((event) => {
21466
- if (!isMeshCoordinatorEvent(event.event)) return;
21467
- const instanceId = readNonEmptyString(event.instanceId);
21468
- if (!instanceId) return;
21469
- const sourceInstance = components.instanceManager.getInstance(instanceId);
21470
- if (!sourceInstance || sourceInstance.category !== "cli") return;
21471
- const state = sourceInstance.getState();
21472
- const workspace = readNonEmptyString(state.workspace);
21473
- if (!workspace) return;
21474
- const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
21475
- if (readNonEmptyString(settings.meshCoordinatorFor)) return;
21476
- const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
21477
- const isMeshDelegate = Boolean(meshIdFromRuntime || settings.launchedByCoordinator);
21478
- if (!isMeshDelegate) return;
21479
- const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
21480
- const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
21481
- if (!meshId) return;
21482
- const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
21483
- const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
21484
- const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
21485
- injectMeshSystemMessage(components, {
21486
- meshId,
21487
- sourceInstanceId: instanceId,
21488
- nodeLabel,
21489
- event: event.event,
21490
- metadataEvent: event
21491
- });
21492
- });
21493
- }
22089
+ // src/commands/router.ts
22090
+ init_mesh_events();
21494
22091
 
21495
22092
  // src/status/snapshot.ts
21496
22093
  var os18 = __toESM(require("os"));
@@ -22145,7 +22742,7 @@ async function maybeRunDaemonUpgradeHelperFromEnv() {
22145
22742
 
22146
22743
  // src/commands/router.ts
22147
22744
  var import_os3 = require("os");
22148
- var import_path4 = require("path");
22745
+ var import_path6 = require("path");
22149
22746
  var fs10 = __toESM(require("fs"));
22150
22747
  var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
22151
22748
  var CHANNEL_SERVER_URL = {
@@ -22214,22 +22811,22 @@ function serializeMeshCoordinatorMcpConfig(config, format) {
22214
22811
  }
22215
22812
  function resolveHermesUserHome() {
22216
22813
  const explicitHome = process.env.HERMES_HOME?.trim();
22217
- return explicitHome || (0, import_path4.join)((0, import_os3.homedir)(), ".hermes");
22814
+ return explicitHome || (0, import_path6.join)((0, import_os3.homedir)(), ".hermes");
22218
22815
  }
22219
22816
  function loadHermesCoordinatorBaseConfig(targetConfigPath) {
22220
22817
  const sourceHome = resolveHermesUserHome();
22221
- const sourceConfigPath = (0, import_path4.join)(sourceHome, "config.yaml");
22818
+ const sourceConfigPath = (0, import_path6.join)(sourceHome, "config.yaml");
22222
22819
  if (!fs10.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
22223
- if ((0, import_path4.resolve)(sourceConfigPath) === (0, import_path4.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
22820
+ if ((0, import_path6.resolve)(sourceConfigPath) === (0, import_path6.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
22224
22821
  const parsed = parseMeshCoordinatorMcpConfig(fs10.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
22225
22822
  const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
22226
22823
  return { config: baseConfig, sourceHome, sourceConfigPath };
22227
22824
  }
22228
22825
  function copyHermesCoordinatorCredentialFiles(sourceHome, targetHome) {
22229
- if ((0, import_path4.resolve)(sourceHome) === (0, import_path4.resolve)(targetHome)) return;
22826
+ if ((0, import_path6.resolve)(sourceHome) === (0, import_path6.resolve)(targetHome)) return;
22230
22827
  for (const fileName of [".env", "auth.json"]) {
22231
- const sourcePath = (0, import_path4.join)(sourceHome, fileName);
22232
- const targetPath = (0, import_path4.join)(targetHome, fileName);
22828
+ const sourcePath = (0, import_path6.join)(sourceHome, fileName);
22829
+ const targetPath = (0, import_path6.join)(targetHome, fileName);
22233
22830
  if (!fs10.existsSync(sourcePath)) continue;
22234
22831
  try {
22235
22832
  fs10.copyFileSync(sourcePath, targetPath);
@@ -23190,6 +23787,21 @@ var DaemonCommandRouter = class {
23190
23787
  return { success: false, error: e.message };
23191
23788
  }
23192
23789
  }
23790
+ case "get_mesh_ledger": {
23791
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
23792
+ if (!meshId) return { success: false, error: "meshId required" };
23793
+ try {
23794
+ const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
23795
+ const tail = typeof args?.tail === "number" ? args.tail : 20;
23796
+ const since = typeof args?.since === "string" ? args.since : void 0;
23797
+ const kind = Array.isArray(args?.kind) ? args.kind.filter((k) => typeof k === "string") : void 0;
23798
+ const entries = readLedgerEntries2(meshId, { tail, since, kind });
23799
+ const summary = getLedgerSummary2(meshId);
23800
+ return { success: true, entries, summary };
23801
+ } catch (e) {
23802
+ return { success: false, error: e.message };
23803
+ }
23804
+ }
23193
23805
  case "add_mesh_node": {
23194
23806
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
23195
23807
  const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
@@ -23258,6 +23870,54 @@ var DaemonCommandRouter = class {
23258
23870
  return { success: false, error: e.message };
23259
23871
  }
23260
23872
  }
23873
+ case "refine_mesh_node": {
23874
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
23875
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
23876
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
23877
+ try {
23878
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
23879
+ const mesh = meshRecord?.mesh;
23880
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
23881
+ if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
23882
+ if (!node.isLocalWorktree || !node.workspace) {
23883
+ return { success: false, error: `Refinery requires a local worktree node` };
23884
+ }
23885
+ const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
23886
+ const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
23887
+ if (!repoRoot) return { success: false, error: "Source node repoRoot not found" };
23888
+ const { execFile: execFile3 } = await import("child_process");
23889
+ const { promisify: promisify3 } = await import("util");
23890
+ const execFileAsync3 = promisify3(execFile3);
23891
+ const { stdout: branchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: node.workspace, encoding: "utf8" });
23892
+ const branch = branchStdout.trim();
23893
+ if (!branch) return { success: false, error: "Could not determine branch of the worktree node" };
23894
+ const { stdout: baseBranchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
23895
+ const baseBranch = baseBranchStdout.trim();
23896
+ try {
23897
+ await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
23898
+ } catch (e) {
23899
+ return { success: false, error: `Merge failed (conflicts?): ${e.message}` };
23900
+ }
23901
+ const removeResult = await this.execute("remove_mesh_node", {
23902
+ meshId,
23903
+ nodeId,
23904
+ sessionCleanupMode: "kill",
23905
+ inlineMesh: args?.inlineMesh
23906
+ });
23907
+ try {
23908
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
23909
+ appendLedgerEntry2(meshId, {
23910
+ kind: "node_removed",
23911
+ nodeId,
23912
+ payload: { refined: true, mergedBranch: branch, into: baseBranch }
23913
+ });
23914
+ } catch {
23915
+ }
23916
+ return { success: true, merged: true, branch, into: baseBranch, removeResult };
23917
+ } catch (e) {
23918
+ return { success: false, error: e.message };
23919
+ }
23920
+ }
23261
23921
  case "remove_mesh_node": {
23262
23922
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
23263
23923
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
@@ -23293,6 +23953,17 @@ var DaemonCommandRouter = class {
23293
23953
  const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
23294
23954
  removed = removeNode3(meshId, nodeId);
23295
23955
  }
23956
+ if (removed) {
23957
+ try {
23958
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
23959
+ appendLedgerEntry2(meshId, {
23960
+ kind: "node_removed",
23961
+ nodeId,
23962
+ payload: { worktree: !!node?.isLocalWorktree, sessionCleanupMode }
23963
+ });
23964
+ } catch {
23965
+ }
23966
+ }
23296
23967
  return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
23297
23968
  } catch (e) {
23298
23969
  return { success: false, error: e.message };
@@ -23322,9 +23993,9 @@ var DaemonCommandRouter = class {
23322
23993
  });
23323
23994
  let node;
23324
23995
  if (meshRecord.inline) {
23325
- const { randomUUID: randomUUID8 } = await import("crypto");
23996
+ const { randomUUID: randomUUID10 } = await import("crypto");
23326
23997
  node = {
23327
- id: `node_${randomUUID8().replace(/-/g, "")}`,
23998
+ id: `node_${randomUUID10().replace(/-/g, "")}`,
23328
23999
  workspace: result.worktreePath,
23329
24000
  repoRoot: result.worktreePath,
23330
24001
  daemonId: sourceNode.daemonId,
@@ -23349,6 +24020,15 @@ var DaemonCommandRouter = class {
23349
24020
  });
23350
24021
  if (!node) return { success: false, error: "Failed to register worktree node" };
23351
24022
  }
24023
+ try {
24024
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
24025
+ appendLedgerEntry2(meshId, {
24026
+ kind: "node_cloned",
24027
+ nodeId: node.id,
24028
+ payload: { sourceNodeId, branch: result.branch, worktreePath: result.worktreePath }
24029
+ });
24030
+ } catch {
24031
+ }
23352
24032
  return {
23353
24033
  success: true,
23354
24034
  node,
@@ -23359,6 +24039,19 @@ var DaemonCommandRouter = class {
23359
24039
  return { success: false, error: e.message };
23360
24040
  }
23361
24041
  }
24042
+ case "trigger_mesh_queue": {
24043
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
24044
+ if (!meshId) return { success: false, error: "meshId required" };
24045
+ try {
24046
+ const { triggerMeshQueue: triggerMeshQueue2 } = await Promise.resolve().then(() => (init_mesh_events(), mesh_events_exports));
24047
+ if (meshId) {
24048
+ triggerMeshQueue2(this.deps, meshId);
24049
+ }
24050
+ return { success: true };
24051
+ } catch (e) {
24052
+ return { success: false, error: e.message };
24053
+ }
24054
+ }
23362
24055
  // ─── Mesh Coordinator Launch ───
23363
24056
  case "launch_mesh_coordinator": {
23364
24057
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
@@ -23437,6 +24130,93 @@ var DaemonCommandRouter = class {
23437
24130
  meshCoordinatorSetup: coordinatorSetup
23438
24131
  };
23439
24132
  }
24133
+ if (coordinatorSetup.kind === "cli_command") {
24134
+ let cliCmdSystemPrompt = "";
24135
+ try {
24136
+ cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
24137
+ } catch (error) {
24138
+ const message = error?.message || String(error);
24139
+ LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
24140
+ return {
24141
+ success: false,
24142
+ code: "mesh_coordinator_prompt_failed",
24143
+ error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
24144
+ meshId,
24145
+ cliType,
24146
+ workspace
24147
+ };
24148
+ }
24149
+ try {
24150
+ const { execFileSync: execCmdSync } = await import("child_process");
24151
+ const cmdParts = coordinatorSetup.command.trim().split(/\s+/);
24152
+ const [regCmd, ...regArgs] = cmdParts;
24153
+ LOG.info("MeshCoordinator", `Running MCP registration: ${coordinatorSetup.command}`);
24154
+ execCmdSync(regCmd, regArgs, { stdio: "pipe", timeout: 15e3 });
24155
+ } catch (error) {
24156
+ LOG.warn("MeshCoordinator", `MCP registration command failed (may be pre-registered): ${error?.message || error}`);
24157
+ }
24158
+ const cliCmdArgs = [];
24159
+ const cliCmdEnv = {};
24160
+ if (cliCmdSystemPrompt) {
24161
+ if (cliType === "codex-cli") {
24162
+ cliCmdArgs.push("-c", `developer_instructions=${JSON.stringify(cliCmdSystemPrompt)}`);
24163
+ } else if (cliType === "gemini-cli") {
24164
+ try {
24165
+ const { writeFileSync: wfs, existsSync: efs, readFileSync: rfs } = await import("fs");
24166
+ const geminiMdPath = `${workspace}/GEMINI.md`;
24167
+ const marker = "<!-- adhdev-mesh-coordinator-prompt -->";
24168
+ const markerEnd = "<!-- /adhdev-mesh-coordinator-prompt -->";
24169
+ const block = `${marker}
24170
+ ${cliCmdSystemPrompt}
24171
+ ${markerEnd}`;
24172
+ if (efs(geminiMdPath)) {
24173
+ const existing = rfs(geminiMdPath, "utf-8");
24174
+ const replaced = existing.replace(
24175
+ new RegExp(`${marker}[\\s\\S]*?${markerEnd}`, "g"),
24176
+ block
24177
+ );
24178
+ wfs(geminiMdPath, replaced.includes(marker) ? replaced : `${existing}
24179
+
24180
+ ${block}`);
24181
+ } else {
24182
+ wfs(geminiMdPath, block);
24183
+ }
24184
+ LOG.info("MeshCoordinator", `Wrote coordinator prompt to ${workspace}/GEMINI.md`);
24185
+ } catch (e) {
24186
+ LOG.warn("MeshCoordinator", `Could not write GEMINI.md: ${e?.message || e}`);
24187
+ }
24188
+ }
24189
+ }
24190
+ const cliCmdLaunch = await this.deps.cliManager.handleCliCommand("launch_cli", {
24191
+ cliType,
24192
+ dir: workspace,
24193
+ cliArgs: cliCmdArgs.length > 0 ? cliCmdArgs : void 0,
24194
+ env: Object.keys(cliCmdEnv).length > 0 ? cliCmdEnv : void 0,
24195
+ settings: { meshCoordinatorFor: meshId }
24196
+ });
24197
+ if (!cliCmdLaunch?.success) {
24198
+ return { success: false, error: cliCmdLaunch?.error || "Failed to launch CLI session" };
24199
+ }
24200
+ LOG.info("MeshCoordinator", `Launched ${cliType} coordinator (cli_command) for mesh ${meshId}`);
24201
+ try {
24202
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
24203
+ appendLedgerEntry2(meshId, {
24204
+ kind: "coordinator_started",
24205
+ sessionId: cliCmdLaunch.sessionId || cliCmdLaunch.id,
24206
+ providerType: cliType,
24207
+ payload: { workspace }
24208
+ });
24209
+ } catch {
24210
+ }
24211
+ return {
24212
+ success: true,
24213
+ meshId,
24214
+ cliType,
24215
+ workspace,
24216
+ sessionId: cliCmdLaunch.sessionId || cliCmdLaunch.id,
24217
+ mcpRegistered: true
24218
+ };
24219
+ }
23440
24220
  const configFormat = coordinatorSetup.configFormat;
23441
24221
  if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
23442
24222
  return {
@@ -23463,7 +24243,7 @@ var DaemonCommandRouter = class {
23463
24243
  workspace
23464
24244
  };
23465
24245
  }
23466
- const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync14, copyFileSync: copyFileSync4, mkdirSync: mkdirSync16 } = await import("fs");
24246
+ const { existsSync: existsSync25, readFileSync: readFileSync17, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
23467
24247
  const { dirname: dirname9 } = await import("path");
23468
24248
  const mcpConfigPath = coordinatorSetup.configPath;
23469
24249
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
@@ -23497,21 +24277,21 @@ var DaemonCommandRouter = class {
23497
24277
  };
23498
24278
  }
23499
24279
  try {
23500
- mkdirSync16(dirname9(mcpConfigPath), { recursive: true });
24280
+ mkdirSync17(dirname9(mcpConfigPath), { recursive: true });
23501
24281
  } catch (error) {
23502
24282
  const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
23503
24283
  LOG.error("MeshCoordinator", message);
23504
24284
  if (hermesManualFallback) return returnManualFallback(message);
23505
24285
  return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
23506
24286
  }
23507
- const hadExistingMcpConfig = existsSync23(mcpConfigPath);
24287
+ const hadExistingMcpConfig = existsSync25(mcpConfigPath);
23508
24288
  let existingMcpConfig = hermesBaseConfig?.config || {};
23509
24289
  if (hermesBaseConfig) {
23510
24290
  copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
23511
24291
  }
23512
24292
  if (hadExistingMcpConfig) {
23513
24293
  try {
23514
- const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
24294
+ const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync17(mcpConfigPath, "utf-8"), configFormat);
23515
24295
  existingMcpConfig = { ...existingMcpConfig, ...parsedExistingMcpConfig };
23516
24296
  copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
23517
24297
  } catch (error) {
@@ -23533,7 +24313,7 @@ var DaemonCommandRouter = class {
23533
24313
  }
23534
24314
  };
23535
24315
  try {
23536
- writeFileSync14(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
24316
+ writeFileSync15(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
23537
24317
  } catch (error) {
23538
24318
  const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
23539
24319
  LOG.error("MeshCoordinator", message);
@@ -23570,6 +24350,16 @@ var DaemonCommandRouter = class {
23570
24350
  return { success: false, error: launchResult?.error || "Failed to launch CLI session" };
23571
24351
  }
23572
24352
  LOG.info("MeshCoordinator", `Launched ${cliType} coordinator for mesh ${meshId} in ${workspace}`);
24353
+ try {
24354
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
24355
+ appendLedgerEntry2(meshId, {
24356
+ kind: "coordinator_started",
24357
+ sessionId: launchResult.sessionId || launchResult.id,
24358
+ providerType: cliType,
24359
+ payload: { workspace }
24360
+ });
24361
+ } catch {
24362
+ }
23573
24363
  return {
23574
24364
  success: true,
23575
24365
  meshId,
@@ -31355,6 +32145,7 @@ var SessionRegistry = class {
31355
32145
  // src/boot/daemon-lifecycle.ts
31356
32146
  init_logger();
31357
32147
  init_config();
32148
+ init_mesh_events();
31358
32149
  async function initDaemonComponents(config) {
31359
32150
  installGlobalInterceptor();
31360
32151
  const appConfig = loadConfig();
@@ -31638,6 +32429,7 @@ async function shutdownDaemonComponents(components) {
31638
32429
  TurnSnapshotTracker,
31639
32430
  VersionArchive,
31640
32431
  addNode,
32432
+ appendLedgerEntry,
31641
32433
  appendRecentActivity,
31642
32434
  buildAssistantChatMessage,
31643
32435
  buildChatMessage,
@@ -31655,6 +32447,7 @@ async function shutdownDaemonComponents(components) {
31655
32447
  buildThoughtChatMessage,
31656
32448
  buildToolChatMessage,
31657
32449
  buildUserChatMessage,
32450
+ claimNextTask,
31658
32451
  classifyChatMessageVisibility,
31659
32452
  classifyHotChatSessionsForSubscriptionFlush,
31660
32453
  clearDebugTrace,
@@ -31673,6 +32466,7 @@ async function shutdownDaemonComponents(components) {
31673
32466
  detectAllVersions,
31674
32467
  detectCLIs,
31675
32468
  detectIDEs,
32469
+ enqueueTask,
31676
32470
  ensureSessionHostReady,
31677
32471
  execNpmCommandSync,
31678
32472
  filterActivityChatMessages,
@@ -31691,10 +32485,13 @@ async function shutdownDaemonComponents(components) {
31691
32485
  getGitFileDiff,
31692
32486
  getGitRepoStatus,
31693
32487
  getHostMemorySnapshot,
32488
+ getLedgerDir,
32489
+ getLedgerSummary,
31694
32490
  getLogLevel,
31695
32491
  getMesh,
31696
32492
  getMeshByRepo,
31697
32493
  getNpmExecOptions,
32494
+ getQueue,
31698
32495
  getRecentActivity,
31699
32496
  getRecentCommands,
31700
32497
  getRecentDebugTrace,
@@ -31702,6 +32499,7 @@ async function shutdownDaemonComponents(components) {
31702
32499
  getSavedProviderSessions,
31703
32500
  getSessionHostRecoveryLabel,
31704
32501
  getSessionHostSurfaceKind,
32502
+ getSessionRecoveryContext,
31705
32503
  getWorkspaceState,
31706
32504
  handleGitCommand,
31707
32505
  hasCdpManager,
@@ -31755,6 +32553,7 @@ async function shutdownDaemonComponents(components) {
31755
32553
  prepareSessionModalUpdate,
31756
32554
  probeCdpPort,
31757
32555
  readChatHistory,
32556
+ readLedgerEntries,
31758
32557
  recordDebugTrace,
31759
32558
  registerExtensionProviders,
31760
32559
  removeNode,
@@ -31783,9 +32582,12 @@ async function shutdownDaemonComponents(components) {
31783
32582
  startDaemonDevSupport,
31784
32583
  summarizeGitStatus,
31785
32584
  syncMeshes,
32585
+ triggerMeshQueue,
31786
32586
  updateConfig,
31787
32587
  updateMesh,
31788
32588
  updateNode,
32589
+ updateSessionTaskStatus,
32590
+ updateTaskStatus,
31789
32591
  upsertSavedProviderSession
31790
32592
  });
31791
32593
  //# sourceMappingURL=index.js.map