@adhdev/daemon-core 0.9.76-rc.5 → 0.9.76-rc.51

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.
Files changed (46) hide show
  1. package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -1
  2. package/dist/cli-adapters/provider-cli-runtime.d.ts +1 -0
  3. package/dist/commands/cli-manager.d.ts +17 -4
  4. package/dist/commands/mesh-coordinator.d.ts +2 -0
  5. package/dist/commands/router.d.ts +11 -0
  6. package/dist/config/mesh-config.d.ts +3 -0
  7. package/dist/git/git-types.d.ts +1 -1
  8. package/dist/git/git-worktree.d.ts +64 -0
  9. package/dist/git/index.d.ts +2 -0
  10. package/dist/index.js +1398 -436
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +1425 -467
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/mesh/coordinator-prompt.d.ts +1 -0
  15. package/dist/mesh/mesh-events.d.ts +9 -0
  16. package/dist/providers/chat-message-normalization.d.ts +11 -0
  17. package/dist/providers/cli-provider-instance.d.ts +3 -0
  18. package/dist/providers/provider-instance-manager.d.ts +1 -0
  19. package/dist/providers/provider-instance.d.ts +2 -0
  20. package/dist/repo-mesh-types.d.ts +13 -0
  21. package/dist/shared-types.d.ts +4 -0
  22. package/package.json +4 -5
  23. package/src/cli-adapters/provider-cli-adapter.ts +28 -7
  24. package/src/cli-adapters/provider-cli-runtime.ts +3 -2
  25. package/src/commands/chat-commands.ts +109 -8
  26. package/src/commands/cli-manager.ts +78 -5
  27. package/src/commands/handler.ts +13 -4
  28. package/src/commands/mesh-coordinator.ts +149 -6
  29. package/src/commands/router.d.ts +1 -0
  30. package/src/commands/router.ts +554 -34
  31. package/src/config/mesh-config.ts +23 -2
  32. package/src/git/git-commands.ts +5 -1
  33. package/src/git/git-types.ts +1 -0
  34. package/src/git/git-worktree.ts +214 -0
  35. package/src/git/index.ts +14 -0
  36. package/src/mesh/coordinator-prompt.ts +25 -10
  37. package/src/mesh/mesh-events.ts +109 -43
  38. package/src/providers/chat-message-normalization.ts +54 -0
  39. package/src/providers/cli-provider-instance.d.ts +2 -0
  40. package/src/providers/cli-provider-instance.ts +58 -7
  41. package/src/providers/provider-instance-manager.ts +20 -1
  42. package/src/providers/provider-instance.ts +2 -0
  43. package/src/repo-mesh-types.ts +15 -0
  44. package/src/shared-types.ts +4 -0
  45. package/src/status/builders.ts +17 -12
  46. package/src/status/reporter.ts +6 -0
package/dist/index.mjs CHANGED
@@ -36,11 +36,140 @@ var init_repo_mesh_types = __esm({
36
36
  requireApprovalForPush: true,
37
37
  requireApprovalForDestructiveGit: true,
38
38
  dirtyWorkspaceBehavior: "warn",
39
- maxParallelTasks: 2
39
+ maxParallelTasks: 2,
40
+ sessionCleanupOnNodeRemove: "preserve"
40
41
  };
41
42
  }
42
43
  });
43
44
 
45
+ // src/git/git-worktree.ts
46
+ var git_worktree_exports = {};
47
+ __export(git_worktree_exports, {
48
+ createWorktree: () => createWorktree,
49
+ listWorktrees: () => listWorktrees,
50
+ parseWorktreeListOutput: () => parseWorktreeListOutput,
51
+ removeWorktree: () => removeWorktree,
52
+ resolveWorktreePath: () => resolveWorktreePath
53
+ });
54
+ import * as path4 from "path";
55
+ import { mkdir } from "fs/promises";
56
+ import { existsSync } from "fs";
57
+ import { execFile as execFile2 } from "child_process";
58
+ import { promisify as promisify2 } from "util";
59
+ function resolveWorktreePath(repoRoot, meshName, branch) {
60
+ const safeBranch = branch.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
61
+ const safeMeshName = meshName.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
62
+ const parentDir = path4.dirname(repoRoot);
63
+ return path4.join(parentDir, WORKTREE_DIR_NAME, safeMeshName, safeBranch);
64
+ }
65
+ async function createWorktree(opts) {
66
+ const { repoRoot, branch, baseBranch, meshName } = opts;
67
+ const targetDir = opts.targetDir || resolveWorktreePath(repoRoot, meshName, branch);
68
+ if (existsSync(targetDir)) {
69
+ throw new Error(`Worktree target directory already exists: ${targetDir}`);
70
+ }
71
+ await mkdir(path4.dirname(targetDir), { recursive: true });
72
+ const args = ["worktree", "add", targetDir, "-b", branch];
73
+ if (baseBranch) {
74
+ args.push(baseBranch);
75
+ }
76
+ try {
77
+ await execFileAsync2("git", args, {
78
+ cwd: repoRoot,
79
+ encoding: "utf8",
80
+ timeout: GIT_TIMEOUT_MS,
81
+ maxBuffer: GIT_MAX_BUFFER,
82
+ windowsHide: true
83
+ });
84
+ } catch (error) {
85
+ const stderr = typeof error.stderr === "string" ? error.stderr : "";
86
+ if (/already exists/i.test(stderr)) {
87
+ throw new Error(`Branch '${branch}' already exists or is checked out in another worktree`);
88
+ }
89
+ throw new Error(`git worktree add failed: ${stderr.trim() || error.message}`);
90
+ }
91
+ return {
92
+ success: true,
93
+ worktreePath: targetDir,
94
+ branch
95
+ };
96
+ }
97
+ async function removeWorktree(repoRoot, worktreePath) {
98
+ if (!existsSync(worktreePath)) {
99
+ await pruneWorktrees(repoRoot);
100
+ return { success: true, removedPath: worktreePath };
101
+ }
102
+ try {
103
+ await execFileAsync2("git", ["worktree", "remove", worktreePath, "--force"], {
104
+ cwd: repoRoot,
105
+ encoding: "utf8",
106
+ timeout: GIT_TIMEOUT_MS,
107
+ maxBuffer: GIT_MAX_BUFFER,
108
+ windowsHide: true
109
+ });
110
+ } catch (error) {
111
+ const stderr = typeof error.stderr === "string" ? error.stderr : "";
112
+ throw new Error(`git worktree remove failed: ${stderr.trim() || error.message}`);
113
+ }
114
+ return { success: true, removedPath: worktreePath };
115
+ }
116
+ async function listWorktrees(repoRoot) {
117
+ const { stdout } = await execFileAsync2("git", ["worktree", "list", "--porcelain"], {
118
+ cwd: repoRoot,
119
+ encoding: "utf8",
120
+ timeout: GIT_TIMEOUT_MS,
121
+ maxBuffer: GIT_MAX_BUFFER,
122
+ windowsHide: true
123
+ });
124
+ return parseWorktreeListOutput(stdout);
125
+ }
126
+ function parseWorktreeListOutput(output) {
127
+ const entries = [];
128
+ const blocks = output.trim().split(/\n\n+/);
129
+ for (const block of blocks) {
130
+ if (!block.trim()) continue;
131
+ const lines = block.trim().split("\n");
132
+ const entry = { path: "", head: "", branch: null, bare: false };
133
+ for (const line of lines) {
134
+ if (line.startsWith("worktree ")) {
135
+ entry.path = line.slice("worktree ".length).trim();
136
+ } else if (line.startsWith("HEAD ")) {
137
+ entry.head = line.slice("HEAD ".length).trim();
138
+ } else if (line.startsWith("branch ")) {
139
+ const ref = line.slice("branch ".length).trim();
140
+ entry.branch = ref.replace(/^refs\/heads\//, "");
141
+ } else if (line === "bare") {
142
+ entry.bare = true;
143
+ }
144
+ }
145
+ if (entry.path) {
146
+ entries.push(entry);
147
+ }
148
+ }
149
+ return entries;
150
+ }
151
+ async function pruneWorktrees(repoRoot) {
152
+ try {
153
+ await execFileAsync2("git", ["worktree", "prune"], {
154
+ cwd: repoRoot,
155
+ encoding: "utf8",
156
+ timeout: GIT_TIMEOUT_MS,
157
+ windowsHide: true
158
+ });
159
+ } catch {
160
+ }
161
+ }
162
+ var execFileAsync2, WORKTREE_DIR_NAME, GIT_TIMEOUT_MS, GIT_MAX_BUFFER;
163
+ var init_git_worktree = __esm({
164
+ "src/git/git-worktree.ts"() {
165
+ "use strict";
166
+ execFileAsync2 = promisify2(execFile2);
167
+ WORKTREE_DIR_NAME = ".adhdev-worktrees";
168
+ GIT_TIMEOUT_MS = 3e4;
169
+ GIT_MAX_BUFFER = 4 * 1024 * 1024;
170
+ }
171
+ });
172
+
44
173
  // src/config/config.ts
45
174
  var config_exports = {};
46
175
  __export(config_exports, {
@@ -56,8 +185,8 @@ __export(config_exports, {
56
185
  updateConfig: () => updateConfig
57
186
  });
58
187
  import { homedir } from "os";
59
- import { join } from "path";
60
- import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
188
+ import { join as join2 } from "path";
189
+ import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
61
190
  import { randomUUID } from "crypto";
62
191
  function resolveProviderSourceMode(providerSourceMode, legacyDisableUpstream) {
63
192
  if (providerSourceMode === "normal" || providerSourceMode === "no-upstream") {
@@ -151,18 +280,18 @@ function ensureMachineId(config) {
151
280
  };
152
281
  }
153
282
  function getConfigDir() {
154
- const dir = join(homedir(), ".adhdev");
155
- if (!existsSync(dir)) {
283
+ const dir = join2(homedir(), ".adhdev");
284
+ if (!existsSync2(dir)) {
156
285
  mkdirSync(dir, { recursive: true });
157
286
  }
158
287
  return dir;
159
288
  }
160
289
  function getConfigPath() {
161
- return join(getConfigDir(), "config.json");
290
+ return join2(getConfigDir(), "config.json");
162
291
  }
163
292
  function migrateStateToStateFile(raw) {
164
- const statePath = join(getConfigDir(), "state.json");
165
- if (existsSync(statePath)) return;
293
+ const statePath = join2(getConfigDir(), "state.json");
294
+ if (existsSync2(statePath)) return;
166
295
  const recentActivity = Array.isArray(raw.recentActivity) ? raw.recentActivity : [];
167
296
  const savedProviderSessions = Array.isArray(raw.savedProviderSessions) ? raw.savedProviderSessions : [];
168
297
  const legacySessionReads = isPlainObject(raw.recentSessionReads) ? raw.recentSessionReads : {};
@@ -186,7 +315,7 @@ function migrateStateToStateFile(raw) {
186
315
  }
187
316
  function loadConfig() {
188
317
  const configPath = getConfigPath();
189
- if (!existsSync(configPath)) {
318
+ if (!existsSync2(configPath)) {
190
319
  const initialized = ensureMachineId({ ...DEFAULT_CONFIG });
191
320
  try {
192
321
  saveConfig(initialized.config);
@@ -217,7 +346,7 @@ function saveConfig(config) {
217
346
  const configPath = getConfigPath();
218
347
  const dir = getConfigDir();
219
348
  const normalized = normalizeConfig(config);
220
- if (!existsSync(dir)) {
349
+ if (!existsSync2(dir)) {
221
350
  mkdirSync(dir, { recursive: true, mode: 448 });
222
351
  }
223
352
  writeFileSync(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
@@ -295,17 +424,17 @@ __export(mesh_config_exports, {
295
424
  updateMesh: () => updateMesh,
296
425
  updateNode: () => updateNode
297
426
  });
298
- import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
299
- import { join as join3 } from "path";
427
+ import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
428
+ import { join as join4 } from "path";
300
429
  import { randomUUID as randomUUID3 } from "crypto";
301
430
  function getMeshConfigPath() {
302
- return join3(getConfigDir(), "meshes.json");
431
+ return join4(getConfigDir(), "meshes.json");
303
432
  }
304
433
  function loadMeshConfig() {
305
- const path26 = getMeshConfigPath();
306
- if (!existsSync3(path26)) return { meshes: [] };
434
+ const path27 = getMeshConfigPath();
435
+ if (!existsSync4(path27)) return { meshes: [] };
307
436
  try {
308
- const raw = JSON.parse(readFileSync2(path26, "utf-8"));
437
+ const raw = JSON.parse(readFileSync2(path27, "utf-8"));
309
438
  if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
310
439
  return raw;
311
440
  } catch {
@@ -313,16 +442,16 @@ function loadMeshConfig() {
313
442
  }
314
443
  }
315
444
  function saveMeshConfig(config) {
316
- const path26 = getMeshConfigPath();
317
- writeFileSync2(path26, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
445
+ const path27 = getMeshConfigPath();
446
+ writeFileSync2(path27, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
318
447
  }
319
448
  function normalizeRepoIdentity(remoteUrl) {
320
449
  let identity = remoteUrl.trim();
321
450
  if (identity.startsWith("http://") || identity.startsWith("https://")) {
322
451
  try {
323
452
  const url = new URL(identity);
324
- const path26 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
325
- return `${url.hostname}/${path26}`;
453
+ const path27 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
454
+ return `${url.hostname}/${path27}`;
326
455
  } catch {
327
456
  }
328
457
  }
@@ -330,6 +459,18 @@ function normalizeRepoIdentity(remoteUrl) {
330
459
  if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
331
460
  return identity;
332
461
  }
462
+ function mergeMeshPolicy(base, patch) {
463
+ const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
464
+ if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
465
+ policy.dirtyWorkspaceBehavior = "warn";
466
+ }
467
+ const maxParallelTasks = Number(policy.maxParallelTasks);
468
+ policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
469
+ if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
470
+ policy.sessionCleanupOnNodeRemove = "preserve";
471
+ }
472
+ return policy;
473
+ }
333
474
  function listMeshes() {
334
475
  return loadMeshConfig().meshes;
335
476
  }
@@ -353,7 +494,7 @@ function createMesh(opts) {
353
494
  repoIdentity,
354
495
  repoRemoteUrl: opts.repoRemoteUrl,
355
496
  defaultBranch: opts.defaultBranch,
356
- policy: { ...DEFAULT_MESH_POLICY, ...opts.policy },
497
+ policy: mergeMeshPolicy(void 0, opts.policy),
357
498
  coordinator: opts.coordinator || {},
358
499
  nodes: [],
359
500
  createdAt: now,
@@ -369,7 +510,7 @@ function updateMesh(meshId, opts) {
369
510
  if (!mesh) return void 0;
370
511
  if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
371
512
  if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
372
- if (opts.policy) mesh.policy = { ...mesh.policy, ...opts.policy };
513
+ if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
373
514
  if (opts.coordinator) mesh.coordinator = opts.coordinator;
374
515
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
375
516
  saveMeshConfig(config);
@@ -397,9 +538,12 @@ function addNode(meshId, opts) {
397
538
  id: `node_${randomUUID3().replace(/-/g, "")}`,
398
539
  workspace: opts.workspace.trim(),
399
540
  repoRoot: opts.repoRoot,
541
+ daemonId: opts.daemonId,
400
542
  userOverrides: opts.userOverrides || {},
401
543
  policy: opts.policy || {},
402
- isLocalWorktree: opts.isLocalWorktree
544
+ isLocalWorktree: opts.isLocalWorktree,
545
+ worktreeBranch: opts.worktreeBranch,
546
+ clonedFromNodeId: opts.clonedFromNodeId
403
547
  };
404
548
  mesh.nodes.push(node);
405
549
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -429,11 +573,13 @@ function updateNode(meshId, nodeId, opts) {
429
573
  saveMeshConfig(config);
430
574
  return node;
431
575
  }
576
+ var SESSION_CLEANUP_MODES;
432
577
  var init_mesh_config = __esm({
433
578
  "src/config/mesh-config.ts"() {
434
579
  "use strict";
435
580
  init_config();
436
581
  init_repo_mesh_types();
582
+ SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
437
583
  }
438
584
  });
439
585
 
@@ -443,7 +589,7 @@ __export(coordinator_prompt_exports, {
443
589
  buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
444
590
  });
445
591
  function buildCoordinatorSystemPrompt(ctx) {
446
- const { mesh, status, userInstruction } = ctx;
592
+ const { mesh, status, userInstruction, coordinatorCliType } = ctx;
447
593
  const sections = [];
448
594
  sections.push(`You are a **Repo Mesh Coordinator** \u2014 a technical team lead who orchestrates work across multiple agent sessions on a shared Git repository.
449
595
 
@@ -457,15 +603,15 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
457
603
  } else {
458
604
  sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
459
605
  }
460
- sections.push(buildPolicySection(mesh.policy));
606
+ sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
461
607
  sections.push(TOOLS_SECTION);
462
608
  sections.push(WORKFLOW_SECTION);
463
- sections.push(RULES_SECTION);
609
+ sections.push(buildRulesSection(coordinatorCliType));
464
610
  if (userInstruction) {
465
611
  sections.push(`## Additional Context
466
612
  ${userInstruction}`);
467
613
  }
468
- if (mesh.coordinator.systemPromptSuffix) {
614
+ if (mesh.coordinator?.systemPromptSuffix) {
469
615
  sections.push(mesh.coordinator.systemPromptSuffix);
470
616
  }
471
617
  return sections.join("\n\n");
@@ -510,10 +656,29 @@ function buildPolicySection(policy) {
510
656
  return `## Policy
511
657
  ${rules.join("\n")}`;
512
658
  }
513
- var TOOLS_SECTION, WORKFLOW_SECTION, RULES_SECTION;
659
+ function buildRulesSection(coordinatorCliType) {
660
+ const coordinatorNote = coordinatorCliType ? `
661
+ - **Coordinator runtime is not a delegation default.** This coordinator is running as \`${coordinatorCliType}\`, but delegated node sessions must follow the user's requested provider, not the coordinator's own runtime.` : "";
662
+ return `## Rules
663
+
664
+ - **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.
665
+ - **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.
666
+ - **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.
667
+ - **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.
668
+ - **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
669
+ - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
670
+ - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
671
+ - **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
672
+ - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
673
+ - **Never fabricate tool results.** Always call the actual tool; never pretend you did.
674
+ - **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
675
+ - **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
676
+ }
677
+ var TOOLS_SECTION, WORKFLOW_SECTION;
514
678
  var init_coordinator_prompt = __esm({
515
679
  "src/mesh/coordinator-prompt.ts"() {
516
680
  "use strict";
681
+ init_repo_mesh_types();
517
682
  TOOLS_SECTION = `## Available Tools
518
683
 
519
684
  | Tool | Purpose |
@@ -525,36 +690,29 @@ var init_coordinator_prompt = __esm({
525
690
  | \`mesh_read_chat\` | Read an agent's recent messages to check progress |
526
691
  | \`mesh_git_status\` | Check git status on a specific node |
527
692
  | \`mesh_checkpoint\` | Create a git checkpoint on a node |
528
- | \`mesh_approve\` | Approve/reject a pending agent action |`;
693
+ | \`mesh_approve\` | Approve/reject a pending agent action |
694
+ | \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
695
+ | \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |`;
529
696
  WORKFLOW_SECTION = `## Orchestration Workflow
530
697
 
531
698
  1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
532
699
  2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
533
700
  3. **Delegate** \u2014 For each task:
534
701
  a. Pick the best node (consider: health, dirty state, current workload).
535
- b. If no session exists, call \`mesh_launch_session\` to start one.
536
- c. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
702
+ b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
703
+ c. If no session exists, call \`mesh_launch_session\` to start one.
704
+ d. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
537
705
  4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
538
706
  5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
539
707
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
540
- 7. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
541
- RULES_SECTION = `## Rules
542
-
543
- - **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.
544
- - **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.
545
- - **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.
546
- - **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
547
- - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
548
- - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
549
- - **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
550
- - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
551
- - **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
708
+ 7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
709
+ 8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
552
710
  }
553
711
  });
554
712
 
555
713
  // src/logging/logger.ts
556
714
  import * as fs2 from "fs";
557
- import * as path9 from "path";
715
+ import * as path10 from "path";
558
716
  import * as os4 from "os";
559
717
  function setLogLevel(level) {
560
718
  currentLevel = level;
@@ -570,13 +728,13 @@ function getDaemonLogDir() {
570
728
  return LOG_DIR;
571
729
  }
572
730
  function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
573
- return path9.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
731
+ return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
574
732
  }
575
733
  function checkDateRotation() {
576
734
  const today = getDateStr();
577
735
  if (today !== currentDate) {
578
736
  currentDate = today;
579
- currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
737
+ currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
580
738
  cleanOldLogs();
581
739
  }
582
740
  }
@@ -590,7 +748,7 @@ function cleanOldLogs() {
590
748
  const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
591
749
  if (dateMatch && dateMatch[1] < cutoffStr) {
592
750
  try {
593
- fs2.unlinkSync(path9.join(LOG_DIR, file));
751
+ fs2.unlinkSync(path10.join(LOG_DIR, file));
594
752
  } catch {
595
753
  }
596
754
  }
@@ -713,7 +871,7 @@ var init_logger = __esm({
713
871
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
714
872
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
715
873
  currentLevel = "info";
716
- LOG_DIR = process.platform === "win32" ? path9.join(process.env.LOCALAPPDATA || process.env.APPDATA || path9.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path9.join(os4.homedir(), "Library", "Logs", "adhdev") : path9.join(os4.homedir(), ".local", "share", "adhdev", "logs");
874
+ LOG_DIR = process.platform === "win32" ? path10.join(process.env.LOCALAPPDATA || process.env.APPDATA || path10.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path10.join(os4.homedir(), "Library", "Logs", "adhdev") : path10.join(os4.homedir(), ".local", "share", "adhdev", "logs");
717
875
  MAX_LOG_SIZE = 5 * 1024 * 1024;
718
876
  MAX_LOG_DAYS = 7;
719
877
  try {
@@ -721,16 +879,16 @@ var init_logger = __esm({
721
879
  } catch {
722
880
  }
723
881
  currentDate = getDateStr();
724
- currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
882
+ currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
725
883
  cleanOldLogs();
726
884
  try {
727
- const oldLog = path9.join(LOG_DIR, "daemon.log");
885
+ const oldLog = path10.join(LOG_DIR, "daemon.log");
728
886
  if (fs2.existsSync(oldLog)) {
729
887
  const stat2 = fs2.statSync(oldLog);
730
888
  const oldDate = stat2.mtime.toISOString().slice(0, 10);
731
- fs2.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
889
+ fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
732
890
  }
733
- const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
891
+ const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
734
892
  if (fs2.existsSync(oldLogBackup)) {
735
893
  fs2.unlinkSync(oldLogBackup);
736
894
  }
@@ -762,7 +920,7 @@ var init_logger = __esm({
762
920
  }
763
921
  };
764
922
  interceptorInstalled = false;
765
- LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
923
+ LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
766
924
  }
767
925
  });
768
926
 
@@ -1171,7 +1329,7 @@ var init_pty_transport = __esm({
1171
1329
 
1172
1330
  // src/cli-adapters/provider-cli-shared.ts
1173
1331
  import * as os9 from "os";
1174
- import * as path13 from "path";
1332
+ import * as path14 from "path";
1175
1333
  import { execSync as execSync3 } from "child_process";
1176
1334
  function stripAnsi(str) {
1177
1335
  return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
@@ -1236,9 +1394,9 @@ function buildCliScreenSnapshot(text) {
1236
1394
  function findBinary(name) {
1237
1395
  const trimmed = String(name || "").trim();
1238
1396
  if (!trimmed) return trimmed;
1239
- const expanded = trimmed.startsWith("~") ? path13.join(os9.homedir(), trimmed.slice(1)) : trimmed;
1240
- if (path13.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
1241
- return path13.isAbsolute(expanded) ? expanded : path13.resolve(expanded);
1397
+ const expanded = trimmed.startsWith("~") ? path14.join(os9.homedir(), trimmed.slice(1)) : trimmed;
1398
+ if (path14.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
1399
+ return path14.isAbsolute(expanded) ? expanded : path14.resolve(expanded);
1242
1400
  }
1243
1401
  const isWin = os9.platform() === "win32";
1244
1402
  try {
@@ -1254,7 +1412,7 @@ function findBinary(name) {
1254
1412
  }
1255
1413
  }
1256
1414
  function isScriptBinary(binaryPath) {
1257
- if (!path13.isAbsolute(binaryPath)) return false;
1415
+ if (!path14.isAbsolute(binaryPath)) return false;
1258
1416
  try {
1259
1417
  const fs16 = __require("fs");
1260
1418
  const resolved = fs16.realpathSync(binaryPath);
@@ -1270,7 +1428,7 @@ function isScriptBinary(binaryPath) {
1270
1428
  }
1271
1429
  }
1272
1430
  function looksLikeMachOOrElf(filePath) {
1273
- if (!path13.isAbsolute(filePath)) return false;
1431
+ if (!path14.isAbsolute(filePath)) return false;
1274
1432
  try {
1275
1433
  const fs16 = __require("fs");
1276
1434
  const resolved = fs16.realpathSync(filePath);
@@ -1484,10 +1642,10 @@ var init_provider_cli_config = __esm({
1484
1642
 
1485
1643
  // src/cli-adapters/provider-cli-runtime.ts
1486
1644
  import * as os10 from "os";
1487
- import * as path14 from "path";
1645
+ import * as path15 from "path";
1488
1646
  import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from "@adhdev/session-host-core";
1489
1647
  function resolveCliSpawnPlan(options) {
1490
- const { provider, runtimeSettings, workingDir, extraArgs } = options;
1648
+ const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
1491
1649
  const { spawn: spawnConfig } = provider;
1492
1650
  const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
1493
1651
  const binaryPath = findBinary(configuredCommand);
@@ -1495,9 +1653,9 @@ function resolveCliSpawnPlan(options) {
1495
1653
  const allArgs = [...spawnConfig.args, ...extraArgs];
1496
1654
  let shellCmd;
1497
1655
  let shellArgs;
1498
- const useShellUnix = !isWin && (!!spawnConfig.shell || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1656
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1499
1657
  const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1500
- const useShellWin = !!spawnConfig.shell || isCmdShim || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1658
+ const useShellWin = !!spawnConfig.shell || isCmdShim || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1501
1659
  const useShell = isWin ? useShellWin : useShellUnix;
1502
1660
  if (useShell) {
1503
1661
  shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
@@ -1511,7 +1669,7 @@ function resolveCliSpawnPlan(options) {
1511
1669
  shellCmd = binaryPath;
1512
1670
  shellArgs = allArgs;
1513
1671
  }
1514
- const env = buildCliSpawnEnv(process.env, spawnConfig.env);
1672
+ const env = buildCliSpawnEnv(process.env, { ...spawnConfig.env || {}, ...extraEnv || {} });
1515
1673
  env.TERMINAL_CWD = workingDir;
1516
1674
  return {
1517
1675
  binaryPath,
@@ -1610,8 +1768,9 @@ var init_provider_cli_adapter = __esm({
1610
1768
  init_provider_cli_runtime();
1611
1769
  init_provider_cli_shared();
1612
1770
  ProviderCliAdapter = class _ProviderCliAdapter {
1613
- constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
1771
+ constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
1614
1772
  this.extraArgs = extraArgs;
1773
+ this.extraEnv = extraEnv;
1615
1774
  this.provider = provider;
1616
1775
  this.transportFactory = transportFactory;
1617
1776
  this.cliType = provider.type;
@@ -1762,8 +1921,9 @@ var init_provider_cli_adapter = __esm({
1762
1921
  const currentSnapshot = normalizeScreenSnapshot(screenText);
1763
1922
  const lastSnapshot = this.lastScreenSnapshot;
1764
1923
  if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
1765
- const staleSnapshotLooksActive = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel/i.test(lastSnapshot);
1766
- const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:\n|\r|$)/.test(screenText) && !/\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel/i.test(screenText);
1924
+ const activeScreenPattern = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel|Enter to confirm\s*[·•-]\s*Esc to cancel|\b(?:MCP servers?|tool calls?)\b[^\n\r]{0,160}\brequire approval\b/i;
1925
+ const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
1926
+ const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
1767
1927
  if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
1768
1928
  if (currentSnapshot.length >= lastSnapshot.length) return screenText;
1769
1929
  return `${screenText}
@@ -1926,7 +2086,8 @@ ${lastSnapshot}`;
1926
2086
  provider: this.provider,
1927
2087
  runtimeSettings: this.runtimeSettings,
1928
2088
  workingDir: this.workingDir,
1929
- extraArgs: this.extraArgs
2089
+ extraArgs: this.extraArgs,
2090
+ extraEnv: this.extraEnv
1930
2091
  });
1931
2092
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
1932
2093
  this.resetTraceSession();
@@ -3124,9 +3285,8 @@ ${lastSnapshot}`;
3124
3285
  };
3125
3286
  this.recordTrace("submit_echo_missing", diagnostic);
3126
3287
  if (this.requirePromptEchoBeforeSubmit) {
3127
- const message = `${this.cliName} prompt echo was not observed on the PTY screen before submit`;
3128
- LOG.warn("CLI", `[${this.cliType}] ${message} elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
3129
- completion.rejectOnce(new Error(message));
3288
+ LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending guarded submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
3289
+ this.submitSendKey(state, completion);
3130
3290
  return;
3131
3291
  }
3132
3292
  LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
@@ -3173,7 +3333,14 @@ ${lastSnapshot}`;
3173
3333
  })() : null;
3174
3334
  const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
3175
3335
  if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
3176
- throw new Error(`${this.cliName} is still processing the previous prompt`);
3336
+ const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
3337
+ const parsedHasActionableModal = Boolean(
3338
+ parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
3339
+ );
3340
+ const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
3341
+ if (!terminalLooksIdle) {
3342
+ throw new Error(`${this.cliName} is still processing the previous prompt`);
3343
+ }
3177
3344
  }
3178
3345
  if (this.isWaitingForResponse && !allowInputDuringGeneration) {
3179
3346
  if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
@@ -4547,6 +4714,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
4547
4714
  "dirty_index_required",
4548
4715
  "conflict",
4549
4716
  "invalid_args",
4717
+ "nothing_to_commit",
4550
4718
  "git_command_failed"
4551
4719
  ]);
4552
4720
  function failure(reason, error) {
@@ -4791,7 +4959,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
4791
4959
  } catch (err) {
4792
4960
  const output = (err?.stdout || "") + (err?.stderr || "");
4793
4961
  if (/nothing to commit/i.test(output)) {
4794
- throw new GitCommandError("git_command_failed", "Nothing to commit");
4962
+ throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
4963
+ stdout: err?.stdout,
4964
+ stderr: err?.stderr
4965
+ });
4795
4966
  }
4796
4967
  throw err;
4797
4968
  }
@@ -4983,20 +5154,23 @@ var TurnSnapshotTracker = class {
4983
5154
  }
4984
5155
  };
4985
5156
 
5157
+ // src/git/index.ts
5158
+ init_git_worktree();
5159
+
4986
5160
  // src/index.ts
4987
5161
  init_config();
4988
5162
 
4989
5163
  // src/config/workspaces.ts
4990
5164
  import * as fs from "fs";
4991
5165
  import * as os from "os";
4992
- import * as path4 from "path";
5166
+ import * as path5 from "path";
4993
5167
  import { randomUUID as randomUUID2 } from "crypto";
4994
5168
  var MAX_WORKSPACES = 50;
4995
5169
  function expandPath(p) {
4996
5170
  const t = (p || "").trim();
4997
5171
  if (!t) return "";
4998
- if (t.startsWith("~")) return path4.join(os.homedir(), t.slice(1).replace(/^\//, ""));
4999
- return path4.resolve(t);
5172
+ if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
5173
+ return path5.resolve(t);
5000
5174
  }
5001
5175
  function validateWorkspacePath(absPath) {
5002
5176
  try {
@@ -5010,7 +5184,7 @@ function validateWorkspacePath(absPath) {
5010
5184
  }
5011
5185
  }
5012
5186
  function defaultWorkspaceLabel(absPath) {
5013
- const base = path4.basename(absPath) || absPath;
5187
+ const base = path5.basename(absPath) || absPath;
5014
5188
  return base;
5015
5189
  }
5016
5190
  function getDefaultWorkspacePath(config) {
@@ -5101,9 +5275,9 @@ function resolveIdeLaunchWorkspace(args, config) {
5101
5275
  return getDefaultWorkspacePath(config) || void 0;
5102
5276
  }
5103
5277
  function findWorkspaceByPath(config, rawPath) {
5104
- const abs = path4.resolve(expandPath(rawPath));
5278
+ const abs = path5.resolve(expandPath(rawPath));
5105
5279
  if (!abs) return void 0;
5106
- return (config.workspaces || []).find((w) => path4.resolve(expandPath(w.path)) === abs);
5280
+ return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
5107
5281
  }
5108
5282
  function addWorkspaceEntry(config, rawPath, label, options) {
5109
5283
  const abs = expandPath(rawPath);
@@ -5119,7 +5293,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
5119
5293
  const v = validateWorkspacePath(abs);
5120
5294
  if (!v.ok) return { error: v.error };
5121
5295
  const list = [...config.workspaces || []];
5122
- if (list.some((w) => path4.resolve(w.path) === abs)) {
5296
+ if (list.some((w) => path5.resolve(w.path) === abs)) {
5123
5297
  return { error: "Workspace already in list" };
5124
5298
  }
5125
5299
  if (list.length >= MAX_WORKSPACES) {
@@ -5153,7 +5327,7 @@ function setDefaultWorkspaceId(config, id) {
5153
5327
  }
5154
5328
 
5155
5329
  // src/config/recent-activity.ts
5156
- import * as path5 from "path";
5330
+ import * as path6 from "path";
5157
5331
 
5158
5332
  // src/providers/summary-metadata.ts
5159
5333
  function normalizeSummaryItem(item) {
@@ -5222,9 +5396,9 @@ var MAX_ACTIVITY = 30;
5222
5396
  function normalizeWorkspace(workspace) {
5223
5397
  if (!workspace) return "";
5224
5398
  try {
5225
- return path5.resolve(expandPath(workspace));
5399
+ return path6.resolve(expandPath(workspace));
5226
5400
  } catch {
5227
- return path5.resolve(workspace);
5401
+ return path6.resolve(workspace);
5228
5402
  }
5229
5403
  }
5230
5404
  function buildRecentActivityKey(entry) {
@@ -5392,14 +5566,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
5392
5566
  }
5393
5567
 
5394
5568
  // src/config/saved-sessions.ts
5395
- import * as path6 from "path";
5569
+ import * as path7 from "path";
5396
5570
  var MAX_SAVED_SESSIONS = 500;
5397
5571
  function normalizeWorkspace2(workspace) {
5398
5572
  if (!workspace) return "";
5399
5573
  try {
5400
- return path6.resolve(expandPath(workspace));
5574
+ return path7.resolve(expandPath(workspace));
5401
5575
  } catch {
5402
- return path6.resolve(workspace);
5576
+ return path7.resolve(workspace);
5403
5577
  }
5404
5578
  }
5405
5579
  function buildSavedProviderSessionKey(providerSessionId) {
@@ -5505,8 +5679,8 @@ async function syncMeshes(transport) {
5505
5679
 
5506
5680
  // src/config/state-store.ts
5507
5681
  init_config();
5508
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5509
- import { join as join4 } from "path";
5682
+ import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5683
+ import { join as join5 } from "path";
5510
5684
  var DEFAULT_STATE = {
5511
5685
  recentActivity: [],
5512
5686
  savedProviderSessions: [],
@@ -5519,7 +5693,7 @@ function isPlainObject2(value) {
5519
5693
  return !!value && typeof value === "object" && !Array.isArray(value);
5520
5694
  }
5521
5695
  function getStatePath() {
5522
- return join4(getConfigDir(), "state.json");
5696
+ return join5(getConfigDir(), "state.json");
5523
5697
  }
5524
5698
  function normalizeState(raw) {
5525
5699
  const parsed = isPlainObject2(raw) ? raw : {};
@@ -5555,7 +5729,7 @@ function normalizeState(raw) {
5555
5729
  }
5556
5730
  function loadState() {
5557
5731
  const statePath = getStatePath();
5558
- if (!existsSync4(statePath)) {
5732
+ if (!existsSync5(statePath)) {
5559
5733
  return { ...DEFAULT_STATE };
5560
5734
  }
5561
5735
  try {
@@ -5576,9 +5750,9 @@ function resetState() {
5576
5750
 
5577
5751
  // src/detection/ide-detector.ts
5578
5752
  import { execSync } from "child_process";
5579
- import { existsSync as existsSync5 } from "fs";
5753
+ import { existsSync as existsSync6 } from "fs";
5580
5754
  import { platform, homedir as homedir3 } from "os";
5581
- import * as path7 from "path";
5755
+ import * as path8 from "path";
5582
5756
  var BUILTIN_IDE_DEFINITIONS = [];
5583
5757
  var registeredIDEs = /* @__PURE__ */ new Map();
5584
5758
  function registerIDEDefinition(def) {
@@ -5597,10 +5771,10 @@ function getMergedDefinitions() {
5597
5771
  function findCliCommand(command) {
5598
5772
  const trimmed = String(command || "").trim();
5599
5773
  if (!trimmed) return null;
5600
- if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5601
- const candidate = trimmed.startsWith("~") ? path7.join(homedir3(), trimmed.slice(1)) : trimmed;
5602
- const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
5603
- return existsSync5(resolved) ? resolved : null;
5774
+ if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5775
+ const candidate = trimmed.startsWith("~") ? path8.join(homedir3(), trimmed.slice(1)) : trimmed;
5776
+ const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
5777
+ return existsSync6(resolved) ? resolved : null;
5604
5778
  }
5605
5779
  try {
5606
5780
  const result = execSync(
@@ -5627,31 +5801,31 @@ function getIdeVersion(cliCommand) {
5627
5801
  function checkPathExists(paths) {
5628
5802
  const home = homedir3();
5629
5803
  for (const p of paths) {
5630
- const normalized = p.startsWith("~") ? path7.join(home, p.slice(1)) : p;
5804
+ const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
5631
5805
  if (normalized.includes("*")) {
5632
5806
  const username = home.split(/[\\/]/).pop() || "";
5633
5807
  const resolved = normalized.replace("*", username);
5634
- if (existsSync5(resolved)) return resolved;
5808
+ if (existsSync6(resolved)) return resolved;
5635
5809
  } else {
5636
- if (existsSync5(normalized)) return normalized;
5810
+ if (existsSync6(normalized)) return normalized;
5637
5811
  }
5638
5812
  }
5639
5813
  return null;
5640
5814
  }
5641
5815
  async function detectIDEs(providerLoader) {
5642
- const os21 = platform();
5816
+ const os22 = platform();
5643
5817
  const results = [];
5644
5818
  for (const def of getMergedDefinitions()) {
5645
5819
  const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
5646
- const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os21] || []) || []);
5820
+ const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
5647
5821
  let resolvedCli = cliPath;
5648
- if (!resolvedCli && appPath && os21 === "darwin") {
5822
+ if (!resolvedCli && appPath && os22 === "darwin") {
5649
5823
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
5650
- if (existsSync5(bundledCli)) resolvedCli = bundledCli;
5824
+ if (existsSync6(bundledCli)) resolvedCli = bundledCli;
5651
5825
  }
5652
- if (!resolvedCli && appPath && os21 === "win32") {
5653
- const { dirname: dirname8 } = await import("path");
5654
- const appDir = dirname8(appPath);
5826
+ if (!resolvedCli && appPath && os22 === "win32") {
5827
+ const { dirname: dirname9 } = await import("path");
5828
+ const appDir = dirname9(appPath);
5655
5829
  const candidates = [
5656
5830
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
5657
5831
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -5660,13 +5834,13 @@ async function detectIDEs(providerLoader) {
5660
5834
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
5661
5835
  ];
5662
5836
  for (const c of candidates) {
5663
- if (existsSync5(c)) {
5837
+ if (existsSync6(c)) {
5664
5838
  resolvedCli = c;
5665
5839
  break;
5666
5840
  }
5667
5841
  }
5668
5842
  }
5669
- const installed = os21 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
5843
+ const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
5670
5844
  const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
5671
5845
  results.push({
5672
5846
  id: def.id,
@@ -5685,8 +5859,8 @@ async function detectIDEs(providerLoader) {
5685
5859
  // src/detection/cli-detector.ts
5686
5860
  import { exec } from "child_process";
5687
5861
  import * as os2 from "os";
5688
- import * as path8 from "path";
5689
- import { existsSync as existsSync6 } from "fs";
5862
+ import * as path9 from "path";
5863
+ import { existsSync as existsSync7 } from "fs";
5690
5864
  function parseVersion(raw) {
5691
5865
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
5692
5866
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
@@ -5698,19 +5872,19 @@ function shellQuote(value) {
5698
5872
  function expandHome(value) {
5699
5873
  const trimmed = value.trim();
5700
5874
  if (!trimmed.startsWith("~")) return trimmed;
5701
- return path8.join(os2.homedir(), trimmed.slice(1));
5875
+ return path9.join(os2.homedir(), trimmed.slice(1));
5702
5876
  }
5703
5877
  function isExplicitCommandPath(command) {
5704
5878
  const trimmed = command.trim();
5705
- return path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
5879
+ return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
5706
5880
  }
5707
5881
  function resolveCommandPath(command) {
5708
5882
  const trimmed = command.trim();
5709
5883
  if (!trimmed) return null;
5710
5884
  if (isExplicitCommandPath(trimmed)) {
5711
5885
  const expanded = expandHome(trimmed);
5712
- const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
5713
- return existsSync6(candidate) ? candidate : null;
5886
+ const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
5887
+ return existsSync7(candidate) ? candidate : null;
5714
5888
  }
5715
5889
  return null;
5716
5890
  }
@@ -7978,9 +8152,9 @@ ${cleanBody}`;
7978
8152
 
7979
8153
  // src/config/chat-history.ts
7980
8154
  import * as fs3 from "fs";
7981
- import * as path10 from "path";
8155
+ import * as path11 from "path";
7982
8156
  import * as os5 from "os";
7983
- var HISTORY_DIR = path10.join(os5.homedir(), ".adhdev", "history");
8157
+ var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
7984
8158
  var RETAIN_DAYS = 30;
7985
8159
  var SAVED_HISTORY_INDEX_VERSION = 1;
7986
8160
  var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
@@ -8143,7 +8317,7 @@ function extractSavedHistorySessionIdFromFile(file) {
8143
8317
  function buildSavedHistoryFileSignatureMap(dir, files) {
8144
8318
  return new Map(files.map((file) => {
8145
8319
  try {
8146
- const stat2 = fs3.statSync(path10.join(dir, file));
8320
+ const stat2 = fs3.statSync(path11.join(dir, file));
8147
8321
  return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
8148
8322
  } catch {
8149
8323
  return [file, `${file}:missing`];
@@ -8154,7 +8328,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
8154
8328
  return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
8155
8329
  }
8156
8330
  function getSavedHistoryIndexFilePath(dir) {
8157
- return path10.join(dir, SAVED_HISTORY_INDEX_FILE);
8331
+ return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
8158
8332
  }
8159
8333
  function getSavedHistoryIndexLockPath(dir) {
8160
8334
  return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
@@ -8256,7 +8430,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
8256
8430
  }
8257
8431
  for (const file of Array.from(currentEntries.keys())) {
8258
8432
  if (incomingFiles.has(file)) continue;
8259
- if (!fs3.existsSync(path10.join(dir, file))) {
8433
+ if (!fs3.existsSync(path11.join(dir, file))) {
8260
8434
  currentEntries.delete(file);
8261
8435
  }
8262
8436
  }
@@ -8282,7 +8456,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
8282
8456
  const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
8283
8457
  const files = listHistoryFiles(dir);
8284
8458
  for (const file of files) {
8285
- const stat2 = fs3.statSync(path10.join(dir, file));
8459
+ const stat2 = fs3.statSync(path11.join(dir, file));
8286
8460
  if (stat2.mtimeMs > indexStat.mtimeMs) return true;
8287
8461
  }
8288
8462
  return false;
@@ -8292,14 +8466,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
8292
8466
  }
8293
8467
  function buildSavedHistoryFileSignature(dir, file) {
8294
8468
  try {
8295
- const stat2 = fs3.statSync(path10.join(dir, file));
8469
+ const stat2 = fs3.statSync(path11.join(dir, file));
8296
8470
  return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
8297
8471
  } catch {
8298
8472
  return `${file}:missing`;
8299
8473
  }
8300
8474
  }
8301
8475
  function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
8302
- const filePath = path10.join(dir, file);
8476
+ const filePath = path11.join(dir, file);
8303
8477
  const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
8304
8478
  const currentEntry = entries.get(file) || null;
8305
8479
  const nextSummary = updater(currentEntry?.summary || null);
@@ -8372,7 +8546,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
8372
8546
  function computeSavedHistoryFileSummary(dir, file) {
8373
8547
  const historySessionId = extractSavedHistorySessionIdFromFile(file);
8374
8548
  if (!historySessionId) return null;
8375
- const filePath = path10.join(dir, file);
8549
+ const filePath = path11.join(dir, file);
8376
8550
  const content = fs3.readFileSync(filePath, "utf-8");
8377
8551
  const lines = content.split("\n").filter(Boolean);
8378
8552
  let messageCount = 0;
@@ -8459,7 +8633,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
8459
8633
  const summaryBySessionId = /* @__PURE__ */ new Map();
8460
8634
  const nextPersistedEntries = /* @__PURE__ */ new Map();
8461
8635
  for (const file of files.slice().sort()) {
8462
- const filePath = path10.join(dir, file);
8636
+ const filePath = path11.join(dir, file);
8463
8637
  const signature = fileSignatures.get(file) || `${file}:missing`;
8464
8638
  const cached = savedHistoryFileSummaryCache.get(filePath);
8465
8639
  const persisted = persistedEntries.get(file);
@@ -8579,12 +8753,12 @@ var ChatHistoryWriter = class {
8579
8753
  });
8580
8754
  }
8581
8755
  if (newMessages.length === 0) return;
8582
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8756
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8583
8757
  fs3.mkdirSync(dir, { recursive: true });
8584
8758
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8585
8759
  const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
8586
8760
  const fileName = `${filePrefix}${date}.jsonl`;
8587
- const filePath = path10.join(dir, fileName);
8761
+ const filePath = path11.join(dir, fileName);
8588
8762
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
8589
8763
  fs3.appendFileSync(filePath, lines, "utf-8");
8590
8764
  updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
@@ -8675,11 +8849,11 @@ var ChatHistoryWriter = class {
8675
8849
  const ws = String(workspace || "").trim();
8676
8850
  if (!id || !ws) return;
8677
8851
  try {
8678
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8852
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8679
8853
  fs3.mkdirSync(dir, { recursive: true });
8680
8854
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8681
8855
  const fileName = `${this.sanitize(id)}_${date}.jsonl`;
8682
- const filePath = path10.join(dir, fileName);
8856
+ const filePath = path11.join(dir, fileName);
8683
8857
  const record = {
8684
8858
  ts: (/* @__PURE__ */ new Date()).toISOString(),
8685
8859
  receivedAt: Date.now(),
@@ -8725,14 +8899,14 @@ var ChatHistoryWriter = class {
8725
8899
  this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
8726
8900
  this.lastSeenCounts.delete(fromDedupKey);
8727
8901
  }
8728
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8902
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8729
8903
  if (!fs3.existsSync(dir)) return;
8730
8904
  const fromPrefix = `${this.sanitize(fromId)}_`;
8731
8905
  const toPrefix = `${this.sanitize(toId)}_`;
8732
8906
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
8733
8907
  for (const file of files) {
8734
- const sourcePath = path10.join(dir, file);
8735
- const targetPath = path10.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
8908
+ const sourcePath = path11.join(dir, file);
8909
+ const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
8736
8910
  const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
8737
8911
  const rewritten = sourceLines.map((line) => {
8738
8912
  try {
@@ -8766,13 +8940,13 @@ var ChatHistoryWriter = class {
8766
8940
  const sessionId = String(historySessionId || "").trim();
8767
8941
  if (!sessionId) return;
8768
8942
  try {
8769
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8943
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8770
8944
  if (!fs3.existsSync(dir)) return;
8771
8945
  const prefix = `${this.sanitize(sessionId)}_`;
8772
8946
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
8773
8947
  const seen = /* @__PURE__ */ new Set();
8774
8948
  for (const file of files) {
8775
- const filePath = path10.join(dir, file);
8949
+ const filePath = path11.join(dir, file);
8776
8950
  const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8777
8951
  const next = [];
8778
8952
  for (const line of lines) {
@@ -8826,11 +9000,11 @@ var ChatHistoryWriter = class {
8826
9000
  const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
8827
9001
  const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
8828
9002
  for (const dir of agentDirs) {
8829
- const dirPath = path10.join(HISTORY_DIR, dir.name);
9003
+ const dirPath = path11.join(HISTORY_DIR, dir.name);
8830
9004
  const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
8831
9005
  let removedAny = false;
8832
9006
  for (const file of files) {
8833
- const filePath = path10.join(dirPath, file);
9007
+ const filePath = path11.join(dirPath, file);
8834
9008
  const stat2 = fs3.statSync(filePath);
8835
9009
  if (stat2.mtimeMs < cutoff) {
8836
9010
  fs3.unlinkSync(filePath);
@@ -8880,13 +9054,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
8880
9054
  function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
8881
9055
  try {
8882
9056
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
8883
- const dir = path10.join(HISTORY_DIR, sanitized);
9057
+ const dir = path11.join(HISTORY_DIR, sanitized);
8884
9058
  if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
8885
9059
  const files = listHistoryFiles(dir, historySessionId);
8886
9060
  const allMessages = [];
8887
9061
  const seen = /* @__PURE__ */ new Set();
8888
9062
  for (const file of files) {
8889
- const filePath = path10.join(dir, file);
9063
+ const filePath = path11.join(dir, file);
8890
9064
  const content = fs3.readFileSync(filePath, "utf-8");
8891
9065
  const lines = content.trim().split("\n").filter(Boolean);
8892
9066
  for (let i = 0; i < lines.length; i++) {
@@ -8910,7 +9084,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
8910
9084
  function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
8911
9085
  try {
8912
9086
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
8913
- const dir = path10.join(HISTORY_DIR, sanitized);
9087
+ const dir = path11.join(HISTORY_DIR, sanitized);
8914
9088
  if (!fs3.existsSync(dir)) {
8915
9089
  savedHistorySessionCache.delete(sanitized);
8916
9090
  return { sessions: [], hasMore: false };
@@ -8971,11 +9145,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
8971
9145
  }
8972
9146
  function readExistingSessionStartRecord(agentType, historySessionId) {
8973
9147
  try {
8974
- const dir = path10.join(HISTORY_DIR, agentType);
9148
+ const dir = path11.join(HISTORY_DIR, agentType);
8975
9149
  if (!fs3.existsSync(dir)) return null;
8976
9150
  const files = listHistoryFiles(dir, historySessionId).sort();
8977
9151
  for (const file of files) {
8978
- const lines = fs3.readFileSync(path10.join(dir, file), "utf-8").split("\n").filter(Boolean);
9152
+ const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
8979
9153
  for (const line of lines) {
8980
9154
  try {
8981
9155
  const parsed = JSON.parse(line);
@@ -8995,16 +9169,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
8995
9169
  function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
8996
9170
  if (records.length === 0) return false;
8997
9171
  try {
8998
- const dir = path10.join(HISTORY_DIR, agentType);
9172
+ const dir = path11.join(HISTORY_DIR, agentType);
8999
9173
  fs3.mkdirSync(dir, { recursive: true });
9000
9174
  const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
9001
9175
  for (const file of fs3.readdirSync(dir)) {
9002
9176
  if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
9003
- fs3.unlinkSync(path10.join(dir, file));
9177
+ fs3.unlinkSync(path11.join(dir, file));
9004
9178
  }
9005
9179
  }
9006
9180
  const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
9007
- const filePath = path10.join(dir, `${prefix}${targetDate}.jsonl`);
9181
+ const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
9008
9182
  fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
9009
9183
  `, "utf-8");
9010
9184
  invalidatePersistedSavedHistoryIndex(agentType, dir);
@@ -10999,6 +11173,14 @@ function getActiveChatOptions(profile) {
10999
11173
  if (profile === "full") return {};
11000
11174
  return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
11001
11175
  }
11176
+ function resolveSessionStatus(activeChat, providerStatus) {
11177
+ const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
11178
+ const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
11179
+ if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
11180
+ if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
11181
+ if (topLevelStatus !== "idle") return topLevelStatus;
11182
+ return chatStatus;
11183
+ }
11002
11184
  function shouldIncludeSessionControls(profile) {
11003
11185
  return profile !== "live";
11004
11186
  }
@@ -11077,9 +11259,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
11077
11259
  providerName: state.name,
11078
11260
  kind: "workspace",
11079
11261
  transport: "cdp-page",
11080
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11081
- activeModal: activeChat?.activeModal || null
11082
- }),
11262
+ status: resolveSessionStatus(activeChat, state.status),
11083
11263
  title,
11084
11264
  workspace,
11085
11265
  ...git && { git },
@@ -11114,9 +11294,7 @@ function buildExtensionAgentSession(parent, ext, options) {
11114
11294
  providerSessionId: ext.providerSessionId,
11115
11295
  kind: "agent",
11116
11296
  transport: "cdp-webview",
11117
- status: normalizeManagedStatus(activeChat?.status || ext.status, {
11118
- activeModal: activeChat?.activeModal || null
11119
- }),
11297
+ status: resolveSessionStatus(activeChat, ext.status),
11120
11298
  title: activeChat?.title || ext.name,
11121
11299
  workspace,
11122
11300
  ...git && { git },
@@ -11166,9 +11344,7 @@ function buildCliSession(state, options) {
11166
11344
  providerSessionId: state.providerSessionId,
11167
11345
  kind: "agent",
11168
11346
  transport: "pty",
11169
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11170
- activeModal: activeChat?.activeModal || null
11171
- }),
11347
+ status: resolveSessionStatus(activeChat, state.status),
11172
11348
  title: activeChat?.title || state.name,
11173
11349
  workspace,
11174
11350
  ...git && { git },
@@ -11216,9 +11392,7 @@ function buildAcpSession(state, options) {
11216
11392
  providerName: state.name,
11217
11393
  kind: "agent",
11218
11394
  transport: "acp",
11219
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11220
- activeModal: activeChat?.activeModal || null
11221
- }),
11395
+ status: resolveSessionStatus(activeChat, state.status),
11222
11396
  title: activeChat?.title || state.name,
11223
11397
  workspace,
11224
11398
  ...git && { git },
@@ -11341,7 +11515,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
11341
11515
  // src/commands/chat-commands.ts
11342
11516
  import * as fs4 from "fs";
11343
11517
  import * as os6 from "os";
11344
- import * as path11 from "path";
11518
+ import * as path12 from "path";
11345
11519
  import { randomUUID as randomUUID5 } from "crypto";
11346
11520
 
11347
11521
  // src/providers/provider-input-support.ts
@@ -11544,6 +11718,7 @@ function buildSessionModalDeliverySignature(payload) {
11544
11718
  // src/commands/chat-commands.ts
11545
11719
  var RECENT_SEND_WINDOW_MS = 1200;
11546
11720
  var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
11721
+ var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
11547
11722
  var recentSendByTarget = /* @__PURE__ */ new Map();
11548
11723
  function getCurrentProviderType(h, fallback = "") {
11549
11724
  return h.currentSession?.providerType || h.currentProviderType || fallback;
@@ -11596,6 +11771,16 @@ function buildSendInputSignature(input) {
11596
11771
  function getSendChatInputEnvelope(args) {
11597
11772
  return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
11598
11773
  }
11774
+ function sleep(ms) {
11775
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
11776
+ }
11777
+ async function waitOnceForFreshHermesCliStart(adapter, log) {
11778
+ if (adapter.cliType !== "hermes-cli") return;
11779
+ const status = typeof adapter.getStatus === "function" ? adapter.getStatus()?.status : void 0;
11780
+ if (status !== "starting") return;
11781
+ log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
11782
+ await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
11783
+ }
11599
11784
  function getHistorySessionId(h, args) {
11600
11785
  const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
11601
11786
  if (explicit) return explicit;
@@ -11704,6 +11889,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
11704
11889
  return raw;
11705
11890
  }
11706
11891
  }
11892
+ function isGeneratingLikeStatus(status) {
11893
+ return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
11894
+ }
11895
+ function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
11896
+ if (!isGeneratingLikeStatus(parsedStatus)) return false;
11897
+ if (hasNonEmptyModalButtons(activeModal)) return false;
11898
+ const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
11899
+ if (adapterRawStatus !== "idle") return false;
11900
+ if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
11901
+ return true;
11902
+ }
11903
+ function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
11904
+ if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
11905
+ return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
11906
+ }
11907
+ function finalizeStreamingMessagesWhenIdle(messages, status) {
11908
+ if (status !== "idle") return messages;
11909
+ return messages.map((message) => {
11910
+ const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
11911
+ const hasStreamingMeta = meta?.streaming === true;
11912
+ if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
11913
+ return {
11914
+ ...message,
11915
+ ...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
11916
+ ...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
11917
+ };
11918
+ });
11919
+ }
11707
11920
  function buildReadChatCommandResult(payload, args) {
11708
11921
  let validatedPayload;
11709
11922
  const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
@@ -11852,7 +12065,7 @@ function buildDebugBundleText(bundle) {
11852
12065
  }
11853
12066
  function getChatDebugBundleDir() {
11854
12067
  const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
11855
- return override || path11.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
12068
+ return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
11856
12069
  }
11857
12070
  function safeBundleIdSegment(value, fallback) {
11858
12071
  const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
@@ -11868,6 +12081,14 @@ function buildChatDebugBundleSummary(bundle) {
11868
12081
  const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
11869
12082
  const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
11870
12083
  const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
12084
+ const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
12085
+ const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
12086
+ const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
12087
+ const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
12088
+ const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
12089
+ const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
12090
+ const cliStatus = typeof cli?.status === "string" ? cli.status : "";
12091
+ const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
11871
12092
  return {
11872
12093
  createdAt: bundle.createdAt,
11873
12094
  targetSessionId: target.targetSessionId,
@@ -11876,8 +12097,22 @@ function buildChatDebugBundleSummary(bundle) {
11876
12097
  readChatSuccess: readChat.success,
11877
12098
  readChatStatus: readChat.status,
11878
12099
  readChatTotalMessages: readChat.totalMessages,
12100
+ readChatReturnedMessages,
11879
12101
  cliStatus: cli?.status,
12102
+ cliParsedStatus: cliParsedStatus || void 0,
11880
12103
  cliMessageCount: cli?.messageCount,
12104
+ cliParsedMessageCount,
12105
+ cliPartialResponseChars: cliPartialResponse.length,
12106
+ parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
12107
+ parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
12108
+ readChatDebug: Object.keys(debugReadChat).length ? {
12109
+ adapterStatus: debugReadChat.adapterStatus,
12110
+ parsedStatus: debugReadChat.parsedStatus,
12111
+ returnedStatus: debugReadChat.returnedStatus,
12112
+ parsedMsgCount: debugReadChat.parsedMsgCount,
12113
+ returnedMsgCount: debugReadChat.returnedMsgCount,
12114
+ shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
12115
+ } : void 0,
11881
12116
  hasFrontendSnapshot: !!frontend
11882
12117
  };
11883
12118
  }
@@ -11885,7 +12120,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
11885
12120
  const bundleId = createChatDebugBundleId(targetSessionId);
11886
12121
  const dir = getChatDebugBundleDir();
11887
12122
  fs4.mkdirSync(dir, { recursive: true });
11888
- const savedPath = path11.join(dir, `${bundleId}.json`);
12123
+ const savedPath = path12.join(dir, `${bundleId}.json`);
11889
12124
  const json = `${JSON.stringify(bundle, null, 2)}
11890
12125
  `;
11891
12126
  fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
@@ -12115,7 +12350,7 @@ async function handleChatHistory(h, args) {
12115
12350
  }
12116
12351
  }
12117
12352
  async function handleReadChat(h, args) {
12118
- const provider = h.getProvider(args?.agentType);
12353
+ const provider = h.getProvider(args?.agentType || args?.providerType);
12119
12354
  const transport = getTargetTransport(h, provider);
12120
12355
  const historySessionId = getHistorySessionId(h, args);
12121
12356
  const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
@@ -12142,10 +12377,13 @@ async function handleReadChat(h, args) {
12142
12377
  const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
12143
12378
  const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
12144
12379
  const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
12145
- const returnedStatus = parsedRecord.status || "idle";
12146
- LOG.debug("Command", `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord.status || "")} parsedMsgCount=${parsedRecord.messages.length}`);
12380
+ const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
12381
+ const runtimeMessageMerger = getTargetInstance(h, args);
12382
+ const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
12383
+ const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
12384
+ LOG.debug("Command", `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord.status || "")} parsedMsgCount=${parsedRecord.messages.length} returnedMsgCount=${returnedMessages.length}`);
12147
12385
  return buildReadChatCommandResult({
12148
- messages: parsedRecord.messages,
12386
+ messages: returnedMessages,
12149
12387
  status: returnedStatus,
12150
12388
  activeModal,
12151
12389
  debugReadChat: {
@@ -12156,7 +12394,7 @@ async function handleReadChat(h, args) {
12156
12394
  returnedStatus: String(returnedStatus || ""),
12157
12395
  shouldPreferAdapterMessages: false,
12158
12396
  parsedMsgCount: parsedRecord.messages.length,
12159
- returnedMsgCount: parsedRecord.messages.length
12397
+ returnedMsgCount: returnedMessages.length
12160
12398
  },
12161
12399
  ...title ? { title } : {},
12162
12400
  ...providerSessionId ? { providerSessionId } : {},
@@ -12402,6 +12640,7 @@ async function handleSendChat(h, args) {
12402
12640
  try {
12403
12641
  assertTextOnlyInput(provider, input);
12404
12642
  if (!text) return { success: false, error: "text required for PTY send" };
12643
+ await waitOnceForFreshHermesCliStart(adapter, _log);
12405
12644
  await adapter.sendMessage(text);
12406
12645
  return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
12407
12646
  } catch (e) {
@@ -12901,9 +13140,17 @@ async function handleResolveAction(h, args) {
12901
13140
  const targetState = targetInstance?.getState?.();
12902
13141
  const surfacedModal = targetState?.activeChat?.activeModal && Array.isArray(targetState.activeChat.activeModal.buttons) && targetState.activeChat.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? targetState.activeChat.activeModal : null;
12903
13142
  const statusModal = status?.activeModal && Array.isArray(status.activeModal.buttons) && status.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? status.activeModal : null;
12904
- const effectiveModal = statusModal || surfacedModal;
12905
- const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" ? "waiting_approval" : status?.status;
12906
- LOG.info("Command", `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || "")} rawStatus=${String(status?.status || "")} effectiveStatus=${String(effectiveStatus || "")} statusModal=${statusModal ? "yes" : "no"} surfacedModal=${surfacedModal ? "yes" : "no"} instance=${targetInstance ? "yes" : "no"}`);
13143
+ const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
13144
+ try {
13145
+ return parseMaybeJson(adapter.getScriptParsedStatus());
13146
+ } catch {
13147
+ return null;
13148
+ }
13149
+ })() : null;
13150
+ const parsedModal = parsedStatus?.status === "waiting_approval" && parsedStatus?.activeModal && Array.isArray(parsedStatus.activeModal.buttons) && parsedStatus.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? parsedStatus.activeModal : null;
13151
+ const effectiveModal = statusModal || surfacedModal || parsedModal;
13152
+ const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
13153
+ LOG.info("Command", `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || "")} rawStatus=${String(status?.status || "")} effectiveStatus=${String(effectiveStatus || "")} statusModal=${statusModal ? "yes" : "no"} surfacedModal=${surfacedModal ? "yes" : "no"} parsedModal=${parsedModal ? "yes" : "no"} instance=${targetInstance ? "yes" : "no"}`);
12907
13154
  if (!effectiveModal) {
12908
13155
  return { success: false, error: "Not in approval state" };
12909
13156
  }
@@ -13029,7 +13276,7 @@ async function handleResolveAction(h, args) {
13029
13276
 
13030
13277
  // src/commands/cdp-commands.ts
13031
13278
  import * as fs5 from "fs";
13032
- import * as path12 from "path";
13279
+ import * as path13 from "path";
13033
13280
  import * as os7 from "os";
13034
13281
  var KEY_TO_VK = {
13035
13282
  Backspace: 8,
@@ -13286,25 +13533,25 @@ function resolveSafePath(requestedPath) {
13286
13533
  const inputPath = rawPath || ".";
13287
13534
  const home = os7.homedir();
13288
13535
  if (inputPath.startsWith("~")) {
13289
- return path12.resolve(path12.join(home, inputPath.slice(1)));
13536
+ return path13.resolve(path13.join(home, inputPath.slice(1)));
13290
13537
  }
13291
13538
  if (process.platform === "win32") {
13292
13539
  const normalized = normalizeWindowsRequestedPath(inputPath);
13293
- if (path12.win32.isAbsolute(normalized)) {
13294
- return path12.win32.normalize(normalized);
13540
+ if (path13.win32.isAbsolute(normalized)) {
13541
+ return path13.win32.normalize(normalized);
13295
13542
  }
13296
- return path12.win32.resolve(normalized);
13543
+ return path13.win32.resolve(normalized);
13297
13544
  }
13298
- if (path12.isAbsolute(inputPath)) {
13299
- return path12.normalize(inputPath);
13545
+ if (path13.isAbsolute(inputPath)) {
13546
+ return path13.normalize(inputPath);
13300
13547
  }
13301
- return path12.resolve(inputPath);
13548
+ return path13.resolve(inputPath);
13302
13549
  }
13303
13550
  function listDirectoryEntriesSafe(dirPath) {
13304
13551
  const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
13305
13552
  const files = [];
13306
13553
  for (const entry of entries) {
13307
- const entryPath = path12.join(dirPath, entry.name);
13554
+ const entryPath = path13.join(dirPath, entry.name);
13308
13555
  try {
13309
13556
  if (entry.isDirectory()) {
13310
13557
  files.push({ name: entry.name, type: "directory" });
@@ -13358,7 +13605,7 @@ async function handleFileRead(h, args) {
13358
13605
  async function handleFileWrite(h, args) {
13359
13606
  try {
13360
13607
  const filePath = resolveSafePath(args?.path);
13361
- fs5.mkdirSync(path12.dirname(filePath), { recursive: true });
13608
+ fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
13362
13609
  fs5.writeFileSync(filePath, args?.content || "", "utf-8");
13363
13610
  return { success: true, path: filePath };
13364
13611
  } catch (e) {
@@ -14142,9 +14389,11 @@ var DaemonCommandHandler = class {
14142
14389
  }
14143
14390
  const sessionLookupFailed = !!targetSessionId && !session;
14144
14391
  const managerKey = this.extractIdeType(args, sessionLookupFailed);
14145
- let providerType;
14392
+ let providerType = args?.agentType || args?.providerType;
14146
14393
  if (!sessionLookupFailed) {
14147
- providerType = session?.providerType || args?.agentType || args?.providerType || this.inferProviderType(managerKey);
14394
+ providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
14395
+ } else if (!providerType) {
14396
+ providerType = this.inferProviderType(managerKey);
14148
14397
  }
14149
14398
  return { session, managerKey, providerType, sessionLookupFailed };
14150
14399
  }
@@ -14224,7 +14473,8 @@ var DaemonCommandHandler = class {
14224
14473
  "pty_resize",
14225
14474
  "invoke_provider_script"
14226
14475
  ]);
14227
- if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd)) {
14476
+ const allowsInactiveReadChatFallback = cmd === "read_chat" && !!this._currentRoute.providerType && (typeof args?.providerSessionId === "string" && args.providerSessionId.trim().length > 0 || typeof args?.historySessionId === "string" && args.historySessionId.trim().length > 0);
14477
+ if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
14228
14478
  const result2 = {
14229
14479
  success: false,
14230
14480
  error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
@@ -14478,16 +14728,16 @@ var DaemonCommandHandler = class {
14478
14728
  // src/commands/cli-manager.ts
14479
14729
  init_provider_cli_adapter();
14480
14730
  import * as os13 from "os";
14481
- import * as path16 from "path";
14731
+ import * as path17 from "path";
14482
14732
  import * as crypto4 from "crypto";
14483
- import { existsSync as existsSync11 } from "fs";
14733
+ import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
14484
14734
  import { execFileSync } from "child_process";
14485
14735
  import chalk from "chalk";
14486
14736
  init_config();
14487
14737
 
14488
14738
  // src/providers/cli-provider-instance.ts
14489
14739
  import * as os12 from "os";
14490
- import * as path15 from "path";
14740
+ import * as path16 from "path";
14491
14741
  import * as crypto3 from "crypto";
14492
14742
  import * as fs6 from "fs";
14493
14743
  import { createRequire } from "module";
@@ -14546,7 +14796,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
14546
14796
  var CachedDatabaseSync = null;
14547
14797
  function getDatabaseSync() {
14548
14798
  if (CachedDatabaseSync) return CachedDatabaseSync;
14549
- const requireFn = typeof __require === "function" ? __require : createRequire(path15.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
14799
+ const requireFn = typeof __require === "function" ? __require : createRequire(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
14550
14800
  const sqliteModule = requireFn(`node:${"sqlite"}`);
14551
14801
  CachedDatabaseSync = sqliteModule.DatabaseSync;
14552
14802
  if (!CachedDatabaseSync) {
@@ -14599,7 +14849,7 @@ var CliProviderInstance = class {
14599
14849
  this.providerSessionId = options?.providerSessionId;
14600
14850
  this.launchMode = options?.launchMode || "new";
14601
14851
  this.onProviderSessionResolved = options?.onProviderSessionResolved;
14602
- this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
14852
+ this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
14603
14853
  this.monitor = new StatusMonitor();
14604
14854
  this.historyWriter = new ChatHistoryWriter();
14605
14855
  }
@@ -15076,7 +15326,19 @@ var CliProviderInstance = class {
15076
15326
  }
15077
15327
  }
15078
15328
  pushEvent(event) {
15079
- this.events.push(event);
15329
+ const enrichedEvent = {
15330
+ ...event,
15331
+ instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
15332
+ targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
15333
+ providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
15334
+ workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
15335
+ providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
15336
+ };
15337
+ if (this.context?.emitProviderEvent) {
15338
+ this.context.emitProviderEvent(enrichedEvent);
15339
+ return;
15340
+ }
15341
+ this.events.push(enrichedEvent);
15080
15342
  }
15081
15343
  flushEvents() {
15082
15344
  const events = [...this.events];
@@ -15283,12 +15545,29 @@ ${effect.notification.body || ""}`.trim();
15283
15545
  );
15284
15546
  }
15285
15547
  }
15548
+ mergeRuntimeChatMessages(parsedMessages) {
15549
+ return this.mergeConversationMessages(parsedMessages);
15550
+ }
15286
15551
  mergeConversationMessages(parsedMessages) {
15287
15552
  if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
15288
- return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
15289
- const aTime = a.message.receivedAt || a.message.timestamp || 0;
15290
- const bTime = b.message.receivedAt || b.message.timestamp || 0;
15291
- if (aTime !== bTime) return aTime - bTime;
15553
+ const parsedEntries = parsedMessages.map((message, index) => ({
15554
+ message,
15555
+ index,
15556
+ source: "parsed"
15557
+ }));
15558
+ const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
15559
+ message: entry.message,
15560
+ index: parsedMessages.length + index,
15561
+ source: "runtime"
15562
+ }));
15563
+ const getTime = (message) => {
15564
+ const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
15565
+ return Number.isFinite(value) && value > 0 ? value : 0;
15566
+ };
15567
+ return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
15568
+ const aTime = getTime(a.message);
15569
+ const bTime = getTime(b.message);
15570
+ if (aTime && bTime && aTime !== bTime) return aTime - bTime;
15292
15571
  return a.index - b.index;
15293
15572
  }).map((entry) => entry.message));
15294
15573
  }
@@ -16617,17 +16896,17 @@ function shouldRestoreHostedRuntime(record, managerTag) {
16617
16896
  // src/commands/cli-manager.ts
16618
16897
  function isExplicitCommand(command) {
16619
16898
  const trimmed = command.trim();
16620
- return path16.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
16899
+ return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
16621
16900
  }
16622
16901
  function expandExecutable(command) {
16623
16902
  const trimmed = command.trim();
16624
- return trimmed.startsWith("~") ? path16.join(os13.homedir(), trimmed.slice(1)) : trimmed;
16903
+ return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
16625
16904
  }
16626
16905
  function commandExists(command) {
16627
16906
  const trimmed = command.trim();
16628
16907
  if (!trimmed) return false;
16629
16908
  if (isExplicitCommand(trimmed)) {
16630
- return existsSync11(expandExecutable(trimmed));
16909
+ return existsSync12(expandExecutable(trimmed));
16631
16910
  }
16632
16911
  try {
16633
16912
  execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -16645,6 +16924,35 @@ function colorize(color, text) {
16645
16924
  const fn = chalkApi?.[color];
16646
16925
  return typeof fn === "function" ? fn(text) : text;
16647
16926
  }
16927
+ var COORDINATOR_DELEGATED_ENV_UNSETS = {
16928
+ ADHDEV_INLINE_MESH: "",
16929
+ ADHDEV_MCP_TRANSPORT: "",
16930
+ ADHDEV_MESH_ID: "",
16931
+ HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
16932
+ };
16933
+ function hasCliArg(args, flag) {
16934
+ return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
16935
+ }
16936
+ function ensureEmptyDelegatedMcpConfig(workspace) {
16937
+ const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
16938
+ mkdirSync7(baseDir, { recursive: true });
16939
+ const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
16940
+ const filePath = path17.join(baseDir, `${workspaceHash}.json`);
16941
+ writeFileSync7(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
16942
+ return filePath;
16943
+ }
16944
+ function buildCoordinatorDelegatedCliLaunchOptions(input) {
16945
+ const cliType = String(input.cliType || "").trim();
16946
+ const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
16947
+ const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
16948
+ if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
16949
+ cliArgs.unshift("--ignore-user-config");
16950
+ }
16951
+ if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
16952
+ cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
16953
+ }
16954
+ return { cliArgs, env };
16955
+ }
16648
16956
  function isUuid(value) {
16649
16957
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
16650
16958
  }
@@ -16815,7 +17123,7 @@ var DaemonCliManager = class {
16815
17123
  attachExisting
16816
17124
  }) || void 0;
16817
17125
  }
16818
- createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
17126
+ createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
16819
17127
  const normalizedType = this.providerLoader.resolveAlias(cliType);
16820
17128
  const provider = this.providerLoader.getMeta(normalizedType);
16821
17129
  if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
@@ -16829,7 +17137,7 @@ var DaemonCliManager = class {
16829
17137
  providerSessionId,
16830
17138
  attachExisting
16831
17139
  );
16832
- return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
17140
+ return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
16833
17141
  }
16834
17142
  throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
16835
17143
  }
@@ -16902,7 +17210,7 @@ var DaemonCliManager = class {
16902
17210
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
16903
17211
  const trimmed = (workingDir || "").trim();
16904
17212
  if (!trimmed) throw new Error("working directory required");
16905
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path16.resolve(trimmed);
17213
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
16906
17214
  const normalizedType = this.providerLoader.resolveAlias(cliType);
16907
17215
  const rawProvider = this.providerLoader.getByAlias(cliType);
16908
17216
  const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
@@ -17032,6 +17340,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
17032
17340
  {
17033
17341
  providerSessionId: sessionBinding.providerSessionId,
17034
17342
  launchMode: sessionBinding.launchMode,
17343
+ extraEnv: options?.extraEnv,
17035
17344
  onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
17036
17345
  this.persistRecentActivity({
17037
17346
  kind: "cli",
@@ -17052,7 +17361,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
17052
17361
  resolvedCliArgs,
17053
17362
  key,
17054
17363
  sessionBinding.providerSessionId,
17055
- false
17364
+ false,
17365
+ options?.extraEnv
17056
17366
  );
17057
17367
  try {
17058
17368
  await adapter.spawn();
@@ -17276,12 +17586,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
17276
17586
  const dir = resolved.path;
17277
17587
  const launchSource = resolved.source;
17278
17588
  if (!cliType) throw new Error("cliType required");
17589
+ const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
17590
+ const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
17591
+ cliType,
17592
+ workspace: dir,
17593
+ cliArgs: args?.cliArgs,
17594
+ env: args?.env
17595
+ }) : null;
17279
17596
  const started = await this.startSession(
17280
17597
  cliType,
17281
17598
  dir,
17282
- args?.cliArgs,
17599
+ delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
17283
17600
  args?.initialModel,
17284
- { resumeSessionId: args?.resumeSessionId, settingsOverride: args?.settings }
17601
+ {
17602
+ resumeSessionId: args?.resumeSessionId,
17603
+ settingsOverride,
17604
+ extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
17605
+ }
17285
17606
  );
17286
17607
  return {
17287
17608
  success: true,
@@ -17403,11 +17724,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
17403
17724
  import { execSync as execSync4, spawn as spawn2 } from "child_process";
17404
17725
  import * as net from "net";
17405
17726
  import * as os15 from "os";
17406
- import * as path18 from "path";
17727
+ import * as path19 from "path";
17407
17728
 
17408
17729
  // src/providers/provider-loader.ts
17409
17730
  import * as fs7 from "fs";
17410
- import * as path17 from "path";
17731
+ import * as path18 from "path";
17411
17732
  import * as os14 from "os";
17412
17733
  import * as chokidar from "chokidar";
17413
17734
  init_logger();
@@ -17731,7 +18052,7 @@ var ProviderLoader = class _ProviderLoader {
17731
18052
  try {
17732
18053
  if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
17733
18054
  return ["ide", "extension", "cli", "acp"].some(
17734
- (category) => fs7.existsSync(path17.join(candidate, category))
18055
+ (category) => fs7.existsSync(path18.join(candidate, category))
17735
18056
  );
17736
18057
  } catch {
17737
18058
  return false;
@@ -17739,20 +18060,20 @@ var ProviderLoader = class _ProviderLoader {
17739
18060
  }
17740
18061
  static hasProviderRootMarker(candidate) {
17741
18062
  try {
17742
- return fs7.existsSync(path17.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
18063
+ return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
17743
18064
  } catch {
17744
18065
  return false;
17745
18066
  }
17746
18067
  }
17747
18068
  detectDefaultUserDir() {
17748
- const fallback = path17.join(os14.homedir(), ".adhdev", "providers");
18069
+ const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
17749
18070
  const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
17750
18071
  const visited = /* @__PURE__ */ new Set();
17751
18072
  for (const start of this.probeStarts) {
17752
- let current = path17.resolve(start);
18073
+ let current = path18.resolve(start);
17753
18074
  while (!visited.has(current)) {
17754
18075
  visited.add(current);
17755
- const siblingCandidate = path17.join(path17.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
18076
+ const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
17756
18077
  if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
17757
18078
  const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
17758
18079
  if (envOptIn || hasMarker) {
@@ -17774,7 +18095,7 @@ var ProviderLoader = class _ProviderLoader {
17774
18095
  return { path: siblingCandidate, source };
17775
18096
  }
17776
18097
  }
17777
- const parent = path17.dirname(current);
18098
+ const parent = path18.dirname(current);
17778
18099
  if (parent === current) break;
17779
18100
  current = parent;
17780
18101
  }
@@ -17784,11 +18105,11 @@ var ProviderLoader = class _ProviderLoader {
17784
18105
  constructor(options) {
17785
18106
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
17786
18107
  this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
17787
- this.defaultProvidersDir = path17.join(os14.homedir(), ".adhdev", "providers");
18108
+ this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
17788
18109
  const detected = this.detectDefaultUserDir();
17789
18110
  this.userDir = detected.path;
17790
18111
  this.userDirSource = detected.source;
17791
- this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
18112
+ this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
17792
18113
  this.disableUpstream = false;
17793
18114
  this.applySourceConfig({
17794
18115
  userDir: options?.userDir,
@@ -17847,7 +18168,7 @@ var ProviderLoader = class _ProviderLoader {
17847
18168
  this.userDir = detected.path;
17848
18169
  this.userDirSource = detected.source;
17849
18170
  }
17850
- this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
18171
+ this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
17851
18172
  this.disableUpstream = this.sourceMode === "no-upstream";
17852
18173
  if (this.explicitProviderDir) {
17853
18174
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
@@ -17861,7 +18182,7 @@ var ProviderLoader = class _ProviderLoader {
17861
18182
  * Canonical provider directory shape for a given root.
17862
18183
  */
17863
18184
  getProviderDir(root, category, type) {
17864
- return path17.join(root, category, type);
18185
+ return path18.join(root, category, type);
17865
18186
  }
17866
18187
  /**
17867
18188
  * Canonical user override directory for a provider.
@@ -17888,7 +18209,7 @@ var ProviderLoader = class _ProviderLoader {
17888
18209
  resolveProviderFile(type, ...segments) {
17889
18210
  const dir = this.findProviderDirInternal(type);
17890
18211
  if (!dir) return null;
17891
- return path17.join(dir, ...segments);
18212
+ return path18.join(dir, ...segments);
17892
18213
  }
17893
18214
  /**
17894
18215
  * Load all providers (3-tier priority)
@@ -17927,7 +18248,7 @@ var ProviderLoader = class _ProviderLoader {
17927
18248
  if (!fs7.existsSync(this.upstreamDir)) return false;
17928
18249
  try {
17929
18250
  return fs7.readdirSync(this.upstreamDir).some(
17930
- (d) => fs7.statSync(path17.join(this.upstreamDir, d)).isDirectory()
18251
+ (d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
17931
18252
  );
17932
18253
  } catch {
17933
18254
  return false;
@@ -18424,8 +18745,8 @@ var ProviderLoader = class _ProviderLoader {
18424
18745
  resolved._resolvedScriptDir = entry.scriptDir;
18425
18746
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
18426
18747
  if (providerDir) {
18427
- const fullDir = path17.join(providerDir, entry.scriptDir);
18428
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
18748
+ const fullDir = path18.join(providerDir, entry.scriptDir);
18749
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18429
18750
  }
18430
18751
  matched = true;
18431
18752
  }
@@ -18440,8 +18761,8 @@ var ProviderLoader = class _ProviderLoader {
18440
18761
  resolved._resolvedScriptDir = base.defaultScriptDir;
18441
18762
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
18442
18763
  if (providerDir) {
18443
- const fullDir = path17.join(providerDir, base.defaultScriptDir);
18444
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
18764
+ const fullDir = path18.join(providerDir, base.defaultScriptDir);
18765
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18445
18766
  }
18446
18767
  }
18447
18768
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -18458,8 +18779,8 @@ var ProviderLoader = class _ProviderLoader {
18458
18779
  resolved._resolvedScriptDir = dirOverride;
18459
18780
  resolved._resolvedScriptsSource = `versions:${range}`;
18460
18781
  if (providerDir) {
18461
- const fullDir = path17.join(providerDir, dirOverride);
18462
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
18782
+ const fullDir = path18.join(providerDir, dirOverride);
18783
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18463
18784
  }
18464
18785
  }
18465
18786
  } else if (override.scripts) {
@@ -18475,8 +18796,8 @@ var ProviderLoader = class _ProviderLoader {
18475
18796
  resolved._resolvedScriptDir = base.defaultScriptDir;
18476
18797
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
18477
18798
  if (providerDir) {
18478
- const fullDir = path17.join(providerDir, base.defaultScriptDir);
18479
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
18799
+ const fullDir = path18.join(providerDir, base.defaultScriptDir);
18800
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18480
18801
  }
18481
18802
  }
18482
18803
  }
@@ -18508,14 +18829,14 @@ var ProviderLoader = class _ProviderLoader {
18508
18829
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
18509
18830
  return null;
18510
18831
  }
18511
- const dir = path17.join(providerDir, scriptDir);
18832
+ const dir = path18.join(providerDir, scriptDir);
18512
18833
  if (!fs7.existsSync(dir)) {
18513
18834
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
18514
18835
  return null;
18515
18836
  }
18516
18837
  const cached = this.scriptsCache.get(dir);
18517
18838
  if (cached) return cached;
18518
- const scriptsJs = path17.join(dir, "scripts.js");
18839
+ const scriptsJs = path18.join(dir, "scripts.js");
18519
18840
  if (fs7.existsSync(scriptsJs)) {
18520
18841
  try {
18521
18842
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -18557,7 +18878,7 @@ var ProviderLoader = class _ProviderLoader {
18557
18878
  return;
18558
18879
  }
18559
18880
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
18560
- this.log(`File changed: ${path17.basename(filePath)}, reloading...`);
18881
+ this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
18561
18882
  this.reload();
18562
18883
  }
18563
18884
  };
@@ -18612,7 +18933,7 @@ var ProviderLoader = class _ProviderLoader {
18612
18933
  }
18613
18934
  const https = __require("https");
18614
18935
  const { execSync: execSync7 } = __require("child_process");
18615
- const metaPath = path17.join(this.upstreamDir, _ProviderLoader.META_FILE);
18936
+ const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
18616
18937
  let prevEtag = "";
18617
18938
  let prevTimestamp = 0;
18618
18939
  try {
@@ -18672,17 +18993,17 @@ var ProviderLoader = class _ProviderLoader {
18672
18993
  return { updated: false };
18673
18994
  }
18674
18995
  this.log("Downloading latest providers from GitHub...");
18675
- const tmpTar = path17.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
18676
- const tmpExtract = path17.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
18996
+ const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
18997
+ const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
18677
18998
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
18678
18999
  fs7.mkdirSync(tmpExtract, { recursive: true });
18679
19000
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
18680
19001
  const extracted = fs7.readdirSync(tmpExtract);
18681
19002
  const rootDir = extracted.find(
18682
- (d) => fs7.statSync(path17.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
19003
+ (d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
18683
19004
  );
18684
19005
  if (!rootDir) throw new Error("Unexpected tarball structure");
18685
- const sourceDir = path17.join(tmpExtract, rootDir);
19006
+ const sourceDir = path18.join(tmpExtract, rootDir);
18686
19007
  const backupDir = this.upstreamDir + ".bak";
18687
19008
  if (fs7.existsSync(this.upstreamDir)) {
18688
19009
  if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
@@ -18757,8 +19078,8 @@ var ProviderLoader = class _ProviderLoader {
18757
19078
  copyDirRecursive(src, dest) {
18758
19079
  fs7.mkdirSync(dest, { recursive: true });
18759
19080
  for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
18760
- const srcPath = path17.join(src, entry.name);
18761
- const destPath = path17.join(dest, entry.name);
19081
+ const srcPath = path18.join(src, entry.name);
19082
+ const destPath = path18.join(dest, entry.name);
18762
19083
  if (entry.isDirectory()) {
18763
19084
  this.copyDirRecursive(srcPath, destPath);
18764
19085
  } else {
@@ -18769,7 +19090,7 @@ var ProviderLoader = class _ProviderLoader {
18769
19090
  /** .meta.json save */
18770
19091
  writeMeta(metaPath, etag, timestamp) {
18771
19092
  try {
18772
- fs7.mkdirSync(path17.dirname(metaPath), { recursive: true });
19093
+ fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
18773
19094
  fs7.writeFileSync(metaPath, JSON.stringify({
18774
19095
  etag,
18775
19096
  timestamp,
@@ -18786,7 +19107,7 @@ var ProviderLoader = class _ProviderLoader {
18786
19107
  const scan = (d) => {
18787
19108
  try {
18788
19109
  for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
18789
- if (entry.isDirectory()) scan(path17.join(d, entry.name));
19110
+ if (entry.isDirectory()) scan(path18.join(d, entry.name));
18790
19111
  else if (entry.name === "provider.json") count++;
18791
19112
  }
18792
19113
  } catch {
@@ -19014,17 +19335,17 @@ var ProviderLoader = class _ProviderLoader {
19014
19335
  for (const root of searchRoots) {
19015
19336
  if (!fs7.existsSync(root)) continue;
19016
19337
  const candidate = this.getProviderDir(root, cat, type);
19017
- if (fs7.existsSync(path17.join(candidate, "provider.json"))) return candidate;
19018
- const catDir = path17.join(root, cat);
19338
+ if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
19339
+ const catDir = path18.join(root, cat);
19019
19340
  if (fs7.existsSync(catDir)) {
19020
19341
  try {
19021
19342
  for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
19022
19343
  if (!entry.isDirectory()) continue;
19023
- const jsonPath = path17.join(catDir, entry.name, "provider.json");
19344
+ const jsonPath = path18.join(catDir, entry.name, "provider.json");
19024
19345
  if (fs7.existsSync(jsonPath)) {
19025
19346
  try {
19026
19347
  const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
19027
- if (data.type === type) return path17.join(catDir, entry.name);
19348
+ if (data.type === type) return path18.join(catDir, entry.name);
19028
19349
  } catch {
19029
19350
  }
19030
19351
  }
@@ -19041,7 +19362,7 @@ var ProviderLoader = class _ProviderLoader {
19041
19362
  * (template substitution is NOT applied here — scripts.js handles that)
19042
19363
  */
19043
19364
  buildScriptWrappersFromDir(dir) {
19044
- const scriptsJs = path17.join(dir, "scripts.js");
19365
+ const scriptsJs = path18.join(dir, "scripts.js");
19045
19366
  if (fs7.existsSync(scriptsJs)) {
19046
19367
  try {
19047
19368
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -19055,7 +19376,7 @@ var ProviderLoader = class _ProviderLoader {
19055
19376
  for (const file of fs7.readdirSync(dir)) {
19056
19377
  if (!file.endsWith(".js")) continue;
19057
19378
  const scriptName = toCamel(file.replace(".js", ""));
19058
- const filePath = path17.join(dir, file);
19379
+ const filePath = path18.join(dir, file);
19059
19380
  result[scriptName] = (...args) => {
19060
19381
  try {
19061
19382
  let content = fs7.readFileSync(filePath, "utf-8");
@@ -19115,7 +19436,7 @@ var ProviderLoader = class _ProviderLoader {
19115
19436
  }
19116
19437
  const hasJson = entries.some((e) => e.name === "provider.json");
19117
19438
  if (hasJson) {
19118
- const jsonPath = path17.join(d, "provider.json");
19439
+ const jsonPath = path18.join(d, "provider.json");
19119
19440
  try {
19120
19441
  const raw = fs7.readFileSync(jsonPath, "utf-8");
19121
19442
  const mod = JSON.parse(raw);
@@ -19136,7 +19457,7 @@ var ProviderLoader = class _ProviderLoader {
19136
19457
  this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
19137
19458
  } else {
19138
19459
  const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
19139
- const scriptsPath = path17.join(d, "scripts.js");
19460
+ const scriptsPath = path18.join(d, "scripts.js");
19140
19461
  if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
19141
19462
  try {
19142
19463
  delete __require.cache[__require.resolve(scriptsPath)];
@@ -19162,7 +19483,7 @@ var ProviderLoader = class _ProviderLoader {
19162
19483
  if (!entry.isDirectory()) continue;
19163
19484
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
19164
19485
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
19165
- scan(path17.join(d, entry.name));
19486
+ scan(path18.join(d, entry.name));
19166
19487
  }
19167
19488
  }
19168
19489
  };
@@ -19487,8 +19808,8 @@ function detectCurrentWorkspace(ideId) {
19487
19808
  const appNameMap = getMacAppIdentifiers();
19488
19809
  const appName = appNameMap[ideId];
19489
19810
  if (appName) {
19490
- const storagePath = path18.join(
19491
- process.env.APPDATA || path18.join(os15.homedir(), "AppData", "Roaming"),
19811
+ const storagePath = path19.join(
19812
+ process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
19492
19813
  appName,
19493
19814
  "storage.json"
19494
19815
  );
@@ -19677,9 +19998,9 @@ init_logger();
19677
19998
 
19678
19999
  // src/logging/command-log.ts
19679
20000
  import * as fs8 from "fs";
19680
- import * as path19 from "path";
20001
+ import * as path20 from "path";
19681
20002
  import * as os16 from "os";
19682
- var LOG_DIR2 = process.platform === "win32" ? path19.join(process.env.LOCALAPPDATA || process.env.APPDATA || path19.join(os16.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path19.join(os16.homedir(), "Library", "Logs", "adhdev") : path19.join(os16.homedir(), ".local", "share", "adhdev", "logs");
20003
+ var LOG_DIR2 = process.platform === "win32" ? path20.join(process.env.LOCALAPPDATA || process.env.APPDATA || path20.join(os16.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path20.join(os16.homedir(), "Library", "Logs", "adhdev") : path20.join(os16.homedir(), ".local", "share", "adhdev", "logs");
19683
20004
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
19684
20005
  var MAX_DAYS = 7;
19685
20006
  try {
@@ -19717,13 +20038,13 @@ function getDateStr2() {
19717
20038
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
19718
20039
  }
19719
20040
  var currentDate2 = getDateStr2();
19720
- var currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20041
+ var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
19721
20042
  var writeCount2 = 0;
19722
20043
  function checkRotation() {
19723
20044
  const today = getDateStr2();
19724
20045
  if (today !== currentDate2) {
19725
20046
  currentDate2 = today;
19726
- currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20047
+ currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
19727
20048
  cleanOldFiles();
19728
20049
  }
19729
20050
  }
@@ -19737,7 +20058,7 @@ function cleanOldFiles() {
19737
20058
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
19738
20059
  if (dateMatch && dateMatch[1] < cutoffStr) {
19739
20060
  try {
19740
- fs8.unlinkSync(path19.join(LOG_DIR2, file));
20061
+ fs8.unlinkSync(path20.join(LOG_DIR2, file));
19741
20062
  } catch {
19742
20063
  }
19743
20064
  }
@@ -19821,13 +20142,65 @@ cleanOldFiles();
19821
20142
 
19822
20143
  // src/commands/router.ts
19823
20144
  init_logger();
20145
+ import * as yaml from "js-yaml";
19824
20146
 
19825
20147
  // src/commands/mesh-coordinator.ts
19826
- import { existsSync as existsSync14, realpathSync as realpathSync2 } from "fs";
20148
+ import { execFileSync as execFileSync2 } from "child_process";
20149
+ import { existsSync as existsSync15, readdirSync as readdirSync6, realpathSync as realpathSync2 } from "fs";
19827
20150
  import { createRequire as createRequire2 } from "module";
19828
- import { dirname as dirname3, join as join17, resolve as resolve13 } from "path";
20151
+ import * as os17 from "os";
20152
+ import { dirname as dirname4, isAbsolute as isAbsolute10, join as join18, resolve as resolve13 } from "path";
19829
20153
  var DEFAULT_SERVER_NAME = "adhdev-mesh";
19830
20154
  var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
20155
+ var HERMES_CLI_TYPE = "hermes-cli";
20156
+ var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
20157
+ function isHermesProvider(provider, cliType) {
20158
+ const type = cliType?.trim() || provider?.type?.trim() || "";
20159
+ return type === HERMES_CLI_TYPE;
20160
+ }
20161
+ function resolveHermesMeshCoordinatorSetup(options) {
20162
+ const mcpServer = resolveAdhdevMcpServerLaunch({
20163
+ meshId: options.meshId,
20164
+ nodeExecutable: options.nodeExecutable,
20165
+ adhdevMcpEntryPath: options.adhdevMcpEntryPath
20166
+ });
20167
+ if (!mcpServer) {
20168
+ return {
20169
+ kind: "unsupported",
20170
+ reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
20171
+ };
20172
+ }
20173
+ const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
20174
+ if (!configPath.trim()) {
20175
+ return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
20176
+ }
20177
+ return {
20178
+ kind: "auto_import",
20179
+ serverName: DEFAULT_SERVER_NAME,
20180
+ configPath,
20181
+ configFormat: "hermes_config_yaml",
20182
+ mcpServer
20183
+ };
20184
+ }
20185
+ function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
20186
+ return {
20187
+ kind: "manual",
20188
+ serverName: DEFAULT_SERVER_NAME,
20189
+ configFormat: "hermes_config_yaml",
20190
+ configPathCommand: HERMES_MCP_CONFIG_PATH,
20191
+ requiresRestart: true,
20192
+ instructions: "Hermes CLI does not auto-import repo-local .mcp.json. Add this MCP server to Hermes config under mcp_servers, then start a fresh Hermes session.",
20193
+ template: renderMeshCoordinatorTemplate(
20194
+ "mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
20195
+ {
20196
+ meshId,
20197
+ workspace,
20198
+ serverName: DEFAULT_SERVER_NAME,
20199
+ adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
20200
+ }
20201
+ )
20202
+ };
20203
+ }
19831
20204
  function resolveMeshCoordinatorSetup(options) {
19832
20205
  const { provider, meshId, workspace } = options;
19833
20206
  const config = provider?.meshCoordinator;
@@ -19837,6 +20210,9 @@ function resolveMeshCoordinatorSetup(options) {
19837
20210
  reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
19838
20211
  };
19839
20212
  }
20213
+ if (isHermesProvider(provider, options.cliType)) {
20214
+ return resolveHermesMeshCoordinatorSetup(options);
20215
+ }
19840
20216
  const mcpConfig = config.mcpConfig;
19841
20217
  if (!mcpConfig || mcpConfig.mode === "none") {
19842
20218
  return {
@@ -19846,8 +20222,8 @@ function resolveMeshCoordinatorSetup(options) {
19846
20222
  }
19847
20223
  const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
19848
20224
  if (mcpConfig.mode === "auto_import") {
19849
- const path26 = mcpConfig.path?.trim();
19850
- if (!path26) {
20225
+ const path27 = mcpConfig.path?.trim();
20226
+ if (!path27) {
19851
20227
  return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
19852
20228
  }
19853
20229
  const mcpServer = resolveAdhdevMcpServerLaunch({
@@ -19858,13 +20234,13 @@ function resolveMeshCoordinatorSetup(options) {
19858
20234
  if (!mcpServer) {
19859
20235
  return {
19860
20236
  kind: "unsupported",
19861
- reason: "Could not resolve the ADHDev MCP server entrypoint without relying on a PATH bin shim"
20237
+ reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
19862
20238
  };
19863
20239
  }
19864
20240
  return {
19865
20241
  kind: "auto_import",
19866
20242
  serverName,
19867
- configPath: join17(workspace, path26),
20243
+ configPath: resolveMcpConfigPath(path27, workspace),
19868
20244
  configFormat: mcpConfig.format,
19869
20245
  mcpServer
19870
20246
  };
@@ -19898,14 +20274,85 @@ function resolveMeshCoordinatorSetup(options) {
19898
20274
  function renderMeshCoordinatorTemplate(template, values) {
19899
20275
  return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
19900
20276
  }
20277
+ function resolveMcpConfigPath(configPath, workspace) {
20278
+ const trimmed = configPath.trim();
20279
+ if (trimmed === "~") return os17.homedir();
20280
+ if (trimmed.startsWith("~/")) return join18(os17.homedir(), trimmed.slice(2));
20281
+ if (isAbsolute10(trimmed)) return trimmed;
20282
+ return join18(workspace, trimmed);
20283
+ }
19901
20284
  function resolveAdhdevMcpServerLaunch(options) {
19902
20285
  const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
19903
20286
  if (!entryPath) return null;
20287
+ const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
20288
+ if (!nodeExecutable) return null;
19904
20289
  return {
19905
- command: options.nodeExecutable?.trim() || process.execPath,
19906
- args: [entryPath, "--repo-mesh", options.meshId]
20290
+ command: nodeExecutable,
20291
+ args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
19907
20292
  };
19908
20293
  }
20294
+ function resolveMcpNodeExecutable(explicitExecutable) {
20295
+ const explicit = explicitExecutable?.trim();
20296
+ if (explicit) return explicit;
20297
+ const candidates = [];
20298
+ const addCandidate = (candidate) => {
20299
+ const trimmed = candidate?.trim();
20300
+ if (!trimmed) return;
20301
+ const normalized = normalizeExistingPath(trimmed) || trimmed;
20302
+ if (!candidates.includes(normalized)) candidates.push(normalized);
20303
+ };
20304
+ addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
20305
+ addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
20306
+ addCandidate(process.env.npm_node_execpath);
20307
+ addNodeCandidatesFromPath(process.env.PATH, addCandidate);
20308
+ addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
20309
+ addCandidate("/opt/homebrew/bin/node");
20310
+ addCandidate("/usr/local/bin/node");
20311
+ addCandidate("/usr/bin/node");
20312
+ addCandidate(process.execPath);
20313
+ for (const candidate of candidates) {
20314
+ if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
20315
+ }
20316
+ return null;
20317
+ }
20318
+ function addNodeCandidatesFromPath(pathValue, addCandidate) {
20319
+ for (const entry of (pathValue || "").split(":")) {
20320
+ const dir = entry.trim();
20321
+ if (!dir) continue;
20322
+ addCandidate(join18(dir, "node"));
20323
+ }
20324
+ }
20325
+ function addNodeCandidatesFromNvm(homeDir, addCandidate) {
20326
+ const versionsDir = join18(homeDir, ".nvm", "versions", "node");
20327
+ try {
20328
+ const versionDirs = readdirSync6(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
20329
+ for (const versionDir of versionDirs) {
20330
+ addCandidate(join18(versionsDir, versionDir, "bin", "node"));
20331
+ }
20332
+ } catch {
20333
+ }
20334
+ }
20335
+ function compareNodeVersionNamesDescending(a, b) {
20336
+ const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
20337
+ const left = parse(a);
20338
+ const right = parse(b);
20339
+ for (let i = 0; i < Math.max(left.length, right.length); i++) {
20340
+ const diff = (right[i] || 0) - (left[i] || 0);
20341
+ if (diff !== 0) return diff;
20342
+ }
20343
+ return b.localeCompare(a);
20344
+ }
20345
+ function nodeRuntimeSupportsWebSocket(nodeExecutable) {
20346
+ try {
20347
+ execFileSync2(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
20348
+ stdio: "ignore",
20349
+ timeout: 3e3
20350
+ });
20351
+ return true;
20352
+ } catch {
20353
+ return false;
20354
+ }
20355
+ }
19909
20356
  function resolveAdhdevMcpEntryPath(explicitPath) {
19910
20357
  const explicit = explicitPath?.trim();
19911
20358
  if (explicit) return normalizeExistingPath(explicit) || explicit;
@@ -19918,7 +20365,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19918
20365
  const addPackagedCandidates = (baseFile) => {
19919
20366
  if (!baseFile) return;
19920
20367
  const realBase = normalizeExistingPath(baseFile) || baseFile;
19921
- const dir = dirname3(realBase);
20368
+ const dir = dirname4(realBase);
19922
20369
  addCandidate(resolve13(dir, "../vendor/mcp-server/index.js"));
19923
20370
  addCandidate(resolve13(dir, "../../vendor/mcp-server/index.js"));
19924
20371
  addCandidate(resolve13(dir, "../../../vendor/mcp-server/index.js"));
@@ -19931,7 +20378,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19931
20378
  if (normalized) return normalized;
19932
20379
  }
19933
20380
  try {
19934
- const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join17(process.cwd(), "adhdev-daemon.js");
20381
+ const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join18(process.cwd(), "adhdev-daemon.js");
19935
20382
  const req = createRequire2(requireBase);
19936
20383
  const resolvedModule = req.resolve("@adhdev/mcp-server");
19937
20384
  return normalizeExistingPath(resolvedModule) || resolvedModule;
@@ -19941,16 +20388,110 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19941
20388
  }
19942
20389
  function normalizeExistingPath(filePath) {
19943
20390
  try {
19944
- if (!existsSync14(filePath)) return null;
20391
+ if (!existsSync15(filePath)) return null;
19945
20392
  return realpathSync2.native(filePath);
19946
20393
  } catch {
19947
20394
  return null;
19948
20395
  }
19949
20396
  }
19950
20397
 
20398
+ // src/mesh/mesh-events.ts
20399
+ init_mesh_config();
20400
+ init_logger();
20401
+ function readNonEmptyString(value) {
20402
+ return typeof value === "string" && value.trim() ? value.trim() : "";
20403
+ }
20404
+ function formatCompletionMetadata(event) {
20405
+ const parts = [
20406
+ readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
20407
+ readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
20408
+ readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
20409
+ ].filter(Boolean);
20410
+ return parts.length > 0 ? ` (${parts.join("; ")})` : "";
20411
+ }
20412
+ function buildMeshSystemMessage(args) {
20413
+ const metadata = formatCompletionMetadata(args.metadataEvent);
20414
+ if (args.event === "agent:generating_completed") {
20415
+ 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.`;
20416
+ }
20417
+ if (args.event === "agent:waiting_approval") {
20418
+ return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
20419
+ }
20420
+ return "";
20421
+ }
20422
+ function injectMeshSystemMessage(components, args) {
20423
+ const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
20424
+ const instState = inst.getState();
20425
+ if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
20426
+ if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
20427
+ return true;
20428
+ });
20429
+ if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
20430
+ const messageText = buildMeshSystemMessage({
20431
+ event: args.event,
20432
+ nodeLabel: args.nodeLabel,
20433
+ metadataEvent: args.metadataEvent
20434
+ });
20435
+ if (!messageText) return { success: false, error: "unsupported mesh event" };
20436
+ for (const coord of coordinatorInstances) {
20437
+ const coordState = coord.getState();
20438
+ LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
20439
+ coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
20440
+ }
20441
+ return { success: true, forwarded: coordinatorInstances.length };
20442
+ }
20443
+ function handleMeshForwardEvent(components, payload) {
20444
+ const eventName = readNonEmptyString(payload.event);
20445
+ if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
20446
+ return { success: false, error: "unsupported mesh event" };
20447
+ }
20448
+ const meshId = readNonEmptyString(payload.meshId);
20449
+ if (!meshId) return { success: false, error: "meshId required" };
20450
+ const nodeId = readNonEmptyString(payload.nodeId);
20451
+ const workspace = readNonEmptyString(payload.workspace);
20452
+ const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
20453
+ return injectMeshSystemMessage(components, {
20454
+ meshId,
20455
+ nodeLabel,
20456
+ event: eventName,
20457
+ metadataEvent: {
20458
+ targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
20459
+ providerType: readNonEmptyString(payload.providerType),
20460
+ providerSessionId: readNonEmptyString(payload.providerSessionId)
20461
+ }
20462
+ });
20463
+ }
20464
+ function setupMeshEventForwarding(components) {
20465
+ components.instanceManager.onEvent((event) => {
20466
+ if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
20467
+ const instanceId = readNonEmptyString(event.instanceId);
20468
+ if (!instanceId) return;
20469
+ const sourceInstance = components.instanceManager.getInstance(instanceId);
20470
+ if (!sourceInstance || sourceInstance.category !== "cli") return;
20471
+ const state = sourceInstance.getState();
20472
+ const workspace = readNonEmptyString(state.workspace);
20473
+ if (!workspace) return;
20474
+ const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
20475
+ const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
20476
+ const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
20477
+ const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
20478
+ if (!meshId) return;
20479
+ const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
20480
+ const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
20481
+ const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
20482
+ injectMeshSystemMessage(components, {
20483
+ meshId,
20484
+ sourceInstanceId: instanceId,
20485
+ nodeLabel,
20486
+ event: event.event,
20487
+ metadataEvent: event
20488
+ });
20489
+ });
20490
+ }
20491
+
19951
20492
  // src/status/snapshot.ts
19952
20493
  init_config();
19953
- import * as os17 from "os";
20494
+ import * as os18 from "os";
19954
20495
  init_terminal_screen();
19955
20496
  init_logger();
19956
20497
  var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
@@ -20005,8 +20546,8 @@ function buildAvailableProviders(providerLoader) {
20005
20546
  }
20006
20547
  function buildMachineInfo(profile = "full") {
20007
20548
  const base = {
20008
- hostname: os17.hostname(),
20009
- platform: os17.platform()
20549
+ hostname: os18.hostname(),
20550
+ platform: os18.platform()
20010
20551
  };
20011
20552
  if (profile === "live") {
20012
20553
  return base;
@@ -20015,23 +20556,23 @@ function buildMachineInfo(profile = "full") {
20015
20556
  const memSnap2 = getHostMemorySnapshot();
20016
20557
  return {
20017
20558
  ...base,
20018
- arch: os17.arch(),
20019
- cpus: os17.cpus().length,
20559
+ arch: os18.arch(),
20560
+ cpus: os18.cpus().length,
20020
20561
  totalMem: memSnap2.totalMem,
20021
- release: os17.release()
20562
+ release: os18.release()
20022
20563
  };
20023
20564
  }
20024
20565
  const memSnap = getHostMemorySnapshot();
20025
20566
  return {
20026
20567
  ...base,
20027
- arch: os17.arch(),
20028
- cpus: os17.cpus().length,
20568
+ arch: os18.arch(),
20569
+ cpus: os18.cpus().length,
20029
20570
  totalMem: memSnap.totalMem,
20030
20571
  freeMem: memSnap.freeMem,
20031
20572
  availableMem: memSnap.availableMem,
20032
- loadavg: os17.loadavg(),
20033
- uptime: os17.uptime(),
20034
- release: os17.release()
20573
+ loadavg: os18.loadavg(),
20574
+ uptime: os18.uptime(),
20575
+ release: os18.release()
20035
20576
  };
20036
20577
  }
20037
20578
  function parseMessageTime(value) {
@@ -20262,17 +20803,17 @@ function buildStatusSnapshot(options) {
20262
20803
  }
20263
20804
 
20264
20805
  // src/commands/upgrade-helper.ts
20265
- import { execFileSync as execFileSync2 } from "child_process";
20806
+ import { execFileSync as execFileSync3 } from "child_process";
20266
20807
  import { spawn as spawn3 } from "child_process";
20267
20808
  import * as fs9 from "fs";
20268
- import * as os18 from "os";
20269
- import * as path20 from "path";
20809
+ import * as os19 from "os";
20810
+ import * as path21 from "path";
20270
20811
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
20271
20812
  function getUpgradeLogPath() {
20272
- const home = os18.homedir();
20273
- const dir = path20.join(home, ".adhdev");
20813
+ const home = os19.homedir();
20814
+ const dir = path21.join(home, ".adhdev");
20274
20815
  fs9.mkdirSync(dir, { recursive: true });
20275
- return path20.join(dir, "daemon-upgrade.log");
20816
+ return path21.join(dir, "daemon-upgrade.log");
20276
20817
  }
20277
20818
  function appendUpgradeLog(message) {
20278
20819
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -20283,14 +20824,14 @@ function appendUpgradeLog(message) {
20283
20824
  }
20284
20825
  }
20285
20826
  function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
20286
- const binDir = path20.dirname(nodeExecutable);
20827
+ const binDir = path21.dirname(nodeExecutable);
20287
20828
  if (platform10 === "win32") {
20288
- const npmCliPath = path20.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
20829
+ const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
20289
20830
  if (fs9.existsSync(npmCliPath)) {
20290
20831
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
20291
20832
  }
20292
20833
  for (const candidate of ["npm.exe", "npm"]) {
20293
- const candidatePath = path20.join(binDir, candidate);
20834
+ const candidatePath = path21.join(binDir, candidate);
20294
20835
  if (fs9.existsSync(candidatePath)) {
20295
20836
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
20296
20837
  }
@@ -20298,7 +20839,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
20298
20839
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
20299
20840
  }
20300
20841
  for (const candidate of ["npm"]) {
20301
- const candidatePath = path20.join(binDir, candidate);
20842
+ const candidatePath = path21.join(binDir, candidate);
20302
20843
  if (fs9.existsSync(candidatePath)) {
20303
20844
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
20304
20845
  }
@@ -20315,13 +20856,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20315
20856
  let currentDir = resolvedPath;
20316
20857
  try {
20317
20858
  if (fs9.statSync(resolvedPath).isFile()) {
20318
- currentDir = path20.dirname(resolvedPath);
20859
+ currentDir = path21.dirname(resolvedPath);
20319
20860
  }
20320
20861
  } catch {
20321
- currentDir = path20.dirname(resolvedPath);
20862
+ currentDir = path21.dirname(resolvedPath);
20322
20863
  }
20323
20864
  while (true) {
20324
- const packageJsonPath = path20.join(currentDir, "package.json");
20865
+ const packageJsonPath = path21.join(currentDir, "package.json");
20325
20866
  try {
20326
20867
  if (fs9.existsSync(packageJsonPath)) {
20327
20868
  const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
@@ -20332,7 +20873,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20332
20873
  }
20333
20874
  } catch {
20334
20875
  }
20335
- const parentDir = path20.dirname(currentDir);
20876
+ const parentDir = path21.dirname(currentDir);
20336
20877
  if (parentDir === currentDir) {
20337
20878
  return null;
20338
20879
  }
@@ -20340,13 +20881,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20340
20881
  }
20341
20882
  }
20342
20883
  function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
20343
- const nodeModulesDir = packageName.startsWith("@") ? path20.dirname(path20.dirname(packageRoot)) : path20.dirname(packageRoot);
20344
- if (path20.basename(nodeModulesDir) !== "node_modules") {
20884
+ const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
20885
+ if (path21.basename(nodeModulesDir) !== "node_modules") {
20345
20886
  return null;
20346
20887
  }
20347
- const maybeLibDir = path20.dirname(nodeModulesDir);
20348
- if (path20.basename(maybeLibDir) === "lib") {
20349
- return path20.dirname(maybeLibDir);
20888
+ const maybeLibDir = path21.dirname(nodeModulesDir);
20889
+ if (path21.basename(maybeLibDir) === "lib") {
20890
+ return path21.dirname(maybeLibDir);
20350
20891
  }
20351
20892
  return maybeLibDir;
20352
20893
  }
@@ -20382,7 +20923,7 @@ function getNpmExecOptions(platform10 = process.platform) {
20382
20923
  }
20383
20924
  function execNpmCommandSync(args, options = {}, surface) {
20384
20925
  const execOptions = surface?.execOptions || getNpmExecOptions();
20385
- return execFileSync2(
20926
+ return execFileSync3(
20386
20927
  surface?.npmExecutable || "npm",
20387
20928
  [...surface?.npmArgsPrefix || [], ...args],
20388
20929
  {
@@ -20395,7 +20936,7 @@ function execNpmCommandSync(args, options = {}, surface) {
20395
20936
  function killPid(pid) {
20396
20937
  try {
20397
20938
  if (process.platform === "win32") {
20398
- execFileSync2("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
20939
+ execFileSync3("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
20399
20940
  } else {
20400
20941
  process.kill(pid, "SIGTERM");
20401
20942
  }
@@ -20407,7 +20948,7 @@ function killPid(pid) {
20407
20948
  function getWindowsProcessCommandLine(pid) {
20408
20949
  const pidFilter = `ProcessId=${pid}`;
20409
20950
  try {
20410
- const psOut = execFileSync2("powershell.exe", [
20951
+ const psOut = execFileSync3("powershell.exe", [
20411
20952
  "-NoProfile",
20412
20953
  "-NonInteractive",
20413
20954
  "-ExecutionPolicy",
@@ -20419,7 +20960,7 @@ function getWindowsProcessCommandLine(pid) {
20419
20960
  } catch {
20420
20961
  }
20421
20962
  try {
20422
- const wmicOut = execFileSync2("wmic", [
20963
+ const wmicOut = execFileSync3("wmic", [
20423
20964
  "process",
20424
20965
  "where",
20425
20966
  pidFilter,
@@ -20435,7 +20976,7 @@ function getProcessCommandLine(pid) {
20435
20976
  if (!Number.isFinite(pid) || pid <= 0) return null;
20436
20977
  if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
20437
20978
  try {
20438
- const text = execFileSync2("ps", ["-o", "command=", "-p", String(pid)], {
20979
+ const text = execFileSync3("ps", ["-o", "command=", "-p", String(pid)], {
20439
20980
  encoding: "utf8",
20440
20981
  timeout: 3e3,
20441
20982
  stdio: ["ignore", "pipe", "ignore"]
@@ -20461,7 +21002,7 @@ async function waitForPidExit(pid, timeoutMs) {
20461
21002
  }
20462
21003
  }
20463
21004
  function stopSessionHostProcesses(appName) {
20464
- const pidFile = path20.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
21005
+ const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
20465
21006
  try {
20466
21007
  if (fs9.existsSync(pidFile)) {
20467
21008
  const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
@@ -20478,7 +21019,7 @@ function stopSessionHostProcesses(appName) {
20478
21019
  }
20479
21020
  }
20480
21021
  function removeDaemonPidFile() {
20481
- const pidFile = path20.join(os18.homedir(), ".adhdev", "daemon.pid");
21022
+ const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
20482
21023
  try {
20483
21024
  fs9.unlinkSync(pidFile);
20484
21025
  } catch {
@@ -20489,7 +21030,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
20489
21030
  const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
20490
21031
  if (!npmRoot) return;
20491
21032
  const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
20492
- const binDir = process.platform === "win32" ? npmPrefix : path20.join(npmPrefix, "bin");
21033
+ const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
20493
21034
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
20494
21035
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
20495
21036
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -20497,25 +21038,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
20497
21038
  }
20498
21039
  if (pkgName.startsWith("@")) {
20499
21040
  const [scope, name] = pkgName.split("/");
20500
- const scopeDir = path20.join(npmRoot, scope);
21041
+ const scopeDir = path21.join(npmRoot, scope);
20501
21042
  if (!fs9.existsSync(scopeDir)) return;
20502
21043
  for (const entry of fs9.readdirSync(scopeDir)) {
20503
21044
  if (!entry.startsWith(`.${name}-`)) continue;
20504
- fs9.rmSync(path20.join(scopeDir, entry), { recursive: true, force: true });
20505
- appendUpgradeLog(`Removed stale scoped staging dir: ${path20.join(scopeDir, entry)}`);
21045
+ fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
21046
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
20506
21047
  }
20507
21048
  } else {
20508
21049
  for (const entry of fs9.readdirSync(npmRoot)) {
20509
21050
  if (!entry.startsWith(`.${pkgName}-`)) continue;
20510
- fs9.rmSync(path20.join(npmRoot, entry), { recursive: true, force: true });
20511
- appendUpgradeLog(`Removed stale staging dir: ${path20.join(npmRoot, entry)}`);
21051
+ fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
21052
+ appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
20512
21053
  }
20513
21054
  }
20514
21055
  if (fs9.existsSync(binDir)) {
20515
21056
  for (const entry of fs9.readdirSync(binDir)) {
20516
21057
  if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
20517
- fs9.rmSync(path20.join(binDir, entry), { recursive: true, force: true });
20518
- appendUpgradeLog(`Removed stale bin staging entry: ${path20.join(binDir, entry)}`);
21058
+ fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
21059
+ appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
20519
21060
  }
20520
21061
  }
20521
21062
  }
@@ -20551,7 +21092,7 @@ async function runDaemonUpgradeHelper(payload) {
20551
21092
  cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
20552
21093
  const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
20553
21094
  appendUpgradeLog(`Installing ${spec}`);
20554
- const installOutput = execFileSync2(
21095
+ const installOutput = execFileSync3(
20555
21096
  installCommand.command,
20556
21097
  installCommand.args,
20557
21098
  {
@@ -20616,6 +21157,56 @@ function normalizeReleaseChannel(value) {
20616
21157
  function resolveUpgradeChannel(args) {
20617
21158
  return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
20618
21159
  }
21160
+ function readProviderPriorityFromPolicy(policy) {
21161
+ const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
21162
+ const raw = record.providerPriority;
21163
+ if (!Array.isArray(raw)) return [];
21164
+ const seen = /* @__PURE__ */ new Set();
21165
+ return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
21166
+ if (seen.has(type)) return false;
21167
+ seen.add(type);
21168
+ return true;
21169
+ });
21170
+ }
21171
+ async function resolveProviderTypeFromPriority(args) {
21172
+ if (!args.providerPriority.length) {
21173
+ return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
21174
+ }
21175
+ const failed = [];
21176
+ for (const requestedType of args.providerPriority) {
21177
+ const normalizedType = args.providerLoader.resolveAlias(requestedType);
21178
+ if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
21179
+ failed.push(`${requestedType}: disabled`);
21180
+ continue;
21181
+ }
21182
+ const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
21183
+ args.providerLoader.setCliDetectionResults([{
21184
+ id: normalizedType,
21185
+ installed: !!detected,
21186
+ path: detected?.path
21187
+ }], false);
21188
+ args.onStatusChange?.();
21189
+ if (detected) return { providerType: normalizedType };
21190
+ failed.push(`${requestedType}: not detected`);
21191
+ }
21192
+ return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
21193
+ }
21194
+ function loadYamlModule() {
21195
+ return yaml;
21196
+ }
21197
+ function getMcpServersKey(format) {
21198
+ return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
21199
+ }
21200
+ function parseMeshCoordinatorMcpConfig(text, format) {
21201
+ if (!text.trim()) return {};
21202
+ if (format === "claude_mcp_json") return JSON.parse(text);
21203
+ const parsed = loadYamlModule().load(text);
21204
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
21205
+ }
21206
+ function serializeMeshCoordinatorMcpConfig(config, format) {
21207
+ if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
21208
+ return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
21209
+ }
20619
21210
  var CHAT_COMMANDS = [
20620
21211
  "send_chat",
20621
21212
  "new_chat",
@@ -20714,6 +21305,154 @@ var DaemonCommandRouter = class {
20714
21305
  constructor(deps) {
20715
21306
  this.deps = deps;
20716
21307
  }
21308
+ getCachedInlineMesh(meshId, inlineMesh) {
21309
+ if (inlineMesh && typeof inlineMesh === "object") {
21310
+ this.inlineMeshCache.set(meshId, inlineMesh);
21311
+ return inlineMesh;
21312
+ }
21313
+ return this.inlineMeshCache.get(meshId);
21314
+ }
21315
+ async getMeshForCommand(meshId, inlineMesh) {
21316
+ try {
21317
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21318
+ const mesh = getMesh3(meshId);
21319
+ if (mesh) return { mesh, inline: false };
21320
+ } catch {
21321
+ }
21322
+ const cached = this.getCachedInlineMesh(meshId, inlineMesh);
21323
+ return cached ? { mesh: cached, inline: true } : null;
21324
+ }
21325
+ updateInlineMeshNode(meshId, mesh, node) {
21326
+ if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
21327
+ const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
21328
+ if (idx >= 0) mesh.nodes[idx] = node;
21329
+ else mesh.nodes.push(node);
21330
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21331
+ this.inlineMeshCache.set(meshId, mesh);
21332
+ }
21333
+ removeInlineMeshNode(meshId, mesh, nodeId) {
21334
+ if (!mesh || !Array.isArray(mesh.nodes)) return false;
21335
+ const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
21336
+ if (idx === -1) return false;
21337
+ mesh.nodes.splice(idx, 1);
21338
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21339
+ this.inlineMeshCache.set(meshId, mesh);
21340
+ return true;
21341
+ }
21342
+ normalizeMeshSessionCleanupMode(value) {
21343
+ return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
21344
+ }
21345
+ sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
21346
+ const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
21347
+ if (!sessionId) return false;
21348
+ if (sessionIds?.size) return sessionIds.has(sessionId);
21349
+ const workspace = typeof node?.workspace === "string" ? node.workspace : "";
21350
+ if (workspace && record?.workspace === workspace) return true;
21351
+ if (record?.meta?.meshNodeId === nodeId) return true;
21352
+ return false;
21353
+ }
21354
+ isCompletedHostedSession(record) {
21355
+ return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
21356
+ }
21357
+ async cleanupMeshSessions(args) {
21358
+ if (args.mode === "preserve") {
21359
+ return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
21360
+ }
21361
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
21362
+ const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
21363
+ const sessions = await this.deps.sessionHostControl.listSessions();
21364
+ const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
21365
+ const hasExplicitSessionIds = !!requestedSessionIds?.size;
21366
+ const stoppedSessionIds = [];
21367
+ const deletedSessionIds = [];
21368
+ const skippedSessionIds = [];
21369
+ const skippedLiveSessionIds = [];
21370
+ const deleteUnsupportedSessionIds = [];
21371
+ const recordsRemainSessionIds = [];
21372
+ const errors = [];
21373
+ const matchedBySurfaceKind = {
21374
+ live_runtime: 0,
21375
+ recovery_snapshot: 0,
21376
+ inactive_record: 0
21377
+ };
21378
+ for (const record of matched) {
21379
+ const surfaceKind = getSessionHostSurfaceKind(record);
21380
+ matchedBySurfaceKind[surfaceKind] += 1;
21381
+ }
21382
+ for (const record of matched) {
21383
+ const sessionId = String(record.sessionId);
21384
+ const completed = this.isCompletedHostedSession(record);
21385
+ const surfaceKind = getSessionHostSurfaceKind(record);
21386
+ const liveRuntime = surfaceKind === "live_runtime";
21387
+ if (!hasExplicitSessionIds && liveRuntime) {
21388
+ skippedSessionIds.push(sessionId);
21389
+ skippedLiveSessionIds.push(sessionId);
21390
+ continue;
21391
+ }
21392
+ try {
21393
+ if (args.mode === "stop") {
21394
+ if (!completed) {
21395
+ if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
21396
+ stoppedSessionIds.push(sessionId);
21397
+ } else {
21398
+ skippedSessionIds.push(sessionId);
21399
+ }
21400
+ continue;
21401
+ }
21402
+ if (args.mode === "delete_stopped") {
21403
+ if (completed) {
21404
+ if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
21405
+ deletedSessionIds.push(sessionId);
21406
+ } else {
21407
+ skippedSessionIds.push(sessionId);
21408
+ }
21409
+ continue;
21410
+ }
21411
+ if (args.mode === "stop_and_delete") {
21412
+ if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
21413
+ deletedSessionIds.push(sessionId);
21414
+ continue;
21415
+ }
21416
+ } catch (e) {
21417
+ const message = e?.message || String(e);
21418
+ if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
21419
+ deleteUnsupportedSessionIds.push(sessionId);
21420
+ recordsRemainSessionIds.push(sessionId);
21421
+ if (args.mode === "stop_and_delete" && !completed) {
21422
+ try {
21423
+ await this.deps.sessionHostControl.stopSession(sessionId);
21424
+ stoppedSessionIds.push(sessionId);
21425
+ } catch (stopError) {
21426
+ errors.push({ sessionId, error: stopError?.message || String(stopError) });
21427
+ continue;
21428
+ }
21429
+ }
21430
+ skippedSessionIds.push(sessionId);
21431
+ continue;
21432
+ }
21433
+ errors.push({ sessionId, error: message });
21434
+ }
21435
+ }
21436
+ const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
21437
+ return {
21438
+ success: errors.length === 0,
21439
+ mode: args.mode,
21440
+ dryRun: args.dryRun === true,
21441
+ matchedCount: matched.length,
21442
+ matchedBySurfaceKind,
21443
+ stoppedSessionIds,
21444
+ deletedSessionIds,
21445
+ skippedSessionIds,
21446
+ skippedLiveSessionIds,
21447
+ ...deleteUnsupported ? {
21448
+ deleteUnsupported: true,
21449
+ effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
21450
+ deleteUnsupportedSessionIds,
21451
+ recordsRemainSessionIds
21452
+ } : {},
21453
+ ...errors.length ? { errors } : {}
21454
+ };
21455
+ }
20717
21456
  async traceSessionHostAction(action, args, run, summarizeResult) {
20718
21457
  const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
20719
21458
  const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
@@ -20833,6 +21572,9 @@ var DaemonCommandRouter = class {
20833
21572
  async executeDaemonCommand(cmd, args) {
20834
21573
  switch (cmd) {
20835
21574
  // ─── CLI / ACP commands ───
21575
+ case "mesh_forward_event": {
21576
+ return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
21577
+ }
20836
21578
  case "launch_cli":
20837
21579
  case "stop_cli":
20838
21580
  case "set_cli_view_mode":
@@ -21377,7 +22119,26 @@ var DaemonCommandRouter = class {
21377
22119
  if (!name) return { success: false, error: "name required" };
21378
22120
  try {
21379
22121
  const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21380
- const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
22122
+ const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
22123
+ return { success: true, mesh };
22124
+ } catch (e) {
22125
+ return { success: false, error: e.message };
22126
+ }
22127
+ }
22128
+ case "update_mesh": {
22129
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22130
+ if (!meshId) return { success: false, error: "meshId required" };
22131
+ try {
22132
+ const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22133
+ const patch = {};
22134
+ if (typeof args?.name === "string") patch.name = args.name;
22135
+ if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
22136
+ if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
22137
+ if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
22138
+ if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
22139
+ const mesh = updateMesh2(meshId, patch);
22140
+ if (!mesh) return { success: false, error: "Mesh not found" };
22141
+ this.inlineMeshCache.set(meshId, mesh);
21381
22142
  return { success: true, mesh };
21382
22143
  } catch (e) {
21383
22144
  return { success: false, error: e.message };
@@ -21401,21 +22162,164 @@ var DaemonCommandRouter = class {
21401
22162
  if (!workspace) return { success: false, error: "workspace required" };
21402
22163
  try {
21403
22164
  const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21404
- const node = addNode3(meshId, { workspace });
22165
+ const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
22166
+ const readOnly = args?.readOnly === true;
22167
+ const policy = {
22168
+ ...readOnly ? { readOnly: true } : {},
22169
+ ...providerPriority.length ? { providerPriority } : {}
22170
+ };
22171
+ const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
21405
22172
  if (!node) return { success: false, error: "Mesh not found" };
21406
22173
  return { success: true, node };
21407
22174
  } catch (e) {
21408
22175
  return { success: false, error: e.message };
21409
22176
  }
21410
22177
  }
22178
+ case "update_mesh_node": {
22179
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22180
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
22181
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
22182
+ try {
22183
+ const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22184
+ const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
22185
+ if (Array.isArray(args?.providerPriority)) {
22186
+ const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
22187
+ delete policy.provider_priority;
22188
+ if (providerPriority.length) {
22189
+ policy.providerPriority = providerPriority;
22190
+ } else {
22191
+ delete policy.providerPriority;
22192
+ }
22193
+ }
22194
+ const node = updateNode2(meshId, nodeId, { policy });
22195
+ if (!node) return { success: false, error: "Mesh node not found" };
22196
+ return { success: true, node };
22197
+ } catch (e) {
22198
+ return { success: false, error: e.message };
22199
+ }
22200
+ }
22201
+ case "cleanup_mesh_sessions": {
22202
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22203
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
22204
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
22205
+ try {
22206
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22207
+ const mesh = meshRecord?.mesh;
22208
+ if (!mesh) return { success: false, error: "Mesh not found" };
22209
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
22210
+ if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
22211
+ const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
22212
+ const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
22213
+ const result = await this.cleanupMeshSessions({
22214
+ meshId,
22215
+ nodeId,
22216
+ node,
22217
+ mode,
22218
+ sessionIds,
22219
+ dryRun: args?.dryRun === true
22220
+ });
22221
+ return result;
22222
+ } catch (e) {
22223
+ return { success: false, error: e.message };
22224
+ }
22225
+ }
21411
22226
  case "remove_mesh_node": {
21412
22227
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21413
22228
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
21414
22229
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
21415
22230
  try {
21416
- const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21417
- const removed = removeNode3(meshId, nodeId);
21418
- return { success: true, removed };
22231
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22232
+ const mesh = meshRecord?.mesh;
22233
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
22234
+ const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
22235
+ args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
22236
+ );
22237
+ let sessionCleanup;
22238
+ if (node && sessionCleanupMode !== "preserve") {
22239
+ sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
22240
+ if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
22241
+ }
22242
+ if (node?.isLocalWorktree && node.workspace) {
22243
+ try {
22244
+ const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
22245
+ const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
22246
+ if (repoRoot) {
22247
+ const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22248
+ await removeWorktree2(repoRoot, node.workspace);
22249
+ }
22250
+ } catch (e) {
22251
+ LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
22252
+ }
22253
+ }
22254
+ let removed = false;
22255
+ if (meshRecord?.inline) {
22256
+ removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
22257
+ } else {
22258
+ const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22259
+ removed = removeNode3(meshId, nodeId);
22260
+ }
22261
+ return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
22262
+ } catch (e) {
22263
+ return { success: false, error: e.message };
22264
+ }
22265
+ }
22266
+ case "clone_mesh_node": {
22267
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22268
+ const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
22269
+ const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
22270
+ const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
22271
+ if (!meshId) return { success: false, error: "meshId required" };
22272
+ if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
22273
+ if (!branch) return { success: false, error: "branch required" };
22274
+ try {
22275
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22276
+ const mesh = meshRecord?.mesh;
22277
+ if (!mesh) return { success: false, error: "Mesh not found" };
22278
+ const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
22279
+ if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
22280
+ const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
22281
+ const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22282
+ const result = await createWorktree2({
22283
+ repoRoot,
22284
+ branch,
22285
+ baseBranch,
22286
+ meshName: mesh.name
22287
+ });
22288
+ let node;
22289
+ if (meshRecord.inline) {
22290
+ const { randomUUID: randomUUID8 } = await import("crypto");
22291
+ node = {
22292
+ id: `node_${randomUUID8().replace(/-/g, "")}`,
22293
+ workspace: result.worktreePath,
22294
+ repoRoot: result.worktreePath,
22295
+ daemonId: sourceNode.daemonId,
22296
+ userOverrides: { ...sourceNode.userOverrides || {} },
22297
+ policy: { ...sourceNode.policy || {} },
22298
+ isLocalWorktree: true,
22299
+ worktreeBranch: result.branch,
22300
+ clonedFromNodeId: sourceNodeId
22301
+ };
22302
+ this.updateInlineMeshNode(meshId, mesh, node);
22303
+ } else {
22304
+ const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22305
+ node = addNode3(meshId, {
22306
+ workspace: result.worktreePath,
22307
+ repoRoot: result.worktreePath,
22308
+ daemonId: sourceNode.daemonId,
22309
+ userOverrides: { ...sourceNode.userOverrides || {} },
22310
+ isLocalWorktree: true,
22311
+ worktreeBranch: result.branch,
22312
+ clonedFromNodeId: sourceNodeId,
22313
+ policy: { ...sourceNode.policy || {} }
22314
+ });
22315
+ if (!node) return { success: false, error: "Failed to register worktree node" };
22316
+ }
22317
+ return {
22318
+ success: true,
22319
+ node,
22320
+ worktreePath: result.worktreePath,
22321
+ branch: result.branch
22322
+ };
21419
22323
  } catch (e) {
21420
22324
  return { success: false, error: e.message };
21421
22325
  }
@@ -21423,7 +22327,7 @@ var DaemonCommandRouter = class {
21423
22327
  // ─── Mesh Coordinator Launch ───
21424
22328
  case "launch_mesh_coordinator": {
21425
22329
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21426
- const cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "claude-cli";
22330
+ let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
21427
22331
  if (!meshId) return { success: false, error: "meshId required" };
21428
22332
  try {
21429
22333
  const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
@@ -21451,9 +22355,29 @@ var DaemonCommandRouter = class {
21451
22355
  }
21452
22356
  const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
21453
22357
  if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
22358
+ if (!cliType) {
22359
+ const resolved = await resolveProviderTypeFromPriority({
22360
+ nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
22361
+ providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
22362
+ providerLoader: this.deps.providerLoader,
22363
+ onStatusChange: this.deps.onStatusChange
22364
+ });
22365
+ if (!resolved.providerType) {
22366
+ return {
22367
+ success: false,
22368
+ code: "mesh_coordinator_provider_priority_unusable",
22369
+ error: resolved.error || "No usable provider found from node providerPriority",
22370
+ meshId,
22371
+ cliType,
22372
+ workspace
22373
+ };
22374
+ }
22375
+ cliType = resolved.providerType;
22376
+ }
21454
22377
  const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
21455
22378
  const coordinatorSetup = resolveMeshCoordinatorSetup({
21456
22379
  provider: providerMeta,
22380
+ cliType,
21457
22381
  meshId,
21458
22382
  workspace
21459
22383
  });
@@ -21478,7 +22402,8 @@ var DaemonCommandRouter = class {
21478
22402
  meshCoordinatorSetup: coordinatorSetup
21479
22403
  };
21480
22404
  }
21481
- if (coordinatorSetup.configFormat !== "claude_mcp_json") {
22405
+ const configFormat = coordinatorSetup.configFormat;
22406
+ if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
21482
22407
  return {
21483
22408
  success: false,
21484
22409
  code: "mesh_coordinator_unsupported",
@@ -21488,44 +22413,93 @@ var DaemonCommandRouter = class {
21488
22413
  workspace
21489
22414
  };
21490
22415
  }
21491
- const { existsSync: existsSync22, readFileSync: readFileSync15, writeFileSync: writeFileSync12, copyFileSync: copyFileSync3 } = await import("fs");
21492
- const mcpConfigPath = coordinatorSetup.configPath;
21493
- const hadExistingMcpConfig = existsSync22(mcpConfigPath);
21494
- let existingMcpConfig = {};
21495
- if (hadExistingMcpConfig) {
21496
- try {
21497
- existingMcpConfig = JSON.parse(readFileSync15(mcpConfigPath, "utf-8"));
21498
- copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
21499
- } catch {
21500
- }
22416
+ let systemPrompt = "";
22417
+ try {
22418
+ systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
22419
+ } catch (error) {
22420
+ const message = error?.message || String(error);
22421
+ LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
22422
+ return {
22423
+ success: false,
22424
+ code: "mesh_coordinator_prompt_failed",
22425
+ error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
22426
+ meshId,
22427
+ cliType,
22428
+ workspace
22429
+ };
21501
22430
  }
22431
+ const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
22432
+ const { dirname: dirname9 } = await import("path");
22433
+ const mcpConfigPath = coordinatorSetup.configPath;
22434
+ const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
22435
+ const returnManualFallback = (message) => ({
22436
+ success: false,
22437
+ code: "mesh_coordinator_manual_mcp_setup_required",
22438
+ error: message,
22439
+ meshId,
22440
+ cliType,
22441
+ workspace,
22442
+ meshCoordinatorSetup: hermesManualFallback
22443
+ });
21502
22444
  const mcpServerEntry = {
21503
22445
  command: coordinatorSetup.mcpServer.command,
21504
22446
  args: coordinatorSetup.mcpServer.args
21505
22447
  };
21506
22448
  if (args?.inlineMesh) {
21507
22449
  mcpServerEntry.env = {
21508
- ADHDEV_INLINE_MESH: JSON.stringify(mesh)
22450
+ ADHDEV_INLINE_MESH: JSON.stringify(mesh),
22451
+ ADHDEV_MCP_TRANSPORT: "ipc"
21509
22452
  };
21510
22453
  }
22454
+ try {
22455
+ mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
22456
+ } catch (error) {
22457
+ const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
22458
+ LOG.error("MeshCoordinator", message);
22459
+ if (hermesManualFallback) return returnManualFallback(message);
22460
+ return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
22461
+ }
22462
+ const hadExistingMcpConfig = existsSync23(mcpConfigPath);
22463
+ let existingMcpConfig = {};
22464
+ if (hadExistingMcpConfig) {
22465
+ try {
22466
+ existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
22467
+ copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
22468
+ } catch (error) {
22469
+ LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
22470
+ return {
22471
+ success: false,
22472
+ code: "mesh_coordinator_config_parse_failed",
22473
+ error: `Failed to parse existing MCP config at ${mcpConfigPath}`
22474
+ };
22475
+ }
22476
+ }
22477
+ const mcpServersKey = getMcpServersKey(configFormat);
22478
+ const existingServers = existingMcpConfig[mcpServersKey];
21511
22479
  const mcpConfig = {
21512
22480
  ...existingMcpConfig,
21513
- mcpServers: {
21514
- ...existingMcpConfig.mcpServers || {},
22481
+ [mcpServersKey]: {
22482
+ ...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
21515
22483
  [coordinatorSetup.serverName]: mcpServerEntry
21516
22484
  }
21517
22485
  };
21518
- writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
21519
- LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
21520
- let systemPrompt = "";
21521
22486
  try {
21522
- systemPrompt = buildCoordinatorSystemPrompt2({ mesh });
21523
- } catch {
21524
- systemPrompt = `You are a Repo Mesh Coordinator for "${mesh.name}". Use the adhdev-mesh MCP tools (mesh_status, mesh_list_nodes, mesh_send_task, mesh_read_chat, mesh_launch_session, etc.) to orchestrate work across ${mesh.nodes.length} node(s).`;
22487
+ writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
22488
+ } catch (error) {
22489
+ const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
22490
+ LOG.error("MeshCoordinator", message);
22491
+ if (hermesManualFallback) return returnManualFallback(message);
22492
+ return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
21525
22493
  }
22494
+ LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
21526
22495
  const cliArgs = [];
22496
+ const launchEnv = {};
21527
22497
  if (systemPrompt) {
21528
- cliArgs.push("--append-system-prompt", systemPrompt);
22498
+ if (configFormat === "hermes_config_yaml") {
22499
+ launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
22500
+ } else {
22501
+ cliArgs.push("--append-system-prompt", systemPrompt);
22502
+ }
21529
22503
  }
21530
22504
  if (cliType === "claude-cli") {
21531
22505
  cliArgs.push("--mcp-config", coordinatorSetup.configPath);
@@ -21534,6 +22508,7 @@ var DaemonCommandRouter = class {
21534
22508
  cliType,
21535
22509
  dir: workspace,
21536
22510
  cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
22511
+ env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
21537
22512
  settings: {
21538
22513
  meshCoordinatorFor: meshId
21539
22514
  }
@@ -21713,6 +22688,12 @@ var DaemonStatusReporter = class {
21713
22688
  if (providerType) {
21714
22689
  payload.providerType = providerType;
21715
22690
  }
22691
+ if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
22692
+ payload.providerSessionId = event.providerSessionId.trim();
22693
+ }
22694
+ if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
22695
+ payload.workspaceName = event.workspaceName.trim();
22696
+ }
21716
22697
  if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
21717
22698
  payload.duration = event.duration;
21718
22699
  }
@@ -22960,7 +23941,10 @@ var ProviderInstanceManager = class {
22960
23941
  this.instances.get(id).dispose();
22961
23942
  }
22962
23943
  this.instances.set(id, instance);
22963
- await instance.init(context);
23944
+ await instance.init({
23945
+ ...context,
23946
+ emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
23947
+ });
22964
23948
  }
22965
23949
  /**
22966
23950
  * Instance remove
@@ -23122,6 +24106,17 @@ var ProviderInstanceManager = class {
23122
24106
  onEvent(listener) {
23123
24107
  this.eventListeners.push(listener);
23124
24108
  }
24109
+ emitProviderEvent(providerType, instanceId, event) {
24110
+ const payload = {
24111
+ ...event,
24112
+ providerType,
24113
+ instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
24114
+ targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
24115
+ };
24116
+ for (const listener of this.eventListeners) {
24117
+ listener(payload);
24118
+ }
24119
+ }
23125
24120
  emitPendingEvents(providerType, state, extra = {}) {
23126
24121
  for (const event of state.pendingEvents) {
23127
24122
  for (const listener of this.eventListeners) {
@@ -23194,11 +24189,11 @@ var ProviderInstanceManager = class {
23194
24189
 
23195
24190
  // src/providers/version-archive.ts
23196
24191
  import * as fs11 from "fs";
23197
- import * as path21 from "path";
23198
- import * as os19 from "os";
24192
+ import * as path22 from "path";
24193
+ import * as os20 from "os";
23199
24194
  import { execSync as execSync5 } from "child_process";
23200
24195
  import { platform as platform8 } from "os";
23201
- var ARCHIVE_PATH = path21.join(os19.homedir(), ".adhdev", "version-history.json");
24196
+ var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
23202
24197
  var MAX_ENTRIES_PER_PROVIDER = 20;
23203
24198
  var VersionArchive = class {
23204
24199
  history = {};
@@ -23245,7 +24240,7 @@ var VersionArchive = class {
23245
24240
  }
23246
24241
  save() {
23247
24242
  try {
23248
- fs11.mkdirSync(path21.dirname(ARCHIVE_PATH), { recursive: true });
24243
+ fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
23249
24244
  fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
23250
24245
  } catch {
23251
24246
  }
@@ -23301,8 +24296,8 @@ function getVersion(binary, versionCommand) {
23301
24296
  function checkPathExists2(paths) {
23302
24297
  for (const p of paths) {
23303
24298
  if (p.includes("*")) {
23304
- const home = os19.homedir();
23305
- const resolved = p.replace(/\*/g, home.split(path21.sep).pop() || "");
24299
+ const home = os20.homedir();
24300
+ const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
23306
24301
  if (fs11.existsSync(resolved)) return resolved;
23307
24302
  } else {
23308
24303
  if (fs11.existsSync(p)) return p;
@@ -23312,7 +24307,7 @@ function checkPathExists2(paths) {
23312
24307
  }
23313
24308
  function getMacAppVersion(appPath) {
23314
24309
  if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
23315
- const plistPath = path21.join(appPath, "Contents", "Info.plist");
24310
+ const plistPath = path22.join(appPath, "Contents", "Info.plist");
23316
24311
  if (!fs11.existsSync(plistPath)) return null;
23317
24312
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
23318
24313
  return raw || null;
@@ -23338,7 +24333,7 @@ async function detectAllVersions(loader, archive) {
23338
24333
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
23339
24334
  let resolvedBin = cliBin;
23340
24335
  if (!resolvedBin && appPath && currentOs === "darwin") {
23341
- const bundled = path21.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
24336
+ const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
23342
24337
  if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
23343
24338
  }
23344
24339
  info.installed = !!(appPath || resolvedBin);
@@ -23379,7 +24374,7 @@ async function detectAllVersions(loader, archive) {
23379
24374
  // src/daemon/dev-server.ts
23380
24375
  import * as http2 from "http";
23381
24376
  import * as fs15 from "fs";
23382
- import * as path25 from "path";
24377
+ import * as path26 from "path";
23383
24378
  init_config();
23384
24379
 
23385
24380
  // src/daemon/scaffold-template.ts
@@ -23731,7 +24726,7 @@ init_logger();
23731
24726
  // src/daemon/dev-cdp-handlers.ts
23732
24727
  init_logger();
23733
24728
  import * as fs12 from "fs";
23734
- import * as path22 from "path";
24729
+ import * as path23 from "path";
23735
24730
  async function handleCdpEvaluate(ctx, req, res) {
23736
24731
  const body = await ctx.readBody(req);
23737
24732
  const { expression, timeout, ideType } = body;
@@ -23909,17 +24904,17 @@ async function handleScriptHints(ctx, type, _req, res) {
23909
24904
  return;
23910
24905
  }
23911
24906
  let scriptsPath = "";
23912
- const directScripts = path22.join(dir, "scripts.js");
24907
+ const directScripts = path23.join(dir, "scripts.js");
23913
24908
  if (fs12.existsSync(directScripts)) {
23914
24909
  scriptsPath = directScripts;
23915
24910
  } else {
23916
- const scriptsDir = path22.join(dir, "scripts");
24911
+ const scriptsDir = path23.join(dir, "scripts");
23917
24912
  if (fs12.existsSync(scriptsDir)) {
23918
24913
  const versions = fs12.readdirSync(scriptsDir).filter((d) => {
23919
- return fs12.statSync(path22.join(scriptsDir, d)).isDirectory();
24914
+ return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
23920
24915
  }).sort().reverse();
23921
24916
  for (const ver of versions) {
23922
- const p = path22.join(scriptsDir, ver, "scripts.js");
24917
+ const p = path23.join(scriptsDir, ver, "scripts.js");
23923
24918
  if (fs12.existsSync(p)) {
23924
24919
  scriptsPath = p;
23925
24920
  break;
@@ -24748,7 +25743,7 @@ async function handleDomContext(ctx, type, req, res) {
24748
25743
 
24749
25744
  // src/daemon/dev-cli-debug.ts
24750
25745
  import * as fs13 from "fs";
24751
- import * as path23 from "path";
25746
+ import * as path24 from "path";
24752
25747
  function slugifyFixtureName(value) {
24753
25748
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
24754
25749
  return normalized || `fixture-${Date.now()}`;
@@ -24758,11 +25753,11 @@ function getCliFixtureDir(ctx, type) {
24758
25753
  if (!providerDir) {
24759
25754
  throw new Error(`Provider directory not found for '${type}'`);
24760
25755
  }
24761
- return path23.join(providerDir, "fixtures");
25756
+ return path24.join(providerDir, "fixtures");
24762
25757
  }
24763
25758
  function readCliFixture(ctx, type, name) {
24764
25759
  const fixtureDir = getCliFixtureDir(ctx, type);
24765
- const filePath = path23.join(fixtureDir, `${name}.json`);
25760
+ const filePath = path24.join(fixtureDir, `${name}.json`);
24766
25761
  if (!fs13.existsSync(filePath)) {
24767
25762
  throw new Error(`Fixture not found: ${filePath}`);
24768
25763
  }
@@ -24930,7 +25925,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
24930
25925
  if (!adapter) return null;
24931
25926
  return { target, instance, adapter };
24932
25927
  }
24933
- function sleep(ms) {
25928
+ function sleep2(ms) {
24934
25929
  return new Promise((resolve16) => setTimeout(resolve16, ms));
24935
25930
  }
24936
25931
  async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
@@ -24947,7 +25942,7 @@ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
24947
25942
  return bundle;
24948
25943
  }
24949
25944
  }
24950
- await sleep(100);
25945
+ await sleep2(100);
24951
25946
  }
24952
25947
  return getCliTargetBundle(ctx, type, instanceId);
24953
25948
  }
@@ -25003,7 +25998,7 @@ async function runCliExerciseInternal(ctx, body) {
25003
25998
  const message = String(lastLaunchError.message || "");
25004
25999
  const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
25005
26000
  if (!retryable || attempt === 2) break;
25006
- await sleep(1e3);
26001
+ await sleep2(1e3);
25007
26002
  }
25008
26003
  }
25009
26004
  if (!launched) {
@@ -25066,16 +26061,16 @@ async function runCliExerciseInternal(ctx, body) {
25066
26061
  const modal = debug?.activeModal || trace?.activeModal || null;
25067
26062
  noteStatus(status);
25068
26063
  if (resolveActiveModalIfNeeded(status, modal)) {
25069
- await sleep(150);
26064
+ await sleep2(150);
25070
26065
  continue;
25071
26066
  }
25072
26067
  const startupParseGate = !!debug?.startupParseGate;
25073
26068
  if (status === "idle" && !startupParseGate) break;
25074
- await sleep(150);
26069
+ await sleep2(150);
25075
26070
  }
25076
26071
  ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
25077
26072
  while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
25078
- await sleep(150);
26073
+ await sleep2(150);
25079
26074
  bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
25080
26075
  if (!bundle) {
25081
26076
  throw new Error("CLI instance disappeared during exercise");
@@ -25529,7 +26524,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
25529
26524
  },
25530
26525
  notes: typeof body?.notes === "string" ? body.notes : void 0
25531
26526
  };
25532
- const filePath = path23.join(fixtureDir, `${name}.json`);
26527
+ const filePath = path24.join(fixtureDir, `${name}.json`);
25533
26528
  fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
25534
26529
  ctx.json(res, 200, {
25535
26530
  saved: true,
@@ -25553,7 +26548,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
25553
26548
  return;
25554
26549
  }
25555
26550
  const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
25556
- const fullPath = path23.join(fixtureDir, file);
26551
+ const fullPath = path24.join(fixtureDir, file);
25557
26552
  try {
25558
26553
  const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
25559
26554
  return {
@@ -25689,8 +26684,8 @@ async function handleCliRaw(ctx, req, res) {
25689
26684
 
25690
26685
  // src/daemon/dev-auto-implement.ts
25691
26686
  import * as fs14 from "fs";
25692
- import * as path24 from "path";
25693
- import * as os20 from "os";
26687
+ import * as path25 from "path";
26688
+ import * as os21 from "os";
25694
26689
  function getAutoImplPid(ctx) {
25695
26690
  const pid = ctx.autoImplProcess?.pid;
25696
26691
  return typeof pid === "number" && pid > 0 ? pid : null;
@@ -25739,22 +26734,22 @@ function getLatestScriptVersionDir(scriptsDir) {
25739
26734
  if (!fs14.existsSync(scriptsDir)) return null;
25740
26735
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
25741
26736
  try {
25742
- return fs14.statSync(path24.join(scriptsDir, d)).isDirectory();
26737
+ return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
25743
26738
  } catch {
25744
26739
  return false;
25745
26740
  }
25746
26741
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
25747
26742
  if (versions.length === 0) return null;
25748
- return path24.join(scriptsDir, versions[0]);
26743
+ return path25.join(scriptsDir, versions[0]);
25749
26744
  }
25750
26745
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
25751
- const canonicalUserDir = path24.resolve(ctx.providerLoader.getUserProviderDir(category, type));
25752
- const desiredDir = requestedDir ? path24.resolve(requestedDir) : canonicalUserDir;
25753
- const upstreamRoot = path24.resolve(ctx.providerLoader.getUpstreamDir());
25754
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path24.sep}`)) {
26746
+ const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
26747
+ const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
26748
+ const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
26749
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
25755
26750
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
25756
26751
  }
25757
- if (path24.basename(desiredDir) !== type) {
26752
+ if (path25.basename(desiredDir) !== type) {
25758
26753
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
25759
26754
  }
25760
26755
  const sourceDir = ctx.findProviderDir(type);
@@ -25762,11 +26757,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
25762
26757
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
25763
26758
  }
25764
26759
  if (!fs14.existsSync(desiredDir)) {
25765
- fs14.mkdirSync(path24.dirname(desiredDir), { recursive: true });
26760
+ fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
25766
26761
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
25767
26762
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
25768
26763
  }
25769
- const providerJson = path24.join(desiredDir, "provider.json");
26764
+ const providerJson = path25.join(desiredDir, "provider.json");
25770
26765
  if (!fs14.existsSync(providerJson)) {
25771
26766
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
25772
26767
  }
@@ -25777,13 +26772,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
25777
26772
  const refDir = ctx.findProviderDir(referenceType);
25778
26773
  if (!refDir || !fs14.existsSync(refDir)) return {};
25779
26774
  const referenceScripts = {};
25780
- const scriptsDir = path24.join(refDir, "scripts");
26775
+ const scriptsDir = path25.join(refDir, "scripts");
25781
26776
  const latestDir = getLatestScriptVersionDir(scriptsDir);
25782
26777
  if (!latestDir) return referenceScripts;
25783
26778
  for (const file of fs14.readdirSync(latestDir)) {
25784
26779
  if (!file.endsWith(".js")) continue;
25785
26780
  try {
25786
- referenceScripts[file] = fs14.readFileSync(path24.join(latestDir, file), "utf-8");
26781
+ referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
25787
26782
  } catch {
25788
26783
  }
25789
26784
  }
@@ -25891,9 +26886,9 @@ async function handleAutoImplement(ctx, type, req, res) {
25891
26886
  });
25892
26887
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
25893
26888
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
25894
- const tmpDir = path24.join(os20.tmpdir(), "adhdev-autoimpl");
26889
+ const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
25895
26890
  if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
25896
- const promptFile = path24.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
26891
+ const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
25897
26892
  fs14.writeFileSync(promptFile, prompt, "utf-8");
25898
26893
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
25899
26894
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -26046,7 +27041,7 @@ async function handleAutoImplement(ctx, type, req, res) {
26046
27041
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
26047
27042
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
26048
27043
  let shellCmd;
26049
- const isWin = os20.platform() === "win32";
27044
+ const isWin = os21.platform() === "win32";
26050
27045
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
26051
27046
  const promptMode = autoImpl?.promptMode ?? "stdin";
26052
27047
  const extraArgs = autoImpl?.extraArgs ?? [];
@@ -26085,7 +27080,7 @@ async function handleAutoImplement(ctx, type, req, res) {
26085
27080
  try {
26086
27081
  const pty = __require("node-pty");
26087
27082
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
26088
- const isWin2 = os20.platform() === "win32";
27083
+ const isWin2 = os21.platform() === "win32";
26089
27084
  child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
26090
27085
  name: "xterm-256color",
26091
27086
  cols: 120,
@@ -26325,7 +27320,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26325
27320
  setMode: "set_mode.js"
26326
27321
  };
26327
27322
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26328
- const scriptsDir = path24.join(providerDir, "scripts");
27323
+ const scriptsDir = path25.join(providerDir, "scripts");
26329
27324
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
26330
27325
  if (latestScriptsDir) {
26331
27326
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26336,7 +27331,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26336
27331
  for (const file of fs14.readdirSync(latestScriptsDir)) {
26337
27332
  if (file.endsWith(".js") && targetFileNames.has(file)) {
26338
27333
  try {
26339
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27334
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26340
27335
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26341
27336
  lines.push("```javascript");
26342
27337
  lines.push(content);
@@ -26353,7 +27348,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26353
27348
  lines.push("");
26354
27349
  for (const file of refFiles) {
26355
27350
  try {
26356
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27351
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26357
27352
  lines.push(`### \`${file}\` \u{1F512}`);
26358
27353
  lines.push("```javascript");
26359
27354
  lines.push(content);
@@ -26394,10 +27389,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26394
27389
  lines.push("");
26395
27390
  }
26396
27391
  }
26397
- const docsDir = path24.join(providerDir, "../../docs");
27392
+ const docsDir = path25.join(providerDir, "../../docs");
26398
27393
  const loadGuide = (name) => {
26399
27394
  try {
26400
- const p = path24.join(docsDir, name);
27395
+ const p = path25.join(docsDir, name);
26401
27396
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
26402
27397
  } catch {
26403
27398
  }
@@ -26634,7 +27629,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26634
27629
  parseApproval: "parse_approval.js"
26635
27630
  };
26636
27631
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26637
- const scriptsDir = path24.join(providerDir, "scripts");
27632
+ const scriptsDir = path25.join(providerDir, "scripts");
26638
27633
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
26639
27634
  if (latestScriptsDir) {
26640
27635
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26646,7 +27641,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26646
27641
  if (!file.endsWith(".js")) continue;
26647
27642
  if (!targetFileNames.has(file)) continue;
26648
27643
  try {
26649
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27644
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26650
27645
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26651
27646
  lines.push("```javascript");
26652
27647
  lines.push(content);
@@ -26662,7 +27657,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26662
27657
  lines.push("");
26663
27658
  for (const file of refFiles) {
26664
27659
  try {
26665
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27660
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26666
27661
  lines.push(`### \`${file}\` \u{1F512}`);
26667
27662
  lines.push("```javascript");
26668
27663
  lines.push(content);
@@ -26695,10 +27690,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26695
27690
  lines.push("");
26696
27691
  }
26697
27692
  }
26698
- const docsDir = path24.join(providerDir, "../../docs");
27693
+ const docsDir = path25.join(providerDir, "../../docs");
26699
27694
  const loadGuide = (name) => {
26700
27695
  try {
26701
- const p = path24.join(docsDir, name);
27696
+ const p = path25.join(docsDir, name);
26702
27697
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
26703
27698
  } catch {
26704
27699
  }
@@ -27145,8 +28140,8 @@ var DevServer = class _DevServer {
27145
28140
  }
27146
28141
  getEndpointList() {
27147
28142
  return this.routes.map((r) => {
27148
- const path26 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
27149
- return `${r.method.padEnd(5)} ${path26}`;
28143
+ const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
28144
+ return `${r.method.padEnd(5)} ${path27}`;
27150
28145
  });
27151
28146
  }
27152
28147
  async start(port = DEV_SERVER_PORT) {
@@ -27434,12 +28429,12 @@ var DevServer = class _DevServer {
27434
28429
  // ─── DevConsole SPA ───
27435
28430
  getConsoleDistDir() {
27436
28431
  const candidates = [
27437
- path25.resolve(__dirname, "../../web-devconsole/dist"),
27438
- path25.resolve(__dirname, "../../../web-devconsole/dist"),
27439
- path25.join(process.cwd(), "packages/web-devconsole/dist")
28432
+ path26.resolve(__dirname, "../../web-devconsole/dist"),
28433
+ path26.resolve(__dirname, "../../../web-devconsole/dist"),
28434
+ path26.join(process.cwd(), "packages/web-devconsole/dist")
27440
28435
  ];
27441
28436
  for (const dir of candidates) {
27442
- if (fs15.existsSync(path25.join(dir, "index.html"))) return dir;
28437
+ if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
27443
28438
  }
27444
28439
  return null;
27445
28440
  }
@@ -27449,7 +28444,7 @@ var DevServer = class _DevServer {
27449
28444
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
27450
28445
  return;
27451
28446
  }
27452
- const htmlPath = path25.join(distDir, "index.html");
28447
+ const htmlPath = path26.join(distDir, "index.html");
27453
28448
  try {
27454
28449
  const html = fs15.readFileSync(htmlPath, "utf-8");
27455
28450
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -27474,15 +28469,15 @@ var DevServer = class _DevServer {
27474
28469
  this.json(res, 404, { error: "Not found" });
27475
28470
  return;
27476
28471
  }
27477
- const safePath = path25.normalize(pathname).replace(/^\.\.\//, "");
27478
- const filePath = path25.join(distDir, safePath);
28472
+ const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
28473
+ const filePath = path26.join(distDir, safePath);
27479
28474
  if (!filePath.startsWith(distDir)) {
27480
28475
  this.json(res, 403, { error: "Forbidden" });
27481
28476
  return;
27482
28477
  }
27483
28478
  try {
27484
28479
  const content = fs15.readFileSync(filePath);
27485
- const ext = path25.extname(filePath);
28480
+ const ext = path26.extname(filePath);
27486
28481
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
27487
28482
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
27488
28483
  res.end(content);
@@ -27595,9 +28590,9 @@ var DevServer = class _DevServer {
27595
28590
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
27596
28591
  if (entry.isDirectory()) {
27597
28592
  files.push({ path: rel, size: 0, type: "dir" });
27598
- scan(path25.join(d, entry.name), rel);
28593
+ scan(path26.join(d, entry.name), rel);
27599
28594
  } else {
27600
- const stat2 = fs15.statSync(path25.join(d, entry.name));
28595
+ const stat2 = fs15.statSync(path26.join(d, entry.name));
27601
28596
  files.push({ path: rel, size: stat2.size, type: "file" });
27602
28597
  }
27603
28598
  }
@@ -27620,7 +28615,7 @@ var DevServer = class _DevServer {
27620
28615
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
27621
28616
  return;
27622
28617
  }
27623
- const fullPath = path25.resolve(dir, path25.normalize(filePath));
28618
+ const fullPath = path26.resolve(dir, path26.normalize(filePath));
27624
28619
  if (!fullPath.startsWith(dir)) {
27625
28620
  this.json(res, 403, { error: "Forbidden" });
27626
28621
  return;
@@ -27645,14 +28640,14 @@ var DevServer = class _DevServer {
27645
28640
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
27646
28641
  return;
27647
28642
  }
27648
- const fullPath = path25.resolve(dir, path25.normalize(filePath));
28643
+ const fullPath = path26.resolve(dir, path26.normalize(filePath));
27649
28644
  if (!fullPath.startsWith(dir)) {
27650
28645
  this.json(res, 403, { error: "Forbidden" });
27651
28646
  return;
27652
28647
  }
27653
28648
  try {
27654
28649
  if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
27655
- fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
28650
+ fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
27656
28651
  fs15.writeFileSync(fullPath, content, "utf-8");
27657
28652
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
27658
28653
  this.providerLoader.reload();
@@ -27669,7 +28664,7 @@ var DevServer = class _DevServer {
27669
28664
  return;
27670
28665
  }
27671
28666
  for (const name of ["scripts.js", "provider.json"]) {
27672
- const p = path25.join(dir, name);
28667
+ const p = path26.join(dir, name);
27673
28668
  if (fs15.existsSync(p)) {
27674
28669
  const source = fs15.readFileSync(p, "utf-8");
27675
28670
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -27690,8 +28685,8 @@ var DevServer = class _DevServer {
27690
28685
  this.json(res, 404, { error: `Provider not found: ${type}` });
27691
28686
  return;
27692
28687
  }
27693
- const target = fs15.existsSync(path25.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
27694
- const targetPath = path25.join(dir, target);
28688
+ const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
28689
+ const targetPath = path26.join(dir, target);
27695
28690
  try {
27696
28691
  if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
27697
28692
  fs15.writeFileSync(targetPath, source, "utf-8");
@@ -27838,7 +28833,7 @@ var DevServer = class _DevServer {
27838
28833
  }
27839
28834
  let targetDir;
27840
28835
  targetDir = this.providerLoader.getUserProviderDir(category, type);
27841
- const jsonPath = path25.join(targetDir, "provider.json");
28836
+ const jsonPath = path26.join(targetDir, "provider.json");
27842
28837
  if (fs15.existsSync(jsonPath)) {
27843
28838
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
27844
28839
  return;
@@ -27850,8 +28845,8 @@ var DevServer = class _DevServer {
27850
28845
  const createdFiles = ["provider.json"];
27851
28846
  if (result.files) {
27852
28847
  for (const [relPath, content] of Object.entries(result.files)) {
27853
- const fullPath = path25.join(targetDir, relPath);
27854
- fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
28848
+ const fullPath = path26.join(targetDir, relPath);
28849
+ fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
27855
28850
  fs15.writeFileSync(fullPath, content, "utf-8");
27856
28851
  createdFiles.push(relPath);
27857
28852
  }
@@ -27904,22 +28899,22 @@ var DevServer = class _DevServer {
27904
28899
  if (!fs15.existsSync(scriptsDir)) return null;
27905
28900
  const versions = fs15.readdirSync(scriptsDir).filter((d) => {
27906
28901
  try {
27907
- return fs15.statSync(path25.join(scriptsDir, d)).isDirectory();
28902
+ return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
27908
28903
  } catch {
27909
28904
  return false;
27910
28905
  }
27911
28906
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
27912
28907
  if (versions.length === 0) return null;
27913
- return path25.join(scriptsDir, versions[0]);
28908
+ return path26.join(scriptsDir, versions[0]);
27914
28909
  }
27915
28910
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
27916
- const canonicalUserDir = path25.resolve(this.providerLoader.getUserProviderDir(category, type));
27917
- const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
27918
- const upstreamRoot = path25.resolve(this.providerLoader.getUpstreamDir());
27919
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
28911
+ const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
28912
+ const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
28913
+ const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
28914
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
27920
28915
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
27921
28916
  }
27922
- if (path25.basename(desiredDir) !== type) {
28917
+ if (path26.basename(desiredDir) !== type) {
27923
28918
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
27924
28919
  }
27925
28920
  const sourceDir = this.findProviderDir(type);
@@ -27927,11 +28922,11 @@ var DevServer = class _DevServer {
27927
28922
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
27928
28923
  }
27929
28924
  if (!fs15.existsSync(desiredDir)) {
27930
- fs15.mkdirSync(path25.dirname(desiredDir), { recursive: true });
28925
+ fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
27931
28926
  fs15.cpSync(sourceDir, desiredDir, { recursive: true });
27932
28927
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
27933
28928
  }
27934
- const providerJson = path25.join(desiredDir, "provider.json");
28929
+ const providerJson = path26.join(desiredDir, "provider.json");
27935
28930
  if (!fs15.existsSync(providerJson)) {
27936
28931
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
27937
28932
  }
@@ -27967,7 +28962,7 @@ var DevServer = class _DevServer {
27967
28962
  setMode: "set_mode.js"
27968
28963
  };
27969
28964
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
27970
- const scriptsDir = path25.join(providerDir, "scripts");
28965
+ const scriptsDir = path26.join(providerDir, "scripts");
27971
28966
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
27972
28967
  if (latestScriptsDir) {
27973
28968
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -27978,7 +28973,7 @@ var DevServer = class _DevServer {
27978
28973
  for (const file of fs15.readdirSync(latestScriptsDir)) {
27979
28974
  if (file.endsWith(".js") && targetFileNames.has(file)) {
27980
28975
  try {
27981
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
28976
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
27982
28977
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
27983
28978
  lines.push("```javascript");
27984
28979
  lines.push(content);
@@ -27995,7 +28990,7 @@ var DevServer = class _DevServer {
27995
28990
  lines.push("");
27996
28991
  for (const file of refFiles) {
27997
28992
  try {
27998
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
28993
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
27999
28994
  lines.push(`### \`${file}\` \u{1F512}`);
28000
28995
  lines.push("```javascript");
28001
28996
  lines.push(content);
@@ -28036,10 +29031,10 @@ var DevServer = class _DevServer {
28036
29031
  lines.push("");
28037
29032
  }
28038
29033
  }
28039
- const docsDir = path25.join(providerDir, "../../docs");
29034
+ const docsDir = path26.join(providerDir, "../../docs");
28040
29035
  const loadGuide = (name) => {
28041
29036
  try {
28042
- const p = path25.join(docsDir, name);
29037
+ const p = path26.join(docsDir, name);
28043
29038
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
28044
29039
  } catch {
28045
29040
  }
@@ -28213,7 +29208,7 @@ var DevServer = class _DevServer {
28213
29208
  parseApproval: "parse_approval.js"
28214
29209
  };
28215
29210
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
28216
- const scriptsDir = path25.join(providerDir, "scripts");
29211
+ const scriptsDir = path26.join(providerDir, "scripts");
28217
29212
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
28218
29213
  if (latestScriptsDir) {
28219
29214
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -28225,7 +29220,7 @@ var DevServer = class _DevServer {
28225
29220
  if (!file.endsWith(".js")) continue;
28226
29221
  if (!targetFileNames.has(file)) continue;
28227
29222
  try {
28228
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29223
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28229
29224
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
28230
29225
  lines.push("```javascript");
28231
29226
  lines.push(content);
@@ -28241,7 +29236,7 @@ var DevServer = class _DevServer {
28241
29236
  lines.push("");
28242
29237
  for (const file of refFiles) {
28243
29238
  try {
28244
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29239
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28245
29240
  lines.push(`### \`${file}\` \u{1F512}`);
28246
29241
  lines.push("```javascript");
28247
29242
  lines.push(content);
@@ -28274,10 +29269,10 @@ var DevServer = class _DevServer {
28274
29269
  lines.push("");
28275
29270
  }
28276
29271
  }
28277
- const docsDir = path25.join(providerDir, "../../docs");
29272
+ const docsDir = path26.join(providerDir, "../../docs");
28278
29273
  const loadGuide = (name) => {
28279
29274
  try {
28280
- const p = path25.join(docsDir, name);
29275
+ const p = path26.join(docsDir, name);
28281
29276
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
28282
29277
  } catch {
28283
29278
  }
@@ -29282,48 +30277,6 @@ var SessionRegistry = class {
29282
30277
  // src/boot/daemon-lifecycle.ts
29283
30278
  init_logger();
29284
30279
  init_config();
29285
-
29286
- // src/mesh/mesh-events.ts
29287
- init_mesh_config();
29288
- init_logger();
29289
- function setupMeshEventForwarding(components) {
29290
- components.instanceManager.onEvent((event) => {
29291
- if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
29292
- const instanceId = event.instanceId;
29293
- if (!instanceId) return;
29294
- const sourceInstance = components.instanceManager.getInstance(instanceId);
29295
- if (!sourceInstance || sourceInstance.category !== "cli") return;
29296
- const state = sourceInstance.getState();
29297
- const workspace = state.workspace;
29298
- if (!workspace) return;
29299
- const mesh = getMeshByRepo(workspace);
29300
- if (!mesh) return;
29301
- const allInstances = components.instanceManager.getByCategory("cli");
29302
- const coordinatorInstances = allInstances.filter((inst) => {
29303
- const instState = inst.getState();
29304
- if (instState.settings?.meshCoordinatorFor !== mesh.id) return false;
29305
- if (instState.instanceId === instanceId) return false;
29306
- return true;
29307
- });
29308
- if (coordinatorInstances.length === 0) return;
29309
- const targetNode = mesh.nodes.find((n) => n.workspace === workspace);
29310
- const nodeLabel = targetNode ? `Node '${targetNode.id}'` : `Agent at ${workspace}`;
29311
- let messageText = "";
29312
- if (event.event === "agent:generating_completed") {
29313
- messageText = `[System] ${nodeLabel} has completed its task and is now idle. You may use mesh_read_chat to review its progress.`;
29314
- } else if (event.event === "agent:waiting_approval") {
29315
- messageText = `[System] ${nodeLabel} is waiting for approval to proceed. You may use mesh_read_chat and mesh_approve to handle it.`;
29316
- }
29317
- if (!messageText) return;
29318
- for (const coord of coordinatorInstances) {
29319
- const coordState = coord.getState();
29320
- LOG.info("MeshEvents", `Forwarding event from ${workspace} to coordinator ${coordState.instanceId}`);
29321
- coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
29322
- }
29323
- });
29324
- }
29325
-
29326
- // src/boot/daemon-lifecycle.ts
29327
30280
  async function initDaemonComponents(config) {
29328
30281
  installGlobalInterceptor();
29329
30282
  const appConfig = loadConfig();
@@ -29629,6 +30582,7 @@ export {
29629
30582
  createGitWorkspaceMonitor,
29630
30583
  createInteractionId,
29631
30584
  createMesh,
30585
+ createWorktree,
29632
30586
  deleteMesh,
29633
30587
  detectAllVersions,
29634
30588
  detectCLIs,
@@ -29681,6 +30635,7 @@ export {
29681
30635
  launchWithCdp,
29682
30636
  listHostedCliRuntimes,
29683
30637
  listMeshes,
30638
+ listWorktrees,
29684
30639
  loadConfig,
29685
30640
  loadState,
29686
30641
  logCommand,
@@ -29700,6 +30655,7 @@ export {
29700
30655
  normalizeSessionModalFields,
29701
30656
  parsePorcelainV2Status,
29702
30657
  parseProviderSourceConfigUpdate,
30658
+ parseWorktreeListOutput,
29703
30659
  partitionSessionHostDiagnosticsSessions,
29704
30660
  partitionSessionHostRecords,
29705
30661
  prepareSessionChatTailUpdate,
@@ -29709,6 +30665,7 @@ export {
29709
30665
  recordDebugTrace,
29710
30666
  registerExtensionProviders,
29711
30667
  removeNode,
30668
+ removeWorktree,
29712
30669
  resetConfig,
29713
30670
  resetDebugRuntimeConfig,
29714
30671
  resetState,
@@ -29718,6 +30675,7 @@ export {
29718
30675
  resolveGitRepository,
29719
30676
  resolveSessionHostAppName,
29720
30677
  resolveSessionHostAppNameResolution,
30678
+ resolveWorktreePath,
29721
30679
  runAsyncBatch,
29722
30680
  runGit,
29723
30681
  saveConfig,