@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/cli-adapters/provider-cli-adapter.d.ts +2 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +14 -4
- package/dist/commands/mesh-coordinator.d.ts +8 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1018 -216
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1014 -224
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events.d.ts +11 -1
- package/dist/mesh/mesh-ledger.d.ts +90 -0
- package/dist/mesh/mesh-sync.d.ts +10 -0
- package/dist/mesh/mesh-work-queue.d.ts +50 -0
- package/dist/repo-mesh-types.d.ts +6 -0
- package/dist/shared-types.d.ts +12 -0
- package/package.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +10 -4
- package/src/cli-adapters/provider-cli-shared.ts +14 -4
- package/src/commands/mesh-coordinator.ts +28 -6
- package/src/commands/router.ts +222 -0
- package/src/commands/stream-commands.ts +8 -1
- package/src/index.ts +11 -0
- package/src/mesh/coordinator-prompt.ts +27 -12
- package/src/mesh/mesh-events.ts +200 -1
- package/src/mesh/mesh-ledger.ts +378 -0
- package/src/mesh/mesh-sync.ts +32 -0
- package/src/mesh/mesh-work-queue.ts +164 -0
- package/src/repo-mesh-types.ts +7 -0
- package/src/shared-types.ts +12 -0
- package/src/status/builders.ts +13 -0
package/dist/index.mjs
CHANGED
|
@@ -38,7 +38,8 @@ var init_repo_mesh_types = __esm({
|
|
|
38
38
|
dirtyWorkspaceBehavior: "warn",
|
|
39
39
|
maxParallelTasks: 2,
|
|
40
40
|
spawnedSessionVisibility: "visible",
|
|
41
|
-
sessionCleanupOnNodeRemove: "preserve"
|
|
41
|
+
sessionCleanupOnNodeRemove: "preserve",
|
|
42
|
+
maxTaskRetries: 1
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
});
|
|
@@ -668,12 +669,13 @@ function buildRulesSection(coordinatorCliType) {
|
|
|
668
669
|
return `## Rules
|
|
669
670
|
|
|
670
671
|
- **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.
|
|
671
|
-
- **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.
|
|
672
|
+
- **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.
|
|
672
673
|
- **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.
|
|
673
|
-
- **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.
|
|
674
|
+
- **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.
|
|
674
675
|
- **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.
|
|
675
676
|
- **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.
|
|
676
|
-
- **Handle failures
|
|
677
|
+
- **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.
|
|
678
|
+
- **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.
|
|
677
679
|
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
678
680
|
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
679
681
|
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.
|
|
@@ -694,6 +696,7 @@ var init_coordinator_prompt = __esm({
|
|
|
694
696
|
| \`mesh_launch_session\` | Start a new agent session on a node |
|
|
695
697
|
| \`mesh_send_task\` | Send a task (natural language) to a running agent |
|
|
696
698
|
| \`mesh_read_chat\` | Read an agent's recent messages to check progress |
|
|
699
|
+
| \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
|
|
697
700
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
698
701
|
| \`mesh_checkpoint\` | Create a git checkpoint on a node |
|
|
699
702
|
| \`mesh_approve\` | Approve/reject a pending agent action |
|
|
@@ -704,25 +707,372 @@ var init_coordinator_prompt = __esm({
|
|
|
704
707
|
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\`.`;
|
|
705
708
|
WORKFLOW_SECTION = `## Orchestration Workflow
|
|
706
709
|
|
|
707
|
-
1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
|
|
708
|
-
2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
|
|
709
|
-
3. **Delegate** \u2014
|
|
710
|
-
a.
|
|
711
|
-
b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
|
|
712
|
-
c.
|
|
713
|
-
d.
|
|
714
|
-
4. **Monitor** \u2014 Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly
|
|
710
|
+
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.
|
|
711
|
+
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.
|
|
712
|
+
3. **Queue / Delegate** \u2014 The Mesh uses an autonomous pull-based Work Queue:
|
|
713
|
+
a. **General Tasks**: Enqueue tasks using \`mesh_enqueue_task\`. Idle node agents will automatically pull tasks from the queue and begin working.
|
|
714
|
+
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.
|
|
715
|
+
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.
|
|
716
|
+
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.
|
|
717
|
+
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\`.
|
|
715
718
|
5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
|
|
716
719
|
6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
|
|
717
720
|
7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
|
|
718
|
-
8. **Report** \u2014 Summarize what was done, what changed, and any issues
|
|
721
|
+
8. **Report** \u2014 Summarize what was done, what changed, and any issues.
|
|
722
|
+
|
|
723
|
+
## Failure Recovery
|
|
724
|
+
|
|
725
|
+
When a node agent stops unexpectedly, the daemon automatically enriches the system message with **Recovery Context** that includes:
|
|
726
|
+
- The number of consecutive failures on that node
|
|
727
|
+
- The original task message (if recorded in the ledger)
|
|
728
|
+
- A recommendation: **retry**, **reassign**, or **escalate**
|
|
729
|
+
|
|
730
|
+
Follow these recovery rules:
|
|
731
|
+
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.
|
|
732
|
+
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.
|
|
733
|
+
3. **If no recovery context**: The stop may be intentional (normal completion). Use \`mesh_read_chat\` once to verify, then move on.
|
|
734
|
+
4. **Always record what happened**: After handling a failure, briefly note the outcome in your report to the user.`;
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
// src/mesh/mesh-ledger.ts
|
|
739
|
+
var mesh_ledger_exports = {};
|
|
740
|
+
__export(mesh_ledger_exports, {
|
|
741
|
+
appendLedgerEntry: () => appendLedgerEntry,
|
|
742
|
+
appendRemoteLedgerEntries: () => appendRemoteLedgerEntries,
|
|
743
|
+
getLedgerDir: () => getLedgerDir,
|
|
744
|
+
getLedgerSummary: () => getLedgerSummary,
|
|
745
|
+
getSessionRecoveryContext: () => getSessionRecoveryContext,
|
|
746
|
+
meshLedgerEvents: () => meshLedgerEvents,
|
|
747
|
+
readLedgerEntries: () => readLedgerEntries
|
|
748
|
+
});
|
|
749
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, appendFileSync, statSync as statSync2, renameSync } from "fs";
|
|
750
|
+
import { join as join5 } from "path";
|
|
751
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
752
|
+
import { EventEmitter } from "events";
|
|
753
|
+
function getLedgerDir() {
|
|
754
|
+
const dir = join5(getConfigDir(), LEDGER_DIR_NAME);
|
|
755
|
+
if (!existsSync5(dir)) {
|
|
756
|
+
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
757
|
+
}
|
|
758
|
+
return dir;
|
|
759
|
+
}
|
|
760
|
+
function getLedgerPath(meshId) {
|
|
761
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
762
|
+
return join5(getLedgerDir(), `${safe}.jsonl`);
|
|
763
|
+
}
|
|
764
|
+
function getRotatedPath(meshId, index) {
|
|
765
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
766
|
+
return join5(getLedgerDir(), `${safe}.${index}.jsonl`);
|
|
767
|
+
}
|
|
768
|
+
function appendLedgerEntry(meshId, partial) {
|
|
769
|
+
const entry = {
|
|
770
|
+
id: randomUUID4(),
|
|
771
|
+
meshId,
|
|
772
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
773
|
+
...partial
|
|
774
|
+
};
|
|
775
|
+
const filePath = getLedgerPath(meshId);
|
|
776
|
+
if (existsSync5(filePath)) {
|
|
777
|
+
try {
|
|
778
|
+
const stat2 = statSync2(filePath);
|
|
779
|
+
if (stat2.size >= MAX_FILE_SIZE_BYTES) {
|
|
780
|
+
rotateLedgerFile(meshId, filePath);
|
|
781
|
+
}
|
|
782
|
+
} catch {
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
try {
|
|
786
|
+
const line = JSON.stringify(entry) + "\n";
|
|
787
|
+
appendFileSync(filePath, line, { encoding: "utf-8", mode: 384 });
|
|
788
|
+
meshLedgerEvents.emit("append", meshId, entry);
|
|
789
|
+
return entry;
|
|
790
|
+
} catch (e) {
|
|
791
|
+
throw new Error(`Failed to append to ledger for mesh ${meshId}: ${e.message}`);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
function appendRemoteLedgerEntries(meshId, entries) {
|
|
795
|
+
if (entries.length === 0) return;
|
|
796
|
+
const ledgerPath = getLedgerPath(meshId);
|
|
797
|
+
const existing = new Set(readLedgerEntries(meshId).map((e) => e.id));
|
|
798
|
+
const newEntries = entries.filter((e) => !existing.has(e.id));
|
|
799
|
+
if (newEntries.length === 0) return;
|
|
800
|
+
try {
|
|
801
|
+
const lines = newEntries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
802
|
+
appendFileSync(ledgerPath, lines, { encoding: "utf-8", mode: 384 });
|
|
803
|
+
} catch (e) {
|
|
804
|
+
throw new Error(`Failed to append remote ledger entries for mesh ${meshId}: ${e.message}`);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
function readLedgerEntries(meshId, opts) {
|
|
808
|
+
const filePath = getLedgerPath(meshId);
|
|
809
|
+
if (!existsSync5(filePath)) return [];
|
|
810
|
+
let content;
|
|
811
|
+
try {
|
|
812
|
+
content = readFileSync3(filePath, "utf-8");
|
|
813
|
+
} catch {
|
|
814
|
+
return [];
|
|
815
|
+
}
|
|
816
|
+
const lines = content.split("\n").filter((line) => line.trim());
|
|
817
|
+
let entries = [];
|
|
818
|
+
for (const line of lines) {
|
|
819
|
+
try {
|
|
820
|
+
const entry = JSON.parse(line);
|
|
821
|
+
if (!entry.id || !entry.kind) continue;
|
|
822
|
+
entries.push(entry);
|
|
823
|
+
} catch {
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (opts?.since) {
|
|
827
|
+
const sinceDate = new Date(opts.since).getTime();
|
|
828
|
+
if (!isNaN(sinceDate)) {
|
|
829
|
+
entries = entries.filter((e) => new Date(e.timestamp).getTime() >= sinceDate);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
if (opts?.kind?.length) {
|
|
833
|
+
const kindSet = new Set(opts.kind);
|
|
834
|
+
entries = entries.filter((e) => kindSet.has(e.kind));
|
|
835
|
+
}
|
|
836
|
+
if (opts?.tail && opts.tail > 0 && entries.length > opts.tail) {
|
|
837
|
+
entries = entries.slice(-opts.tail);
|
|
838
|
+
}
|
|
839
|
+
return entries;
|
|
840
|
+
}
|
|
841
|
+
function getLedgerSummary(meshId) {
|
|
842
|
+
const entries = readLedgerEntries(meshId);
|
|
843
|
+
const now = Date.now();
|
|
844
|
+
const recentFailureCutoff = now - RECENT_FAILURE_WINDOW_MS;
|
|
845
|
+
const summary = {
|
|
846
|
+
meshId,
|
|
847
|
+
totalEntries: entries.length,
|
|
848
|
+
taskDispatched: 0,
|
|
849
|
+
taskCompleted: 0,
|
|
850
|
+
taskFailed: 0,
|
|
851
|
+
taskStalled: 0,
|
|
852
|
+
sessionLaunched: 0,
|
|
853
|
+
checkpointCreated: 0,
|
|
854
|
+
lastActivityAt: null,
|
|
855
|
+
recentFailures: 0
|
|
856
|
+
};
|
|
857
|
+
for (const entry of entries) {
|
|
858
|
+
switch (entry.kind) {
|
|
859
|
+
case "task_dispatched":
|
|
860
|
+
summary.taskDispatched++;
|
|
861
|
+
break;
|
|
862
|
+
case "task_completed":
|
|
863
|
+
summary.taskCompleted++;
|
|
864
|
+
break;
|
|
865
|
+
case "task_failed": {
|
|
866
|
+
summary.taskFailed++;
|
|
867
|
+
if (new Date(entry.timestamp).getTime() >= recentFailureCutoff) {
|
|
868
|
+
summary.recentFailures++;
|
|
869
|
+
}
|
|
870
|
+
break;
|
|
871
|
+
}
|
|
872
|
+
case "task_stalled":
|
|
873
|
+
summary.taskStalled++;
|
|
874
|
+
break;
|
|
875
|
+
case "session_launched":
|
|
876
|
+
summary.sessionLaunched++;
|
|
877
|
+
break;
|
|
878
|
+
case "checkpoint_created":
|
|
879
|
+
summary.checkpointCreated++;
|
|
880
|
+
break;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
if (entries.length > 0) {
|
|
884
|
+
summary.lastActivityAt = entries[entries.length - 1].timestamp;
|
|
885
|
+
}
|
|
886
|
+
return summary;
|
|
887
|
+
}
|
|
888
|
+
function getSessionRecoveryContext(meshId, opts) {
|
|
889
|
+
const maxRetries = opts.maxRetries ?? 1;
|
|
890
|
+
const entries = readLedgerEntries(meshId);
|
|
891
|
+
let lastDispatch = null;
|
|
892
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
893
|
+
const e = entries[i];
|
|
894
|
+
if (e.kind !== "task_dispatched") continue;
|
|
895
|
+
if (opts.sessionId && e.sessionId === opts.sessionId) {
|
|
896
|
+
lastDispatch = e;
|
|
897
|
+
break;
|
|
898
|
+
}
|
|
899
|
+
if (opts.nodeId && e.nodeId === opts.nodeId) {
|
|
900
|
+
lastDispatch = e;
|
|
901
|
+
break;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
const lastTaskMessage = typeof lastDispatch?.payload?.message === "string" ? lastDispatch.payload.message : null;
|
|
905
|
+
const now = Date.now();
|
|
906
|
+
const recentWindow = now - RECENT_FAILURE_WINDOW_MS;
|
|
907
|
+
let consecutiveNodeFailures = 0;
|
|
908
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
909
|
+
const e = entries[i];
|
|
910
|
+
if (new Date(e.timestamp).getTime() < recentWindow) break;
|
|
911
|
+
if (opts.nodeId && e.nodeId !== opts.nodeId) continue;
|
|
912
|
+
if (e.kind === "task_failed") {
|
|
913
|
+
consecutiveNodeFailures++;
|
|
914
|
+
} else if (e.kind === "task_completed" || e.kind === "task_dispatched") {
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
let taskAttemptCount = 0;
|
|
919
|
+
if (lastTaskMessage) {
|
|
920
|
+
const prefix = lastTaskMessage.slice(0, 200);
|
|
921
|
+
for (const e of entries) {
|
|
922
|
+
if (e.kind === "task_dispatched" && typeof e.payload?.message === "string") {
|
|
923
|
+
if (e.payload.message.startsWith(prefix)) {
|
|
924
|
+
taskAttemptCount++;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
const retryRecommended = consecutiveNodeFailures <= maxRetries;
|
|
930
|
+
let advice;
|
|
931
|
+
if (consecutiveNodeFailures === 0) {
|
|
932
|
+
advice = "No recent failures detected. This may be a normal stop.";
|
|
933
|
+
} else if (retryRecommended) {
|
|
934
|
+
const remaining = maxRetries - consecutiveNodeFailures + 1;
|
|
935
|
+
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.`);
|
|
936
|
+
} else {
|
|
937
|
+
advice = `Max retries exceeded (${consecutiveNodeFailures} consecutive failures). Consider: (1) reassigning to a different node, (2) simplifying the task, or (3) escalating to the user.`;
|
|
938
|
+
}
|
|
939
|
+
return {
|
|
940
|
+
lastTaskMessage,
|
|
941
|
+
failedNodeId: opts.nodeId || null,
|
|
942
|
+
failedSessionId: opts.sessionId || null,
|
|
943
|
+
failedProviderType: null,
|
|
944
|
+
// filled by caller if available
|
|
945
|
+
consecutiveNodeFailures,
|
|
946
|
+
taskAttemptCount,
|
|
947
|
+
retryRecommended,
|
|
948
|
+
advice
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
function rotateLedgerFile(meshId, currentPath) {
|
|
952
|
+
let index = 1;
|
|
953
|
+
while (existsSync5(getRotatedPath(meshId, index))) {
|
|
954
|
+
index++;
|
|
955
|
+
if (index > 10) break;
|
|
956
|
+
}
|
|
957
|
+
if (index > 10) index = 10;
|
|
958
|
+
try {
|
|
959
|
+
renameSync(currentPath, getRotatedPath(meshId, index));
|
|
960
|
+
} catch {
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
var LEDGER_DIR_NAME, MAX_FILE_SIZE_BYTES, RECENT_FAILURE_WINDOW_MS, meshLedgerEvents;
|
|
964
|
+
var init_mesh_ledger = __esm({
|
|
965
|
+
"src/mesh/mesh-ledger.ts"() {
|
|
966
|
+
"use strict";
|
|
967
|
+
init_config();
|
|
968
|
+
LEDGER_DIR_NAME = "mesh-ledger";
|
|
969
|
+
MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024;
|
|
970
|
+
RECENT_FAILURE_WINDOW_MS = 30 * 60 * 1e3;
|
|
971
|
+
meshLedgerEvents = new EventEmitter();
|
|
972
|
+
}
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
// src/mesh/mesh-work-queue.ts
|
|
976
|
+
import { existsSync as existsSync6, writeFileSync as writeFileSync3, readFileSync as readFileSync4 } from "fs";
|
|
977
|
+
import { join as join6 } from "path";
|
|
978
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
979
|
+
function getQueuePath(meshId) {
|
|
980
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
981
|
+
return join6(getLedgerDir(), `${safe}.queue.json`);
|
|
982
|
+
}
|
|
983
|
+
function readQueue(meshId) {
|
|
984
|
+
const path28 = getQueuePath(meshId);
|
|
985
|
+
if (!existsSync6(path28)) return [];
|
|
986
|
+
try {
|
|
987
|
+
const content = readFileSync4(path28, "utf-8");
|
|
988
|
+
return JSON.parse(content);
|
|
989
|
+
} catch {
|
|
990
|
+
return [];
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
function writeQueue(meshId, queue) {
|
|
994
|
+
const path28 = getQueuePath(meshId);
|
|
995
|
+
writeFileSync3(path28, JSON.stringify(queue, null, 2), "utf-8");
|
|
996
|
+
}
|
|
997
|
+
function enqueueTask(meshId, message, opts) {
|
|
998
|
+
const queue = readQueue(meshId);
|
|
999
|
+
const entry = {
|
|
1000
|
+
id: randomUUID5(),
|
|
1001
|
+
meshId,
|
|
1002
|
+
message,
|
|
1003
|
+
status: "pending",
|
|
1004
|
+
targetNodeId: opts?.targetNodeId,
|
|
1005
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1006
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1007
|
+
};
|
|
1008
|
+
queue.push(entry);
|
|
1009
|
+
writeQueue(meshId, queue);
|
|
1010
|
+
return entry;
|
|
1011
|
+
}
|
|
1012
|
+
function getQueue(meshId, opts) {
|
|
1013
|
+
let queue = readQueue(meshId);
|
|
1014
|
+
if (opts?.status?.length) {
|
|
1015
|
+
const statuses = new Set(opts.status);
|
|
1016
|
+
queue = queue.filter((q) => statuses.has(q.status));
|
|
1017
|
+
}
|
|
1018
|
+
return queue;
|
|
1019
|
+
}
|
|
1020
|
+
function claimNextTask(meshId, nodeId, sessionId) {
|
|
1021
|
+
const queue = readQueue(meshId);
|
|
1022
|
+
let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId);
|
|
1023
|
+
if (targetIdx === -1) {
|
|
1024
|
+
targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId);
|
|
1025
|
+
}
|
|
1026
|
+
if (targetIdx === -1) return null;
|
|
1027
|
+
const entry = queue[targetIdx];
|
|
1028
|
+
entry.status = "assigned";
|
|
1029
|
+
entry.assignedNodeId = nodeId;
|
|
1030
|
+
entry.assignedSessionId = sessionId;
|
|
1031
|
+
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1032
|
+
writeQueue(meshId, queue);
|
|
1033
|
+
return entry;
|
|
1034
|
+
}
|
|
1035
|
+
function updateTaskStatus(meshId, taskId, status) {
|
|
1036
|
+
const queue = readQueue(meshId);
|
|
1037
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
1038
|
+
if (idx === -1) return null;
|
|
1039
|
+
queue[idx].status = status;
|
|
1040
|
+
queue[idx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1041
|
+
writeQueue(meshId, queue);
|
|
1042
|
+
return queue[idx];
|
|
1043
|
+
}
|
|
1044
|
+
function updateSessionTaskStatus(meshId, sessionId, status) {
|
|
1045
|
+
const queue = readQueue(meshId);
|
|
1046
|
+
for (let i = queue.length - 1; i >= 0; i--) {
|
|
1047
|
+
if (queue[i].assignedSessionId === sessionId && queue[i].status === "assigned") {
|
|
1048
|
+
queue[i].status = status;
|
|
1049
|
+
queue[i].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1050
|
+
writeQueue(meshId, queue);
|
|
1051
|
+
return queue[i];
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
return null;
|
|
1055
|
+
}
|
|
1056
|
+
function getMeshQueueStats(meshId) {
|
|
1057
|
+
const queue = readQueue(meshId);
|
|
1058
|
+
return {
|
|
1059
|
+
pending: queue.filter((q) => q.status === "pending").length,
|
|
1060
|
+
assigned: queue.filter((q) => q.status === "assigned").length,
|
|
1061
|
+
completed: queue.filter((q) => q.status === "completed").length,
|
|
1062
|
+
failed: queue.filter((q) => q.status === "failed").length
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
var init_mesh_work_queue = __esm({
|
|
1066
|
+
"src/mesh/mesh-work-queue.ts"() {
|
|
1067
|
+
"use strict";
|
|
1068
|
+
init_mesh_ledger();
|
|
719
1069
|
}
|
|
720
1070
|
});
|
|
721
1071
|
|
|
722
1072
|
// src/logging/logger.ts
|
|
723
1073
|
import * as fs2 from "fs";
|
|
724
|
-
import * as
|
|
725
|
-
import * as
|
|
1074
|
+
import * as path8 from "path";
|
|
1075
|
+
import * as os2 from "os";
|
|
726
1076
|
function setLogLevel(level) {
|
|
727
1077
|
currentLevel = level;
|
|
728
1078
|
daemonLog("Logger", `Log level set to: ${level}`, "info");
|
|
@@ -737,13 +1087,13 @@ function getDaemonLogDir() {
|
|
|
737
1087
|
return LOG_DIR;
|
|
738
1088
|
}
|
|
739
1089
|
function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
|
|
740
|
-
return
|
|
1090
|
+
return path8.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
|
|
741
1091
|
}
|
|
742
1092
|
function checkDateRotation() {
|
|
743
1093
|
const today = getDateStr();
|
|
744
1094
|
if (today !== currentDate) {
|
|
745
1095
|
currentDate = today;
|
|
746
|
-
currentLogFile =
|
|
1096
|
+
currentLogFile = path8.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
747
1097
|
cleanOldLogs();
|
|
748
1098
|
}
|
|
749
1099
|
}
|
|
@@ -757,7 +1107,7 @@ function cleanOldLogs() {
|
|
|
757
1107
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
758
1108
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
759
1109
|
try {
|
|
760
|
-
fs2.unlinkSync(
|
|
1110
|
+
fs2.unlinkSync(path8.join(LOG_DIR, file));
|
|
761
1111
|
} catch {
|
|
762
1112
|
}
|
|
763
1113
|
}
|
|
@@ -880,7 +1230,7 @@ var init_logger = __esm({
|
|
|
880
1230
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
881
1231
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
882
1232
|
currentLevel = "info";
|
|
883
|
-
LOG_DIR = process.platform === "win32" ?
|
|
1233
|
+
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");
|
|
884
1234
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
885
1235
|
MAX_LOG_DAYS = 7;
|
|
886
1236
|
try {
|
|
@@ -888,16 +1238,16 @@ var init_logger = __esm({
|
|
|
888
1238
|
} catch {
|
|
889
1239
|
}
|
|
890
1240
|
currentDate = getDateStr();
|
|
891
|
-
currentLogFile =
|
|
1241
|
+
currentLogFile = path8.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
892
1242
|
cleanOldLogs();
|
|
893
1243
|
try {
|
|
894
|
-
const oldLog =
|
|
1244
|
+
const oldLog = path8.join(LOG_DIR, "daemon.log");
|
|
895
1245
|
if (fs2.existsSync(oldLog)) {
|
|
896
1246
|
const stat2 = fs2.statSync(oldLog);
|
|
897
1247
|
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
898
|
-
fs2.renameSync(oldLog,
|
|
1248
|
+
fs2.renameSync(oldLog, path8.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
899
1249
|
}
|
|
900
|
-
const oldLogBackup =
|
|
1250
|
+
const oldLogBackup = path8.join(LOG_DIR, "daemon.log.old");
|
|
901
1251
|
if (fs2.existsSync(oldLogBackup)) {
|
|
902
1252
|
fs2.unlinkSync(oldLogBackup);
|
|
903
1253
|
}
|
|
@@ -928,8 +1278,314 @@ var init_logger = __esm({
|
|
|
928
1278
|
};
|
|
929
1279
|
}
|
|
930
1280
|
};
|
|
931
|
-
interceptorInstalled = false;
|
|
932
|
-
LOG_PATH =
|
|
1281
|
+
interceptorInstalled = false;
|
|
1282
|
+
LOG_PATH = path8.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1285
|
+
|
|
1286
|
+
// src/mesh/mesh-events.ts
|
|
1287
|
+
var mesh_events_exports = {};
|
|
1288
|
+
__export(mesh_events_exports, {
|
|
1289
|
+
drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
|
|
1290
|
+
handleMeshForwardEvent: () => handleMeshForwardEvent,
|
|
1291
|
+
setupMeshEventForwarding: () => setupMeshEventForwarding,
|
|
1292
|
+
triggerMeshQueue: () => triggerMeshQueue,
|
|
1293
|
+
tryAssignQueueTask: () => tryAssignQueueTask
|
|
1294
|
+
});
|
|
1295
|
+
function drainPendingMeshCoordinatorEvents() {
|
|
1296
|
+
return pendingMeshCoordinatorEvents.splice(0);
|
|
1297
|
+
}
|
|
1298
|
+
function readNonEmptyString(value) {
|
|
1299
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
1300
|
+
}
|
|
1301
|
+
function isMeshCoordinatorEvent(eventName) {
|
|
1302
|
+
return typeof eventName === "string" && MESH_COORDINATOR_EVENTS.has(eventName);
|
|
1303
|
+
}
|
|
1304
|
+
function formatCompletionMetadata(event) {
|
|
1305
|
+
const parts = [
|
|
1306
|
+
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
1307
|
+
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
1308
|
+
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
1309
|
+
].filter(Boolean);
|
|
1310
|
+
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
1311
|
+
}
|
|
1312
|
+
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
1313
|
+
const task = claimNextTask(meshId, nodeId, sessionId);
|
|
1314
|
+
if (!task) return false;
|
|
1315
|
+
LOG.info("MeshQueue", `Node ${nodeId} (${sessionId}) pulled task ${task.id}`);
|
|
1316
|
+
components.cliManager.handleCliCommand("agent_command", {
|
|
1317
|
+
targetSessionId: sessionId,
|
|
1318
|
+
cliType: providerType,
|
|
1319
|
+
action: "send_chat",
|
|
1320
|
+
message: task.message
|
|
1321
|
+
}).catch((e) => {
|
|
1322
|
+
LOG.error("MeshQueue", `Failed to dispatch task to node ${nodeId}: ${e?.message}`);
|
|
1323
|
+
});
|
|
1324
|
+
return true;
|
|
1325
|
+
}
|
|
1326
|
+
function triggerMeshQueue(components, meshId) {
|
|
1327
|
+
const mesh = getMesh(meshId);
|
|
1328
|
+
if (!mesh) return;
|
|
1329
|
+
const cliInstances = components.instanceManager.getByCategory("cli");
|
|
1330
|
+
for (const inst of cliInstances) {
|
|
1331
|
+
const state = inst.getState();
|
|
1332
|
+
const settings = state.settings || {};
|
|
1333
|
+
const instMeshId = readNonEmptyString(settings.meshNodeFor);
|
|
1334
|
+
if (instMeshId !== meshId && !settings.launchedByCoordinator) continue;
|
|
1335
|
+
const nodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
|
|
1336
|
+
if (!nodeId) continue;
|
|
1337
|
+
if (state.status !== "idle" && state.status !== "stopped" && state.activeChat?.status !== "waiting_input") continue;
|
|
1338
|
+
const sessionId = state.instanceId;
|
|
1339
|
+
const providerType = state.type || readNonEmptyString(settings.providerType);
|
|
1340
|
+
if (providerType) {
|
|
1341
|
+
tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
function buildMeshSystemMessage(args) {
|
|
1346
|
+
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
1347
|
+
if (args.event === "agent:generating_completed") {
|
|
1348
|
+
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.`;
|
|
1349
|
+
}
|
|
1350
|
+
if (args.event === "agent:waiting_approval") {
|
|
1351
|
+
return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
1352
|
+
}
|
|
1353
|
+
if (args.event === "agent:stopped") {
|
|
1354
|
+
const rc = args.recoveryContext;
|
|
1355
|
+
if (rc && rc.consecutiveNodeFailures > 0) {
|
|
1356
|
+
const parts = [
|
|
1357
|
+
`[System] ${args.nodeLabel} has stopped unexpectedly${metadata}.`,
|
|
1358
|
+
`
|
|
1359
|
+
|
|
1360
|
+
**Recovery Context:**`,
|
|
1361
|
+
`- Consecutive failures on this node: ${rc.consecutiveNodeFailures}`,
|
|
1362
|
+
rc.taskAttemptCount > 0 ? `- This task has been attempted ${rc.taskAttemptCount} time(s)` : "",
|
|
1363
|
+
`- Recommendation: ${rc.advice}`
|
|
1364
|
+
];
|
|
1365
|
+
if (rc.retryRecommended && rc.lastTaskMessage) {
|
|
1366
|
+
parts.push(
|
|
1367
|
+
`
|
|
1368
|
+
|
|
1369
|
+
**Original task to retry:**`,
|
|
1370
|
+
`> ${rc.lastTaskMessage.length > 300 ? rc.lastTaskMessage.slice(0, 300) + "..." : rc.lastTaskMessage}`,
|
|
1371
|
+
`
|
|
1372
|
+
To retry: call \`mesh_launch_session\` for this node, then \`mesh_send_task\` with the original task.`
|
|
1373
|
+
);
|
|
1374
|
+
} else if (!rc.retryRecommended) {
|
|
1375
|
+
parts.push(
|
|
1376
|
+
`
|
|
1377
|
+
Do NOT retry on this node. Consider reassigning to a different node or asking the user for guidance.`
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
return parts.filter(Boolean).join("\n");
|
|
1381
|
+
}
|
|
1382
|
+
return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
|
|
1383
|
+
}
|
|
1384
|
+
if (args.event === "monitor:long_generating") {
|
|
1385
|
+
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.`;
|
|
1386
|
+
}
|
|
1387
|
+
return "";
|
|
1388
|
+
}
|
|
1389
|
+
function injectMeshSystemMessage(components, args) {
|
|
1390
|
+
if (args.event === "agent:generating_completed") {
|
|
1391
|
+
const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
|
|
1392
|
+
const nodeId = readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
|
|
1393
|
+
const providerType = readNonEmptyString(args.metadataEvent.providerType);
|
|
1394
|
+
if (sessionId) {
|
|
1395
|
+
updateSessionTaskStatus(args.meshId, sessionId, "completed");
|
|
1396
|
+
if (nodeId && providerType) {
|
|
1397
|
+
setTimeout(() => {
|
|
1398
|
+
tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
1399
|
+
}, 500);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
} else if (args.event === "agent:stopped") {
|
|
1403
|
+
const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
|
|
1404
|
+
if (sessionId) {
|
|
1405
|
+
updateSessionTaskStatus(args.meshId, sessionId, "failed");
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
const ledgerKind = EVENT_TO_LEDGER_KIND[args.event];
|
|
1409
|
+
if (ledgerKind) {
|
|
1410
|
+
try {
|
|
1411
|
+
appendLedgerEntry(args.meshId, {
|
|
1412
|
+
kind: ledgerKind,
|
|
1413
|
+
nodeId: readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
|
|
1414
|
+
sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || void 0,
|
|
1415
|
+
providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
|
|
1416
|
+
payload: {
|
|
1417
|
+
event: args.event,
|
|
1418
|
+
nodeLabel: args.nodeLabel,
|
|
1419
|
+
providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1422
|
+
} catch (e) {
|
|
1423
|
+
LOG.warn("MeshLedger", `Failed to record ${ledgerKind}: ${e?.message || e}`);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
let recoveryContext = null;
|
|
1427
|
+
if (args.event === "agent:stopped") {
|
|
1428
|
+
try {
|
|
1429
|
+
const mesh = getMesh(args.meshId);
|
|
1430
|
+
const maxRetries = mesh?.policy?.maxTaskRetries ?? 1;
|
|
1431
|
+
recoveryContext = getSessionRecoveryContext(args.meshId, {
|
|
1432
|
+
sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || void 0,
|
|
1433
|
+
nodeId: readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
|
|
1434
|
+
maxRetries
|
|
1435
|
+
});
|
|
1436
|
+
recoveryContext.failedProviderType = readNonEmptyString(args.metadataEvent.providerType) || null;
|
|
1437
|
+
if (recoveryContext.retryRecommended && recoveryContext.consecutiveNodeFailures > 0) {
|
|
1438
|
+
appendLedgerEntry(args.meshId, {
|
|
1439
|
+
kind: "recovery_attempted",
|
|
1440
|
+
nodeId: recoveryContext.failedNodeId || void 0,
|
|
1441
|
+
sessionId: recoveryContext.failedSessionId || void 0,
|
|
1442
|
+
providerType: recoveryContext.failedProviderType || void 0,
|
|
1443
|
+
payload: {
|
|
1444
|
+
consecutiveFailures: recoveryContext.consecutiveNodeFailures,
|
|
1445
|
+
taskAttemptCount: recoveryContext.taskAttemptCount,
|
|
1446
|
+
retryRecommended: recoveryContext.retryRecommended,
|
|
1447
|
+
advice: recoveryContext.advice
|
|
1448
|
+
}
|
|
1449
|
+
});
|
|
1450
|
+
if (recoveryContext.lastTaskMessage && recoveryContext.failedNodeId && recoveryContext.failedProviderType) {
|
|
1451
|
+
const autoNodeId = recoveryContext.failedNodeId;
|
|
1452
|
+
try {
|
|
1453
|
+
const task = enqueueTask(args.meshId, recoveryContext.lastTaskMessage, {
|
|
1454
|
+
targetNodeId: autoNodeId
|
|
1455
|
+
});
|
|
1456
|
+
LOG.info("MeshRecovery", `Auto-requeued failed task: ${task.id} for node ${autoNodeId}`);
|
|
1457
|
+
const node = mesh?.nodes.find((n) => n.id === autoNodeId);
|
|
1458
|
+
if (node) {
|
|
1459
|
+
components.cliManager.handleCliCommand("launch_cli", {
|
|
1460
|
+
cliType: recoveryContext.failedProviderType,
|
|
1461
|
+
dir: node.workspace,
|
|
1462
|
+
settings: {
|
|
1463
|
+
meshNodeFor: args.meshId,
|
|
1464
|
+
meshNodeId: node.id,
|
|
1465
|
+
spawnedSessionVisibility: mesh?.policy?.spawnedSessionVisibility || "hidden",
|
|
1466
|
+
launchedByCoordinator: true
|
|
1467
|
+
}
|
|
1468
|
+
}).catch((e) => LOG.error("MeshRecovery", `Failed to auto-relaunch session for ${node.id}: ${e?.message}`));
|
|
1469
|
+
}
|
|
1470
|
+
} catch (e) {
|
|
1471
|
+
LOG.warn("MeshRecovery", `Failed to execute auto-recovery: ${e?.message}`);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
LOG.info("MeshRecovery", `Recovery context for ${args.nodeLabel}: ${recoveryContext.advice}`);
|
|
1476
|
+
} catch (e) {
|
|
1477
|
+
LOG.warn("MeshRecovery", `Failed to build recovery context: ${e?.message || e}`);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
1481
|
+
const instState = inst.getState();
|
|
1482
|
+
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
1483
|
+
if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
|
|
1484
|
+
return true;
|
|
1485
|
+
});
|
|
1486
|
+
if (coordinatorInstances.length === 0) {
|
|
1487
|
+
if (pendingMeshCoordinatorEvents.length < MAX_PENDING_EVENTS) {
|
|
1488
|
+
pendingMeshCoordinatorEvents.push({
|
|
1489
|
+
event: args.event,
|
|
1490
|
+
meshId: args.meshId,
|
|
1491
|
+
nodeLabel: args.nodeLabel,
|
|
1492
|
+
metadataEvent: {
|
|
1493
|
+
...args.metadataEvent,
|
|
1494
|
+
...recoveryContext ? { recoveryContext } : {}
|
|
1495
|
+
},
|
|
1496
|
+
queuedAt: Date.now()
|
|
1497
|
+
});
|
|
1498
|
+
LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
|
|
1499
|
+
}
|
|
1500
|
+
return { success: true, forwarded: 0 };
|
|
1501
|
+
}
|
|
1502
|
+
const messageText = buildMeshSystemMessage({
|
|
1503
|
+
event: args.event,
|
|
1504
|
+
nodeLabel: args.nodeLabel,
|
|
1505
|
+
metadataEvent: args.metadataEvent,
|
|
1506
|
+
recoveryContext
|
|
1507
|
+
});
|
|
1508
|
+
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
1509
|
+
for (const coord of coordinatorInstances) {
|
|
1510
|
+
const coordState = coord.getState();
|
|
1511
|
+
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
1512
|
+
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
1513
|
+
}
|
|
1514
|
+
return { success: true, forwarded: coordinatorInstances.length };
|
|
1515
|
+
}
|
|
1516
|
+
function handleMeshForwardEvent(components, payload) {
|
|
1517
|
+
const eventName = readNonEmptyString(payload.event);
|
|
1518
|
+
if (!isMeshCoordinatorEvent(eventName)) {
|
|
1519
|
+
return { success: false, error: "unsupported mesh event" };
|
|
1520
|
+
}
|
|
1521
|
+
const meshId = readNonEmptyString(payload.meshId);
|
|
1522
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
1523
|
+
const nodeId = readNonEmptyString(payload.nodeId);
|
|
1524
|
+
const workspace = readNonEmptyString(payload.workspace);
|
|
1525
|
+
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
1526
|
+
return injectMeshSystemMessage(components, {
|
|
1527
|
+
meshId,
|
|
1528
|
+
nodeLabel,
|
|
1529
|
+
event: eventName,
|
|
1530
|
+
metadataEvent: {
|
|
1531
|
+
targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
|
|
1532
|
+
providerType: readNonEmptyString(payload.providerType),
|
|
1533
|
+
providerSessionId: readNonEmptyString(payload.providerSessionId)
|
|
1534
|
+
}
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
function setupMeshEventForwarding(components) {
|
|
1538
|
+
components.instanceManager.onEvent((event) => {
|
|
1539
|
+
if (!isMeshCoordinatorEvent(event.event)) return;
|
|
1540
|
+
const instanceId = readNonEmptyString(event.instanceId);
|
|
1541
|
+
if (!instanceId) return;
|
|
1542
|
+
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
1543
|
+
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
1544
|
+
const state = sourceInstance.getState();
|
|
1545
|
+
const workspace = readNonEmptyString(state.workspace);
|
|
1546
|
+
if (!workspace) return;
|
|
1547
|
+
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
1548
|
+
if (readNonEmptyString(settings.meshCoordinatorFor)) return;
|
|
1549
|
+
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
1550
|
+
const isMeshDelegate = Boolean(meshIdFromRuntime || settings.launchedByCoordinator);
|
|
1551
|
+
if (!isMeshDelegate) return;
|
|
1552
|
+
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
1553
|
+
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
1554
|
+
if (!meshId) return;
|
|
1555
|
+
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
1556
|
+
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
1557
|
+
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
1558
|
+
injectMeshSystemMessage(components, {
|
|
1559
|
+
meshId,
|
|
1560
|
+
sourceInstanceId: instanceId,
|
|
1561
|
+
nodeLabel,
|
|
1562
|
+
event: event.event,
|
|
1563
|
+
metadataEvent: event
|
|
1564
|
+
});
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
var MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND;
|
|
1568
|
+
var init_mesh_events = __esm({
|
|
1569
|
+
"src/mesh/mesh-events.ts"() {
|
|
1570
|
+
"use strict";
|
|
1571
|
+
init_mesh_config();
|
|
1572
|
+
init_logger();
|
|
1573
|
+
init_mesh_ledger();
|
|
1574
|
+
init_mesh_work_queue();
|
|
1575
|
+
MAX_PENDING_EVENTS = 50;
|
|
1576
|
+
pendingMeshCoordinatorEvents = [];
|
|
1577
|
+
MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
|
|
1578
|
+
"agent:generating_completed",
|
|
1579
|
+
"agent:waiting_approval",
|
|
1580
|
+
"agent:stopped",
|
|
1581
|
+
"monitor:long_generating"
|
|
1582
|
+
]);
|
|
1583
|
+
EVENT_TO_LEDGER_KIND = {
|
|
1584
|
+
"agent:generating_completed": "task_completed",
|
|
1585
|
+
"agent:waiting_approval": "task_approval_needed",
|
|
1586
|
+
"agent:stopped": "task_failed",
|
|
1587
|
+
"monitor:long_generating": "task_stalled"
|
|
1588
|
+
};
|
|
933
1589
|
}
|
|
934
1590
|
});
|
|
935
1591
|
|
|
@@ -2039,6 +2695,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
2039
2695
|
statusHistory = [];
|
|
2040
2696
|
// ─── CLI Scripts (script-based parsing) ───
|
|
2041
2697
|
cliScripts;
|
|
2698
|
+
/** Per-session opaque state object created by cliScripts.createState(), reset on stop. */
|
|
2699
|
+
scriptState = null;
|
|
2042
2700
|
runtimeSettings = {};
|
|
2043
2701
|
/** Full accumulated rendered PTY transcript for parser/readback use */
|
|
2044
2702
|
accumulatedBuffer = "";
|
|
@@ -2220,6 +2878,7 @@ ${lastSnapshot}`;
|
|
|
2220
2878
|
this.cliScripts = scripts;
|
|
2221
2879
|
this.parsedStatusCache = null;
|
|
2222
2880
|
this.parseErrorMessage = null;
|
|
2881
|
+
this.scriptState = typeof scripts.createState === "function" ? scripts.createState() : null;
|
|
2223
2882
|
const scriptNames = listCliScriptNames(scripts);
|
|
2224
2883
|
LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
|
|
2225
2884
|
}
|
|
@@ -2337,6 +2996,7 @@ ${lastSnapshot}`;
|
|
|
2337
2996
|
this.ready = false;
|
|
2338
2997
|
this.startupParseGate = false;
|
|
2339
2998
|
this.spawnAt = 0;
|
|
2999
|
+
this.scriptState = null;
|
|
2340
3000
|
this.onStatusChange?.();
|
|
2341
3001
|
});
|
|
2342
3002
|
this.spawnAt = Date.now();
|
|
@@ -3110,7 +3770,7 @@ ${lastSnapshot}`;
|
|
|
3110
3770
|
scope: this.currentTurnScope,
|
|
3111
3771
|
runtimeSettings: this.runtimeSettings
|
|
3112
3772
|
});
|
|
3113
|
-
const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
|
|
3773
|
+
const session = this.cliScripts.parseSession(this.scriptState, { ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
|
|
3114
3774
|
this.parseErrorMessage = null;
|
|
3115
3775
|
return session && typeof session === "object" ? session : null;
|
|
3116
3776
|
} catch (e) {
|
|
@@ -3124,7 +3784,7 @@ ${lastSnapshot}`;
|
|
|
3124
3784
|
if (!this.cliScripts?.detectStatus) return null;
|
|
3125
3785
|
try {
|
|
3126
3786
|
const screenText = this.terminalScreen.getText();
|
|
3127
|
-
const status = this.cliScripts.detectStatus({
|
|
3787
|
+
const status = this.cliScripts.detectStatus(this.scriptState, {
|
|
3128
3788
|
tail: text.slice(-500),
|
|
3129
3789
|
screenText,
|
|
3130
3790
|
rawBuffer: this.accumulatedRawBuffer,
|
|
@@ -3143,7 +3803,7 @@ ${lastSnapshot}`;
|
|
|
3143
3803
|
try {
|
|
3144
3804
|
const screenText = this.terminalScreen.getText();
|
|
3145
3805
|
const buffer = screenText || this.accumulatedBuffer;
|
|
3146
|
-
return this.cliScripts.parseApproval({
|
|
3806
|
+
return this.cliScripts.parseApproval(this.scriptState, {
|
|
3147
3807
|
buffer,
|
|
3148
3808
|
screenText,
|
|
3149
3809
|
rawBuffer: this.accumulatedRawBuffer,
|
|
@@ -3251,7 +3911,7 @@ ${lastSnapshot}`;
|
|
|
3251
3911
|
scope: this.currentTurnScope,
|
|
3252
3912
|
runtimeSettings: this.runtimeSettings
|
|
3253
3913
|
});
|
|
3254
|
-
return await Promise.resolve(fn({
|
|
3914
|
+
return await Promise.resolve(fn(this.scriptState, {
|
|
3255
3915
|
...input,
|
|
3256
3916
|
args: args && typeof args === "object" ? { ...args } : {}
|
|
3257
3917
|
}));
|
|
@@ -5851,13 +6511,36 @@ async function syncMeshes(transport) {
|
|
|
5851
6511
|
}
|
|
5852
6512
|
}
|
|
5853
6513
|
}
|
|
6514
|
+
if (transport.syncMeshLedger) {
|
|
6515
|
+
for (const local of localMeshes) {
|
|
6516
|
+
try {
|
|
6517
|
+
await syncMeshLedger(local.id, transport);
|
|
6518
|
+
} catch (e) {
|
|
6519
|
+
result.errors.push(`Ledger sync failed for "${local.name}": ${e.message}`);
|
|
6520
|
+
}
|
|
6521
|
+
}
|
|
6522
|
+
}
|
|
5854
6523
|
return result;
|
|
5855
6524
|
}
|
|
6525
|
+
async function syncMeshLedger(meshId, transport) {
|
|
6526
|
+
if (!transport.syncMeshLedger) return;
|
|
6527
|
+
const { readLedgerEntries: readLedgerEntries2, appendRemoteLedgerEntries: appendRemoteLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
6528
|
+
const localEntries = readLedgerEntries2(meshId);
|
|
6529
|
+
const res = await transport.syncMeshLedger(meshId, { newEntries: localEntries });
|
|
6530
|
+
if (res.missingEntries && res.missingEntries.length > 0) {
|
|
6531
|
+
appendRemoteLedgerEntries2(meshId, res.missingEntries);
|
|
6532
|
+
}
|
|
6533
|
+
}
|
|
6534
|
+
|
|
6535
|
+
// src/index.ts
|
|
6536
|
+
init_mesh_ledger();
|
|
6537
|
+
init_mesh_work_queue();
|
|
6538
|
+
init_mesh_events();
|
|
5856
6539
|
|
|
5857
6540
|
// src/config/state-store.ts
|
|
5858
6541
|
init_config();
|
|
5859
|
-
import { existsSync as
|
|
5860
|
-
import { join as
|
|
6542
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
6543
|
+
import { join as join8 } from "path";
|
|
5861
6544
|
var DEFAULT_STATE = {
|
|
5862
6545
|
recentActivity: [],
|
|
5863
6546
|
savedProviderSessions: [],
|
|
@@ -5870,7 +6553,7 @@ function isPlainObject2(value) {
|
|
|
5870
6553
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5871
6554
|
}
|
|
5872
6555
|
function getStatePath() {
|
|
5873
|
-
return
|
|
6556
|
+
return join8(getConfigDir(), "state.json");
|
|
5874
6557
|
}
|
|
5875
6558
|
function normalizeState(raw) {
|
|
5876
6559
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -5906,11 +6589,11 @@ function normalizeState(raw) {
|
|
|
5906
6589
|
}
|
|
5907
6590
|
function loadState() {
|
|
5908
6591
|
const statePath = getStatePath();
|
|
5909
|
-
if (!
|
|
6592
|
+
if (!existsSync8(statePath)) {
|
|
5910
6593
|
return { ...DEFAULT_STATE };
|
|
5911
6594
|
}
|
|
5912
6595
|
try {
|
|
5913
|
-
const raw =
|
|
6596
|
+
const raw = readFileSync5(statePath, "utf-8");
|
|
5914
6597
|
return normalizeState(JSON.parse(raw));
|
|
5915
6598
|
} catch {
|
|
5916
6599
|
return { ...DEFAULT_STATE };
|
|
@@ -5919,7 +6602,7 @@ function loadState() {
|
|
|
5919
6602
|
function saveState(state) {
|
|
5920
6603
|
const statePath = getStatePath();
|
|
5921
6604
|
const normalized = normalizeState(state);
|
|
5922
|
-
|
|
6605
|
+
writeFileSync4(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
5923
6606
|
}
|
|
5924
6607
|
function resetState() {
|
|
5925
6608
|
saveState({ ...DEFAULT_STATE });
|
|
@@ -5927,9 +6610,9 @@ function resetState() {
|
|
|
5927
6610
|
|
|
5928
6611
|
// src/detection/ide-detector.ts
|
|
5929
6612
|
import { execSync } from "child_process";
|
|
5930
|
-
import { existsSync as
|
|
5931
|
-
import { platform, homedir as
|
|
5932
|
-
import * as
|
|
6613
|
+
import { existsSync as existsSync9 } from "fs";
|
|
6614
|
+
import { platform, homedir as homedir4 } from "os";
|
|
6615
|
+
import * as path9 from "path";
|
|
5933
6616
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5934
6617
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5935
6618
|
function registerIDEDefinition(def) {
|
|
@@ -5948,10 +6631,10 @@ function getMergedDefinitions() {
|
|
|
5948
6631
|
function findCliCommand(command) {
|
|
5949
6632
|
const trimmed = String(command || "").trim();
|
|
5950
6633
|
if (!trimmed) return null;
|
|
5951
|
-
if (
|
|
5952
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5953
|
-
const resolved =
|
|
5954
|
-
return
|
|
6634
|
+
if (path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
6635
|
+
const candidate = trimmed.startsWith("~") ? path9.join(homedir4(), trimmed.slice(1)) : trimmed;
|
|
6636
|
+
const resolved = path9.isAbsolute(candidate) ? candidate : path9.resolve(candidate);
|
|
6637
|
+
return existsSync9(resolved) ? resolved : null;
|
|
5955
6638
|
}
|
|
5956
6639
|
try {
|
|
5957
6640
|
const result = execSync(
|
|
@@ -5976,15 +6659,15 @@ function getIdeVersion(cliCommand) {
|
|
|
5976
6659
|
}
|
|
5977
6660
|
}
|
|
5978
6661
|
function checkPathExists(paths) {
|
|
5979
|
-
const home =
|
|
6662
|
+
const home = homedir4();
|
|
5980
6663
|
for (const p of paths) {
|
|
5981
|
-
const normalized = p.startsWith("~") ?
|
|
6664
|
+
const normalized = p.startsWith("~") ? path9.join(home, p.slice(1)) : p;
|
|
5982
6665
|
if (normalized.includes("*")) {
|
|
5983
6666
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5984
6667
|
const resolved = normalized.replace("*", username);
|
|
5985
|
-
if (
|
|
6668
|
+
if (existsSync9(resolved)) return resolved;
|
|
5986
6669
|
} else {
|
|
5987
|
-
if (
|
|
6670
|
+
if (existsSync9(normalized)) return normalized;
|
|
5988
6671
|
}
|
|
5989
6672
|
}
|
|
5990
6673
|
return null;
|
|
@@ -5998,7 +6681,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5998
6681
|
let resolvedCli = cliPath;
|
|
5999
6682
|
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
6000
6683
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
6001
|
-
if (
|
|
6684
|
+
if (existsSync9(bundledCli)) resolvedCli = bundledCli;
|
|
6002
6685
|
}
|
|
6003
6686
|
if (!resolvedCli && appPath && os22 === "win32") {
|
|
6004
6687
|
const { dirname: dirname9 } = await import("path");
|
|
@@ -6011,7 +6694,7 @@ async function detectIDEs(providerLoader) {
|
|
|
6011
6694
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
6012
6695
|
];
|
|
6013
6696
|
for (const c of candidates) {
|
|
6014
|
-
if (
|
|
6697
|
+
if (existsSync9(c)) {
|
|
6015
6698
|
resolvedCli = c;
|
|
6016
6699
|
break;
|
|
6017
6700
|
}
|
|
@@ -6035,9 +6718,9 @@ async function detectIDEs(providerLoader) {
|
|
|
6035
6718
|
|
|
6036
6719
|
// src/detection/cli-detector.ts
|
|
6037
6720
|
import { exec } from "child_process";
|
|
6038
|
-
import * as
|
|
6039
|
-
import * as
|
|
6040
|
-
import { existsSync as
|
|
6721
|
+
import * as os3 from "os";
|
|
6722
|
+
import * as path10 from "path";
|
|
6723
|
+
import { existsSync as existsSync10 } from "fs";
|
|
6041
6724
|
function parseVersion(raw) {
|
|
6042
6725
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
6043
6726
|
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
@@ -6049,19 +6732,19 @@ function shellQuote(value) {
|
|
|
6049
6732
|
function expandHome(value) {
|
|
6050
6733
|
const trimmed = value.trim();
|
|
6051
6734
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
6052
|
-
return
|
|
6735
|
+
return path10.join(os3.homedir(), trimmed.slice(1));
|
|
6053
6736
|
}
|
|
6054
6737
|
function isExplicitCommandPath(command) {
|
|
6055
6738
|
const trimmed = command.trim();
|
|
6056
|
-
return
|
|
6739
|
+
return path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
6057
6740
|
}
|
|
6058
6741
|
function resolveCommandPath(command) {
|
|
6059
6742
|
const trimmed = command.trim();
|
|
6060
6743
|
if (!trimmed) return null;
|
|
6061
6744
|
if (isExplicitCommandPath(trimmed)) {
|
|
6062
6745
|
const expanded = expandHome(trimmed);
|
|
6063
|
-
const candidate =
|
|
6064
|
-
return
|
|
6746
|
+
const candidate = path10.isAbsolute(expanded) ? expanded : path10.resolve(expanded);
|
|
6747
|
+
return existsSync10(candidate) ? candidate : null;
|
|
6065
6748
|
}
|
|
6066
6749
|
return null;
|
|
6067
6750
|
}
|
|
@@ -6082,7 +6765,7 @@ function execAsync(cmd, timeoutMs = 5e3) {
|
|
|
6082
6765
|
});
|
|
6083
6766
|
}
|
|
6084
6767
|
async function detectCLIs(providerLoader, options) {
|
|
6085
|
-
const platform10 =
|
|
6768
|
+
const platform10 = os3.platform();
|
|
6086
6769
|
const whichCmd = platform10 === "win32" ? "where" : "which";
|
|
6087
6770
|
const includeVersion = options?.includeVersion !== false;
|
|
6088
6771
|
const cliList = providerLoader ? providerLoader.getCliDetectionList() : [];
|
|
@@ -6126,7 +6809,7 @@ async function detectCLI(cliId, providerLoader, options) {
|
|
|
6126
6809
|
const cliList = providerLoader.getCliDetectionList();
|
|
6127
6810
|
const target = cliList.find((c) => c.id === resolvedId);
|
|
6128
6811
|
if (target) {
|
|
6129
|
-
const platform10 =
|
|
6812
|
+
const platform10 = os3.platform();
|
|
6130
6813
|
const whichCmd = platform10 === "win32" ? "where" : "which";
|
|
6131
6814
|
try {
|
|
6132
6815
|
const explicitPath = resolveCommandPath(target.command);
|
|
@@ -6163,10 +6846,10 @@ async function detectCLI(cliId, providerLoader, options) {
|
|
|
6163
6846
|
}
|
|
6164
6847
|
|
|
6165
6848
|
// src/system/host-memory.ts
|
|
6166
|
-
import * as
|
|
6849
|
+
import * as os4 from "os";
|
|
6167
6850
|
import { execSync as execSync2 } from "child_process";
|
|
6168
6851
|
function parseDarwinAvailableBytes(totalMem) {
|
|
6169
|
-
if (
|
|
6852
|
+
if (os4.platform() !== "darwin") return null;
|
|
6170
6853
|
try {
|
|
6171
6854
|
const out = execSync2("vm_stat", {
|
|
6172
6855
|
encoding: "utf-8",
|
|
@@ -6197,8 +6880,8 @@ function parseDarwinAvailableBytes(totalMem) {
|
|
|
6197
6880
|
}
|
|
6198
6881
|
}
|
|
6199
6882
|
function getHostMemorySnapshot() {
|
|
6200
|
-
const totalMem =
|
|
6201
|
-
const freeMem =
|
|
6883
|
+
const totalMem = os4.totalmem();
|
|
6884
|
+
const freeMem = os4.freemem();
|
|
6202
6885
|
const darwinAvail = parseDarwinAvailableBytes(totalMem);
|
|
6203
6886
|
const availableMem = darwinAvail != null ? darwinAvail : freeMem;
|
|
6204
6887
|
return { totalMem, freeMem, availableMem };
|
|
@@ -11568,6 +12251,9 @@ function normalizeActiveChatData(activeChat, options = FULL_STATUS_ACTIVE_CHAT_O
|
|
|
11568
12251
|
return normalized;
|
|
11569
12252
|
}
|
|
11570
12253
|
|
|
12254
|
+
// src/status/builders.ts
|
|
12255
|
+
init_mesh_work_queue();
|
|
12256
|
+
|
|
11571
12257
|
// src/providers/provider-input-support.ts
|
|
11572
12258
|
var VALID_INPUT_MEDIA_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "video", "resource"]);
|
|
11573
12259
|
var VALID_INPUT_STRATEGIES = /* @__PURE__ */ new Set(["native", "native_acp", "resource_link", "text_fallback", "paste", "upload"]);
|
|
@@ -11793,6 +12479,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11793
12479
|
const workspace = state.workspace || null;
|
|
11794
12480
|
const git = getGitSummaryForWorkspace(workspace, options);
|
|
11795
12481
|
const title = activeChat?.title || state.name;
|
|
12482
|
+
const meshCoordinatorFor = state.settings?.meshCoordinatorFor;
|
|
12483
|
+
const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
|
|
11796
12484
|
return {
|
|
11797
12485
|
id: state.instanceId || state.type,
|
|
11798
12486
|
parentId: null,
|
|
@@ -11815,7 +12503,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11815
12503
|
errorMessage: state.errorMessage,
|
|
11816
12504
|
errorReason: state.errorReason,
|
|
11817
12505
|
lastUpdated: state.lastUpdated,
|
|
11818
|
-
settings: state.settings
|
|
12506
|
+
settings: state.settings,
|
|
12507
|
+
...meshQueueStats && { meshQueueStats }
|
|
11819
12508
|
};
|
|
11820
12509
|
}
|
|
11821
12510
|
function buildExtensionAgentSession(parent, ext, options) {
|
|
@@ -11827,6 +12516,8 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11827
12516
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11828
12517
|
const workspace = parent.workspace || null;
|
|
11829
12518
|
const git = getGitSummaryForWorkspace(workspace, options);
|
|
12519
|
+
const meshCoordinatorFor = ext.settings?.meshCoordinatorFor;
|
|
12520
|
+
const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
|
|
11830
12521
|
return {
|
|
11831
12522
|
id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
|
|
11832
12523
|
parentId: parent.instanceId || parent.type,
|
|
@@ -11849,7 +12540,8 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11849
12540
|
errorMessage: ext.errorMessage,
|
|
11850
12541
|
errorReason: ext.errorReason,
|
|
11851
12542
|
lastUpdated: ext.lastUpdated,
|
|
11852
|
-
settings: ext.settings
|
|
12543
|
+
settings: ext.settings,
|
|
12544
|
+
...meshQueueStats && { meshQueueStats }
|
|
11853
12545
|
};
|
|
11854
12546
|
}
|
|
11855
12547
|
function shouldIncludeExtensionSession(ext) {
|
|
@@ -11877,6 +12569,8 @@ function buildCliSession(state, options) {
|
|
|
11877
12569
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11878
12570
|
const workspace = state.workspace || null;
|
|
11879
12571
|
const git = getGitSummaryForWorkspace(workspace, options);
|
|
12572
|
+
const meshCoordinatorFor = state.settings?.meshCoordinatorFor;
|
|
12573
|
+
const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
|
|
11880
12574
|
return {
|
|
11881
12575
|
id: state.instanceId,
|
|
11882
12576
|
parentId: null,
|
|
@@ -11915,7 +12609,8 @@ function buildCliSession(state, options) {
|
|
|
11915
12609
|
errorMessage: state.errorMessage,
|
|
11916
12610
|
errorReason: state.errorReason,
|
|
11917
12611
|
lastUpdated: state.lastUpdated,
|
|
11918
|
-
settings: state.settings
|
|
12612
|
+
settings: state.settings,
|
|
12613
|
+
...meshQueueStats && { meshQueueStats }
|
|
11919
12614
|
};
|
|
11920
12615
|
}
|
|
11921
12616
|
function buildAcpSession(state, options) {
|
|
@@ -11927,6 +12622,8 @@ function buildAcpSession(state, options) {
|
|
|
11927
12622
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11928
12623
|
const workspace = state.workspace || null;
|
|
11929
12624
|
const git = getGitSummaryForWorkspace(workspace, options);
|
|
12625
|
+
const meshCoordinatorFor = state.settings?.meshCoordinatorFor;
|
|
12626
|
+
const meshQueueStats = meshCoordinatorFor ? getMeshQueueStats(meshCoordinatorFor) : void 0;
|
|
11930
12627
|
return {
|
|
11931
12628
|
id: state.instanceId,
|
|
11932
12629
|
parentId: null,
|
|
@@ -11948,7 +12645,8 @@ function buildAcpSession(state, options) {
|
|
|
11948
12645
|
errorMessage: state.errorMessage,
|
|
11949
12646
|
errorReason: state.errorReason,
|
|
11950
12647
|
lastUpdated: state.lastUpdated,
|
|
11951
|
-
settings: state.settings
|
|
12648
|
+
settings: state.settings,
|
|
12649
|
+
...meshQueueStats && { meshQueueStats }
|
|
11952
12650
|
};
|
|
11953
12651
|
}
|
|
11954
12652
|
function buildSessionEntries(allStates, cdpManagers, options = {}) {
|
|
@@ -12058,7 +12756,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
12058
12756
|
import * as fs4 from "fs";
|
|
12059
12757
|
import * as os6 from "os";
|
|
12060
12758
|
import * as path12 from "path";
|
|
12061
|
-
import { randomUUID as
|
|
12759
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
12062
12760
|
init_logger();
|
|
12063
12761
|
|
|
12064
12762
|
// src/logging/debug-trace.ts
|
|
@@ -12583,7 +13281,7 @@ function safeBundleIdSegment(value, fallback) {
|
|
|
12583
13281
|
function createChatDebugBundleId(targetSessionId) {
|
|
12584
13282
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.]/g, "").replace("T", "T").replace("Z", "Z");
|
|
12585
13283
|
const sessionSegment = safeBundleIdSegment(targetSessionId, "unknown-session");
|
|
12586
|
-
return `chat-debug-${timestamp}-${sessionSegment}-${
|
|
13284
|
+
return `chat-debug-${timestamp}-${sessionSegment}-${randomUUID7().slice(0, 8)}`;
|
|
12587
13285
|
}
|
|
12588
13286
|
function buildChatDebugBundleSummary(bundle) {
|
|
12589
13287
|
const target = bundle.target && typeof bundle.target === "object" ? bundle.target : {};
|
|
@@ -14289,11 +14987,13 @@ async function handleOpenPanel(h, args) {
|
|
|
14289
14987
|
async function handlePtyInput(h, args) {
|
|
14290
14988
|
const { cliType, data, targetSessionId } = args || {};
|
|
14291
14989
|
if (!data) return { success: false, error: "data required" };
|
|
14990
|
+
const cleanData = typeof data === "string" ? data.replace(/\x1b\[\?[0-9;]*c/g, "") : data;
|
|
14991
|
+
if (!cleanData) return { success: true };
|
|
14292
14992
|
const adapter = h.getCliAdapter(targetSessionId || cliType);
|
|
14293
14993
|
if (!adapter || typeof adapter.writeRaw !== "function") {
|
|
14294
14994
|
return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
|
|
14295
14995
|
}
|
|
14296
|
-
await adapter.writeRaw(
|
|
14996
|
+
await adapter.writeRaw(cleanData);
|
|
14297
14997
|
return { success: true };
|
|
14298
14998
|
}
|
|
14299
14999
|
function handlePtyResize(_h, args) {
|
|
@@ -15250,7 +15950,7 @@ init_provider_cli_adapter();
|
|
|
15250
15950
|
import * as os13 from "os";
|
|
15251
15951
|
import * as path18 from "path";
|
|
15252
15952
|
import * as crypto4 from "crypto";
|
|
15253
|
-
import { existsSync as
|
|
15953
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
15254
15954
|
import { execFileSync } from "child_process";
|
|
15255
15955
|
import chalk from "chalk";
|
|
15256
15956
|
init_config();
|
|
@@ -17632,7 +18332,7 @@ function commandExists(command) {
|
|
|
17632
18332
|
const trimmed = command.trim();
|
|
17633
18333
|
if (!trimmed) return false;
|
|
17634
18334
|
if (isExplicitCommand(trimmed)) {
|
|
17635
|
-
return
|
|
18335
|
+
return existsSync14(expandExecutable(trimmed));
|
|
17636
18336
|
}
|
|
17637
18337
|
try {
|
|
17638
18338
|
execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -17661,10 +18361,10 @@ function hasCliArg(args, flag) {
|
|
|
17661
18361
|
}
|
|
17662
18362
|
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
17663
18363
|
const baseDir = path18.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
17664
|
-
|
|
18364
|
+
mkdirSync9(baseDir, { recursive: true });
|
|
17665
18365
|
const workspaceHash = crypto4.createHash("sha256").update(path18.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
17666
18366
|
const filePath = path18.join(baseDir, `${workspaceHash}.json`);
|
|
17667
|
-
|
|
18367
|
+
writeFileSync9(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
17668
18368
|
return filePath;
|
|
17669
18369
|
}
|
|
17670
18370
|
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
@@ -20903,10 +21603,10 @@ import * as yaml from "js-yaml";
|
|
|
20903
21603
|
// src/commands/mesh-coordinator.ts
|
|
20904
21604
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
20905
21605
|
import { createHash as createHash2 } from "crypto";
|
|
20906
|
-
import { existsSync as
|
|
21606
|
+
import { existsSync as existsSync17, readdirSync as readdirSync7, realpathSync as realpathSync2 } from "fs";
|
|
20907
21607
|
import { createRequire as createRequire2 } from "module";
|
|
20908
21608
|
import * as os17 from "os";
|
|
20909
|
-
import { dirname as dirname4, isAbsolute as isAbsolute11, join as
|
|
21609
|
+
import { dirname as dirname4, isAbsolute as isAbsolute11, join as join20, resolve as resolve13 } from "path";
|
|
20910
21610
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
20911
21611
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20912
21612
|
var HERMES_CLI_TYPE = "hermes-cli";
|
|
@@ -20927,7 +21627,7 @@ function resolveHermesMeshCoordinatorSetup(options) {
|
|
|
20927
21627
|
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20928
21628
|
};
|
|
20929
21629
|
}
|
|
20930
|
-
const configPath =
|
|
21630
|
+
const configPath = join20(resolveHermesCoordinatorHome(options.meshId, options.workspace), "config.yaml");
|
|
20931
21631
|
if (!configPath.trim()) {
|
|
20932
21632
|
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20933
21633
|
}
|
|
@@ -21008,6 +21708,22 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
21008
21708
|
if (!instructions || !template?.trim()) {
|
|
21009
21709
|
return { kind: "unsupported", reason: "Provider manual MCP setup is missing instructions or template" };
|
|
21010
21710
|
}
|
|
21711
|
+
const renderedTemplate = renderMeshCoordinatorTemplate(template, {
|
|
21712
|
+
meshId,
|
|
21713
|
+
workspace,
|
|
21714
|
+
serverName,
|
|
21715
|
+
adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND
|
|
21716
|
+
});
|
|
21717
|
+
const isCliCommand = !renderedTemplate.trim().includes("\n") && !renderedTemplate.trim().startsWith("{");
|
|
21718
|
+
if (isCliCommand) {
|
|
21719
|
+
return {
|
|
21720
|
+
kind: "cli_command",
|
|
21721
|
+
serverName,
|
|
21722
|
+
command: renderedTemplate.trim(),
|
|
21723
|
+
requiresRestart: mcpConfig.requiresRestart === true,
|
|
21724
|
+
instructions
|
|
21725
|
+
};
|
|
21726
|
+
}
|
|
21011
21727
|
return {
|
|
21012
21728
|
kind: "manual",
|
|
21013
21729
|
serverName,
|
|
@@ -21015,12 +21731,7 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
21015
21731
|
configPathCommand: mcpConfig.configPathCommand,
|
|
21016
21732
|
requiresRestart: mcpConfig.requiresRestart === true,
|
|
21017
21733
|
instructions,
|
|
21018
|
-
template:
|
|
21019
|
-
meshId,
|
|
21020
|
-
workspace,
|
|
21021
|
-
serverName,
|
|
21022
|
-
adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND
|
|
21023
|
-
})
|
|
21734
|
+
template: renderedTemplate
|
|
21024
21735
|
};
|
|
21025
21736
|
}
|
|
21026
21737
|
return {
|
|
@@ -21035,14 +21746,14 @@ function resolveHermesCoordinatorHome(meshId, workspace) {
|
|
|
21035
21746
|
const key = `${meshId || "mesh"}
|
|
21036
21747
|
${resolve13(workspace || os17.tmpdir())}`;
|
|
21037
21748
|
const hash = createHash2("sha256").update(key).digest("hex").slice(0, 16);
|
|
21038
|
-
return
|
|
21749
|
+
return join20(os17.tmpdir(), `adhdev-hermes-mesh-coordinator-${hash}`);
|
|
21039
21750
|
}
|
|
21040
21751
|
function resolveMcpConfigPath(configPath, workspace) {
|
|
21041
21752
|
const trimmed = configPath.trim();
|
|
21042
21753
|
if (trimmed === "~") return os17.homedir();
|
|
21043
|
-
if (trimmed.startsWith("~/")) return
|
|
21754
|
+
if (trimmed.startsWith("~/")) return join20(os17.homedir(), trimmed.slice(2));
|
|
21044
21755
|
if (isAbsolute11(trimmed)) return trimmed;
|
|
21045
|
-
return
|
|
21756
|
+
return join20(workspace, trimmed);
|
|
21046
21757
|
}
|
|
21047
21758
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
21048
21759
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
@@ -21082,15 +21793,15 @@ function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
|
21082
21793
|
for (const entry of (pathValue || "").split(":")) {
|
|
21083
21794
|
const dir = entry.trim();
|
|
21084
21795
|
if (!dir) continue;
|
|
21085
|
-
addCandidate(
|
|
21796
|
+
addCandidate(join20(dir, "node"));
|
|
21086
21797
|
}
|
|
21087
21798
|
}
|
|
21088
21799
|
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
21089
|
-
const versionsDir =
|
|
21800
|
+
const versionsDir = join20(homeDir, ".nvm", "versions", "node");
|
|
21090
21801
|
try {
|
|
21091
21802
|
const versionDirs = readdirSync7(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
21092
21803
|
for (const versionDir of versionDirs) {
|
|
21093
|
-
addCandidate(
|
|
21804
|
+
addCandidate(join20(versionsDir, versionDir, "bin", "node"));
|
|
21094
21805
|
}
|
|
21095
21806
|
} catch {
|
|
21096
21807
|
}
|
|
@@ -21141,7 +21852,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
21141
21852
|
if (normalized) return normalized;
|
|
21142
21853
|
}
|
|
21143
21854
|
try {
|
|
21144
|
-
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] :
|
|
21855
|
+
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join20(process.cwd(), "adhdev-daemon.js");
|
|
21145
21856
|
const req = createRequire2(requireBase);
|
|
21146
21857
|
const resolvedModule = req.resolve("@adhdev/mcp-server");
|
|
21147
21858
|
return normalizeExistingPath(resolvedModule) || resolvedModule;
|
|
@@ -21151,141 +21862,15 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
21151
21862
|
}
|
|
21152
21863
|
function normalizeExistingPath(filePath) {
|
|
21153
21864
|
try {
|
|
21154
|
-
if (!
|
|
21865
|
+
if (!existsSync17(filePath)) return null;
|
|
21155
21866
|
return realpathSync2.native(filePath);
|
|
21156
21867
|
} catch {
|
|
21157
21868
|
return null;
|
|
21158
21869
|
}
|
|
21159
21870
|
}
|
|
21160
21871
|
|
|
21161
|
-
// src/
|
|
21162
|
-
|
|
21163
|
-
init_logger();
|
|
21164
|
-
var MAX_PENDING_EVENTS = 50;
|
|
21165
|
-
var pendingMeshCoordinatorEvents = [];
|
|
21166
|
-
function drainPendingMeshCoordinatorEvents() {
|
|
21167
|
-
return pendingMeshCoordinatorEvents.splice(0);
|
|
21168
|
-
}
|
|
21169
|
-
function readNonEmptyString(value) {
|
|
21170
|
-
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
21171
|
-
}
|
|
21172
|
-
var MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
|
|
21173
|
-
"agent:generating_completed",
|
|
21174
|
-
"agent:waiting_approval",
|
|
21175
|
-
"agent:stopped",
|
|
21176
|
-
"monitor:long_generating"
|
|
21177
|
-
]);
|
|
21178
|
-
function isMeshCoordinatorEvent(eventName) {
|
|
21179
|
-
return typeof eventName === "string" && MESH_COORDINATOR_EVENTS.has(eventName);
|
|
21180
|
-
}
|
|
21181
|
-
function formatCompletionMetadata(event) {
|
|
21182
|
-
const parts = [
|
|
21183
|
-
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
21184
|
-
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
21185
|
-
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
21186
|
-
].filter(Boolean);
|
|
21187
|
-
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
21188
|
-
}
|
|
21189
|
-
function buildMeshSystemMessage(args) {
|
|
21190
|
-
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
21191
|
-
if (args.event === "agent:generating_completed") {
|
|
21192
|
-
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.`;
|
|
21193
|
-
}
|
|
21194
|
-
if (args.event === "agent:waiting_approval") {
|
|
21195
|
-
return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
21196
|
-
}
|
|
21197
|
-
if (args.event === "agent:stopped") {
|
|
21198
|
-
return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
|
|
21199
|
-
}
|
|
21200
|
-
if (args.event === "monitor:long_generating") {
|
|
21201
|
-
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.`;
|
|
21202
|
-
}
|
|
21203
|
-
return "";
|
|
21204
|
-
}
|
|
21205
|
-
function injectMeshSystemMessage(components, args) {
|
|
21206
|
-
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
21207
|
-
const instState = inst.getState();
|
|
21208
|
-
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
21209
|
-
if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
|
|
21210
|
-
return true;
|
|
21211
|
-
});
|
|
21212
|
-
if (coordinatorInstances.length === 0) {
|
|
21213
|
-
if (pendingMeshCoordinatorEvents.length < MAX_PENDING_EVENTS) {
|
|
21214
|
-
pendingMeshCoordinatorEvents.push({
|
|
21215
|
-
event: args.event,
|
|
21216
|
-
meshId: args.meshId,
|
|
21217
|
-
nodeLabel: args.nodeLabel,
|
|
21218
|
-
metadataEvent: args.metadataEvent,
|
|
21219
|
-
queuedAt: Date.now()
|
|
21220
|
-
});
|
|
21221
|
-
LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
|
|
21222
|
-
}
|
|
21223
|
-
return { success: true, forwarded: 0 };
|
|
21224
|
-
}
|
|
21225
|
-
const messageText = buildMeshSystemMessage({
|
|
21226
|
-
event: args.event,
|
|
21227
|
-
nodeLabel: args.nodeLabel,
|
|
21228
|
-
metadataEvent: args.metadataEvent
|
|
21229
|
-
});
|
|
21230
|
-
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
21231
|
-
for (const coord of coordinatorInstances) {
|
|
21232
|
-
const coordState = coord.getState();
|
|
21233
|
-
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
21234
|
-
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
21235
|
-
}
|
|
21236
|
-
return { success: true, forwarded: coordinatorInstances.length };
|
|
21237
|
-
}
|
|
21238
|
-
function handleMeshForwardEvent(components, payload) {
|
|
21239
|
-
const eventName = readNonEmptyString(payload.event);
|
|
21240
|
-
if (!isMeshCoordinatorEvent(eventName)) {
|
|
21241
|
-
return { success: false, error: "unsupported mesh event" };
|
|
21242
|
-
}
|
|
21243
|
-
const meshId = readNonEmptyString(payload.meshId);
|
|
21244
|
-
if (!meshId) return { success: false, error: "meshId required" };
|
|
21245
|
-
const nodeId = readNonEmptyString(payload.nodeId);
|
|
21246
|
-
const workspace = readNonEmptyString(payload.workspace);
|
|
21247
|
-
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
21248
|
-
return injectMeshSystemMessage(components, {
|
|
21249
|
-
meshId,
|
|
21250
|
-
nodeLabel,
|
|
21251
|
-
event: eventName,
|
|
21252
|
-
metadataEvent: {
|
|
21253
|
-
targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
|
|
21254
|
-
providerType: readNonEmptyString(payload.providerType),
|
|
21255
|
-
providerSessionId: readNonEmptyString(payload.providerSessionId)
|
|
21256
|
-
}
|
|
21257
|
-
});
|
|
21258
|
-
}
|
|
21259
|
-
function setupMeshEventForwarding(components) {
|
|
21260
|
-
components.instanceManager.onEvent((event) => {
|
|
21261
|
-
if (!isMeshCoordinatorEvent(event.event)) return;
|
|
21262
|
-
const instanceId = readNonEmptyString(event.instanceId);
|
|
21263
|
-
if (!instanceId) return;
|
|
21264
|
-
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
21265
|
-
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
21266
|
-
const state = sourceInstance.getState();
|
|
21267
|
-
const workspace = readNonEmptyString(state.workspace);
|
|
21268
|
-
if (!workspace) return;
|
|
21269
|
-
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
21270
|
-
if (readNonEmptyString(settings.meshCoordinatorFor)) return;
|
|
21271
|
-
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
21272
|
-
const isMeshDelegate = Boolean(meshIdFromRuntime || settings.launchedByCoordinator);
|
|
21273
|
-
if (!isMeshDelegate) return;
|
|
21274
|
-
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
21275
|
-
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
21276
|
-
if (!meshId) return;
|
|
21277
|
-
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
21278
|
-
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
21279
|
-
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
21280
|
-
injectMeshSystemMessage(components, {
|
|
21281
|
-
meshId,
|
|
21282
|
-
sourceInstanceId: instanceId,
|
|
21283
|
-
nodeLabel,
|
|
21284
|
-
event: event.event,
|
|
21285
|
-
metadataEvent: event
|
|
21286
|
-
});
|
|
21287
|
-
});
|
|
21288
|
-
}
|
|
21872
|
+
// src/commands/router.ts
|
|
21873
|
+
init_mesh_events();
|
|
21289
21874
|
|
|
21290
21875
|
// src/status/snapshot.ts
|
|
21291
21876
|
init_config();
|
|
@@ -22985,6 +23570,21 @@ var DaemonCommandRouter = class {
|
|
|
22985
23570
|
return { success: false, error: e.message };
|
|
22986
23571
|
}
|
|
22987
23572
|
}
|
|
23573
|
+
case "get_mesh_ledger": {
|
|
23574
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
23575
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
23576
|
+
try {
|
|
23577
|
+
const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
23578
|
+
const tail = typeof args?.tail === "number" ? args.tail : 20;
|
|
23579
|
+
const since = typeof args?.since === "string" ? args.since : void 0;
|
|
23580
|
+
const kind = Array.isArray(args?.kind) ? args.kind.filter((k) => typeof k === "string") : void 0;
|
|
23581
|
+
const entries = readLedgerEntries2(meshId, { tail, since, kind });
|
|
23582
|
+
const summary = getLedgerSummary2(meshId);
|
|
23583
|
+
return { success: true, entries, summary };
|
|
23584
|
+
} catch (e) {
|
|
23585
|
+
return { success: false, error: e.message };
|
|
23586
|
+
}
|
|
23587
|
+
}
|
|
22988
23588
|
case "add_mesh_node": {
|
|
22989
23589
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22990
23590
|
const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
@@ -23053,6 +23653,54 @@ var DaemonCommandRouter = class {
|
|
|
23053
23653
|
return { success: false, error: e.message };
|
|
23054
23654
|
}
|
|
23055
23655
|
}
|
|
23656
|
+
case "refine_mesh_node": {
|
|
23657
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
23658
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
23659
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
23660
|
+
try {
|
|
23661
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
23662
|
+
const mesh = meshRecord?.mesh;
|
|
23663
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
23664
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
23665
|
+
if (!node.isLocalWorktree || !node.workspace) {
|
|
23666
|
+
return { success: false, error: `Refinery requires a local worktree node` };
|
|
23667
|
+
}
|
|
23668
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
23669
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
23670
|
+
if (!repoRoot) return { success: false, error: "Source node repoRoot not found" };
|
|
23671
|
+
const { execFile: execFile3 } = await import("child_process");
|
|
23672
|
+
const { promisify: promisify3 } = await import("util");
|
|
23673
|
+
const execFileAsync3 = promisify3(execFile3);
|
|
23674
|
+
const { stdout: branchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: node.workspace, encoding: "utf8" });
|
|
23675
|
+
const branch = branchStdout.trim();
|
|
23676
|
+
if (!branch) return { success: false, error: "Could not determine branch of the worktree node" };
|
|
23677
|
+
const { stdout: baseBranchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
|
|
23678
|
+
const baseBranch = baseBranchStdout.trim();
|
|
23679
|
+
try {
|
|
23680
|
+
await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
|
|
23681
|
+
} catch (e) {
|
|
23682
|
+
return { success: false, error: `Merge failed (conflicts?): ${e.message}` };
|
|
23683
|
+
}
|
|
23684
|
+
const removeResult = await this.execute("remove_mesh_node", {
|
|
23685
|
+
meshId,
|
|
23686
|
+
nodeId,
|
|
23687
|
+
sessionCleanupMode: "kill",
|
|
23688
|
+
inlineMesh: args?.inlineMesh
|
|
23689
|
+
});
|
|
23690
|
+
try {
|
|
23691
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
23692
|
+
appendLedgerEntry2(meshId, {
|
|
23693
|
+
kind: "node_removed",
|
|
23694
|
+
nodeId,
|
|
23695
|
+
payload: { refined: true, mergedBranch: branch, into: baseBranch }
|
|
23696
|
+
});
|
|
23697
|
+
} catch {
|
|
23698
|
+
}
|
|
23699
|
+
return { success: true, merged: true, branch, into: baseBranch, removeResult };
|
|
23700
|
+
} catch (e) {
|
|
23701
|
+
return { success: false, error: e.message };
|
|
23702
|
+
}
|
|
23703
|
+
}
|
|
23056
23704
|
case "remove_mesh_node": {
|
|
23057
23705
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
23058
23706
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
@@ -23088,6 +23736,17 @@ var DaemonCommandRouter = class {
|
|
|
23088
23736
|
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
23089
23737
|
removed = removeNode3(meshId, nodeId);
|
|
23090
23738
|
}
|
|
23739
|
+
if (removed) {
|
|
23740
|
+
try {
|
|
23741
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
23742
|
+
appendLedgerEntry2(meshId, {
|
|
23743
|
+
kind: "node_removed",
|
|
23744
|
+
nodeId,
|
|
23745
|
+
payload: { worktree: !!node?.isLocalWorktree, sessionCleanupMode }
|
|
23746
|
+
});
|
|
23747
|
+
} catch {
|
|
23748
|
+
}
|
|
23749
|
+
}
|
|
23091
23750
|
return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
|
|
23092
23751
|
} catch (e) {
|
|
23093
23752
|
return { success: false, error: e.message };
|
|
@@ -23117,9 +23776,9 @@ var DaemonCommandRouter = class {
|
|
|
23117
23776
|
});
|
|
23118
23777
|
let node;
|
|
23119
23778
|
if (meshRecord.inline) {
|
|
23120
|
-
const { randomUUID:
|
|
23779
|
+
const { randomUUID: randomUUID10 } = await import("crypto");
|
|
23121
23780
|
node = {
|
|
23122
|
-
id: `node_${
|
|
23781
|
+
id: `node_${randomUUID10().replace(/-/g, "")}`,
|
|
23123
23782
|
workspace: result.worktreePath,
|
|
23124
23783
|
repoRoot: result.worktreePath,
|
|
23125
23784
|
daemonId: sourceNode.daemonId,
|
|
@@ -23144,6 +23803,15 @@ var DaemonCommandRouter = class {
|
|
|
23144
23803
|
});
|
|
23145
23804
|
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
23146
23805
|
}
|
|
23806
|
+
try {
|
|
23807
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
23808
|
+
appendLedgerEntry2(meshId, {
|
|
23809
|
+
kind: "node_cloned",
|
|
23810
|
+
nodeId: node.id,
|
|
23811
|
+
payload: { sourceNodeId, branch: result.branch, worktreePath: result.worktreePath }
|
|
23812
|
+
});
|
|
23813
|
+
} catch {
|
|
23814
|
+
}
|
|
23147
23815
|
return {
|
|
23148
23816
|
success: true,
|
|
23149
23817
|
node,
|
|
@@ -23154,6 +23822,19 @@ var DaemonCommandRouter = class {
|
|
|
23154
23822
|
return { success: false, error: e.message };
|
|
23155
23823
|
}
|
|
23156
23824
|
}
|
|
23825
|
+
case "trigger_mesh_queue": {
|
|
23826
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
23827
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
23828
|
+
try {
|
|
23829
|
+
const { triggerMeshQueue: triggerMeshQueue2 } = await Promise.resolve().then(() => (init_mesh_events(), mesh_events_exports));
|
|
23830
|
+
if (meshId) {
|
|
23831
|
+
triggerMeshQueue2(this.deps, meshId);
|
|
23832
|
+
}
|
|
23833
|
+
return { success: true };
|
|
23834
|
+
} catch (e) {
|
|
23835
|
+
return { success: false, error: e.message };
|
|
23836
|
+
}
|
|
23837
|
+
}
|
|
23157
23838
|
// ─── Mesh Coordinator Launch ───
|
|
23158
23839
|
case "launch_mesh_coordinator": {
|
|
23159
23840
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
@@ -23232,6 +23913,93 @@ var DaemonCommandRouter = class {
|
|
|
23232
23913
|
meshCoordinatorSetup: coordinatorSetup
|
|
23233
23914
|
};
|
|
23234
23915
|
}
|
|
23916
|
+
if (coordinatorSetup.kind === "cli_command") {
|
|
23917
|
+
let cliCmdSystemPrompt = "";
|
|
23918
|
+
try {
|
|
23919
|
+
cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
23920
|
+
} catch (error) {
|
|
23921
|
+
const message = error?.message || String(error);
|
|
23922
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
23923
|
+
return {
|
|
23924
|
+
success: false,
|
|
23925
|
+
code: "mesh_coordinator_prompt_failed",
|
|
23926
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
23927
|
+
meshId,
|
|
23928
|
+
cliType,
|
|
23929
|
+
workspace
|
|
23930
|
+
};
|
|
23931
|
+
}
|
|
23932
|
+
try {
|
|
23933
|
+
const { execFileSync: execCmdSync } = await import("child_process");
|
|
23934
|
+
const cmdParts = coordinatorSetup.command.trim().split(/\s+/);
|
|
23935
|
+
const [regCmd, ...regArgs] = cmdParts;
|
|
23936
|
+
LOG.info("MeshCoordinator", `Running MCP registration: ${coordinatorSetup.command}`);
|
|
23937
|
+
execCmdSync(regCmd, regArgs, { stdio: "pipe", timeout: 15e3 });
|
|
23938
|
+
} catch (error) {
|
|
23939
|
+
LOG.warn("MeshCoordinator", `MCP registration command failed (may be pre-registered): ${error?.message || error}`);
|
|
23940
|
+
}
|
|
23941
|
+
const cliCmdArgs = [];
|
|
23942
|
+
const cliCmdEnv = {};
|
|
23943
|
+
if (cliCmdSystemPrompt) {
|
|
23944
|
+
if (cliType === "codex-cli") {
|
|
23945
|
+
cliCmdArgs.push("-c", `developer_instructions=${JSON.stringify(cliCmdSystemPrompt)}`);
|
|
23946
|
+
} else if (cliType === "gemini-cli") {
|
|
23947
|
+
try {
|
|
23948
|
+
const { writeFileSync: wfs, existsSync: efs, readFileSync: rfs } = await import("fs");
|
|
23949
|
+
const geminiMdPath = `${workspace}/GEMINI.md`;
|
|
23950
|
+
const marker = "<!-- adhdev-mesh-coordinator-prompt -->";
|
|
23951
|
+
const markerEnd = "<!-- /adhdev-mesh-coordinator-prompt -->";
|
|
23952
|
+
const block = `${marker}
|
|
23953
|
+
${cliCmdSystemPrompt}
|
|
23954
|
+
${markerEnd}`;
|
|
23955
|
+
if (efs(geminiMdPath)) {
|
|
23956
|
+
const existing = rfs(geminiMdPath, "utf-8");
|
|
23957
|
+
const replaced = existing.replace(
|
|
23958
|
+
new RegExp(`${marker}[\\s\\S]*?${markerEnd}`, "g"),
|
|
23959
|
+
block
|
|
23960
|
+
);
|
|
23961
|
+
wfs(geminiMdPath, replaced.includes(marker) ? replaced : `${existing}
|
|
23962
|
+
|
|
23963
|
+
${block}`);
|
|
23964
|
+
} else {
|
|
23965
|
+
wfs(geminiMdPath, block);
|
|
23966
|
+
}
|
|
23967
|
+
LOG.info("MeshCoordinator", `Wrote coordinator prompt to ${workspace}/GEMINI.md`);
|
|
23968
|
+
} catch (e) {
|
|
23969
|
+
LOG.warn("MeshCoordinator", `Could not write GEMINI.md: ${e?.message || e}`);
|
|
23970
|
+
}
|
|
23971
|
+
}
|
|
23972
|
+
}
|
|
23973
|
+
const cliCmdLaunch = await this.deps.cliManager.handleCliCommand("launch_cli", {
|
|
23974
|
+
cliType,
|
|
23975
|
+
dir: workspace,
|
|
23976
|
+
cliArgs: cliCmdArgs.length > 0 ? cliCmdArgs : void 0,
|
|
23977
|
+
env: Object.keys(cliCmdEnv).length > 0 ? cliCmdEnv : void 0,
|
|
23978
|
+
settings: { meshCoordinatorFor: meshId }
|
|
23979
|
+
});
|
|
23980
|
+
if (!cliCmdLaunch?.success) {
|
|
23981
|
+
return { success: false, error: cliCmdLaunch?.error || "Failed to launch CLI session" };
|
|
23982
|
+
}
|
|
23983
|
+
LOG.info("MeshCoordinator", `Launched ${cliType} coordinator (cli_command) for mesh ${meshId}`);
|
|
23984
|
+
try {
|
|
23985
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
23986
|
+
appendLedgerEntry2(meshId, {
|
|
23987
|
+
kind: "coordinator_started",
|
|
23988
|
+
sessionId: cliCmdLaunch.sessionId || cliCmdLaunch.id,
|
|
23989
|
+
providerType: cliType,
|
|
23990
|
+
payload: { workspace }
|
|
23991
|
+
});
|
|
23992
|
+
} catch {
|
|
23993
|
+
}
|
|
23994
|
+
return {
|
|
23995
|
+
success: true,
|
|
23996
|
+
meshId,
|
|
23997
|
+
cliType,
|
|
23998
|
+
workspace,
|
|
23999
|
+
sessionId: cliCmdLaunch.sessionId || cliCmdLaunch.id,
|
|
24000
|
+
mcpRegistered: true
|
|
24001
|
+
};
|
|
24002
|
+
}
|
|
23235
24003
|
const configFormat = coordinatorSetup.configFormat;
|
|
23236
24004
|
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
23237
24005
|
return {
|
|
@@ -23258,7 +24026,7 @@ var DaemonCommandRouter = class {
|
|
|
23258
24026
|
workspace
|
|
23259
24027
|
};
|
|
23260
24028
|
}
|
|
23261
|
-
const { existsSync:
|
|
24029
|
+
const { existsSync: existsSync25, readFileSync: readFileSync17, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
|
|
23262
24030
|
const { dirname: dirname9 } = await import("path");
|
|
23263
24031
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
23264
24032
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
@@ -23292,21 +24060,21 @@ var DaemonCommandRouter = class {
|
|
|
23292
24060
|
};
|
|
23293
24061
|
}
|
|
23294
24062
|
try {
|
|
23295
|
-
|
|
24063
|
+
mkdirSync17(dirname9(mcpConfigPath), { recursive: true });
|
|
23296
24064
|
} catch (error) {
|
|
23297
24065
|
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
23298
24066
|
LOG.error("MeshCoordinator", message);
|
|
23299
24067
|
if (hermesManualFallback) return returnManualFallback(message);
|
|
23300
24068
|
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
23301
24069
|
}
|
|
23302
|
-
const hadExistingMcpConfig =
|
|
24070
|
+
const hadExistingMcpConfig = existsSync25(mcpConfigPath);
|
|
23303
24071
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
23304
24072
|
if (hermesBaseConfig) {
|
|
23305
24073
|
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
|
|
23306
24074
|
}
|
|
23307
24075
|
if (hadExistingMcpConfig) {
|
|
23308
24076
|
try {
|
|
23309
|
-
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
24077
|
+
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync17(mcpConfigPath, "utf-8"), configFormat);
|
|
23310
24078
|
existingMcpConfig = { ...existingMcpConfig, ...parsedExistingMcpConfig };
|
|
23311
24079
|
copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
|
|
23312
24080
|
} catch (error) {
|
|
@@ -23328,7 +24096,7 @@ var DaemonCommandRouter = class {
|
|
|
23328
24096
|
}
|
|
23329
24097
|
};
|
|
23330
24098
|
try {
|
|
23331
|
-
|
|
24099
|
+
writeFileSync15(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
23332
24100
|
} catch (error) {
|
|
23333
24101
|
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
23334
24102
|
LOG.error("MeshCoordinator", message);
|
|
@@ -23365,6 +24133,16 @@ var DaemonCommandRouter = class {
|
|
|
23365
24133
|
return { success: false, error: launchResult?.error || "Failed to launch CLI session" };
|
|
23366
24134
|
}
|
|
23367
24135
|
LOG.info("MeshCoordinator", `Launched ${cliType} coordinator for mesh ${meshId} in ${workspace}`);
|
|
24136
|
+
try {
|
|
24137
|
+
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
24138
|
+
appendLedgerEntry2(meshId, {
|
|
24139
|
+
kind: "coordinator_started",
|
|
24140
|
+
sessionId: launchResult.sessionId || launchResult.id,
|
|
24141
|
+
providerType: cliType,
|
|
24142
|
+
payload: { workspace }
|
|
24143
|
+
});
|
|
24144
|
+
} catch {
|
|
24145
|
+
}
|
|
23368
24146
|
return {
|
|
23369
24147
|
success: true,
|
|
23370
24148
|
meshId,
|
|
@@ -31155,6 +31933,7 @@ var SessionRegistry = class {
|
|
|
31155
31933
|
// src/boot/daemon-lifecycle.ts
|
|
31156
31934
|
init_logger();
|
|
31157
31935
|
init_config();
|
|
31936
|
+
init_mesh_events();
|
|
31158
31937
|
async function initDaemonComponents(config) {
|
|
31159
31938
|
installGlobalInterceptor();
|
|
31160
31939
|
const appConfig = loadConfig();
|
|
@@ -31437,6 +32216,7 @@ export {
|
|
|
31437
32216
|
TurnSnapshotTracker,
|
|
31438
32217
|
VersionArchive,
|
|
31439
32218
|
addNode,
|
|
32219
|
+
appendLedgerEntry,
|
|
31440
32220
|
appendRecentActivity,
|
|
31441
32221
|
buildAssistantChatMessage,
|
|
31442
32222
|
buildChatMessage,
|
|
@@ -31454,6 +32234,7 @@ export {
|
|
|
31454
32234
|
buildThoughtChatMessage,
|
|
31455
32235
|
buildToolChatMessage,
|
|
31456
32236
|
buildUserChatMessage,
|
|
32237
|
+
claimNextTask,
|
|
31457
32238
|
classifyChatMessageVisibility,
|
|
31458
32239
|
classifyHotChatSessionsForSubscriptionFlush,
|
|
31459
32240
|
clearDebugTrace,
|
|
@@ -31472,6 +32253,7 @@ export {
|
|
|
31472
32253
|
detectAllVersions,
|
|
31473
32254
|
detectCLIs,
|
|
31474
32255
|
detectIDEs,
|
|
32256
|
+
enqueueTask,
|
|
31475
32257
|
ensureSessionHostReady,
|
|
31476
32258
|
execNpmCommandSync,
|
|
31477
32259
|
filterActivityChatMessages,
|
|
@@ -31490,10 +32272,13 @@ export {
|
|
|
31490
32272
|
getGitFileDiff,
|
|
31491
32273
|
getGitRepoStatus,
|
|
31492
32274
|
getHostMemorySnapshot,
|
|
32275
|
+
getLedgerDir,
|
|
32276
|
+
getLedgerSummary,
|
|
31493
32277
|
getLogLevel,
|
|
31494
32278
|
getMesh,
|
|
31495
32279
|
getMeshByRepo,
|
|
31496
32280
|
getNpmExecOptions,
|
|
32281
|
+
getQueue,
|
|
31497
32282
|
getRecentActivity,
|
|
31498
32283
|
getRecentCommands,
|
|
31499
32284
|
getRecentDebugTrace,
|
|
@@ -31501,6 +32286,7 @@ export {
|
|
|
31501
32286
|
getSavedProviderSessions,
|
|
31502
32287
|
getSessionHostRecoveryLabel,
|
|
31503
32288
|
getSessionHostSurfaceKind,
|
|
32289
|
+
getSessionRecoveryContext,
|
|
31504
32290
|
getWorkspaceState,
|
|
31505
32291
|
handleGitCommand,
|
|
31506
32292
|
hasCdpManager,
|
|
@@ -31554,6 +32340,7 @@ export {
|
|
|
31554
32340
|
prepareSessionModalUpdate,
|
|
31555
32341
|
probeCdpPort,
|
|
31556
32342
|
readChatHistory,
|
|
32343
|
+
readLedgerEntries,
|
|
31557
32344
|
recordDebugTrace,
|
|
31558
32345
|
registerExtensionProviders,
|
|
31559
32346
|
removeNode,
|
|
@@ -31582,9 +32369,12 @@ export {
|
|
|
31582
32369
|
startDaemonDevSupport,
|
|
31583
32370
|
summarizeGitStatus,
|
|
31584
32371
|
syncMeshes,
|
|
32372
|
+
triggerMeshQueue,
|
|
31585
32373
|
updateConfig,
|
|
31586
32374
|
updateMesh,
|
|
31587
32375
|
updateNode,
|
|
32376
|
+
updateSessionTaskStatus,
|
|
32377
|
+
updateTaskStatus,
|
|
31588
32378
|
upsertSavedProviderSession
|
|
31589
32379
|
};
|
|
31590
32380
|
//# sourceMappingURL=index.mjs.map
|