@adhdev/daemon-core 0.9.76-rc.6 → 0.9.76-rc.60

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 (53) 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.d.ts +2 -2
  11. package/dist/index.js +1525 -446
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +1550 -477
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/mesh/coordinator-prompt.d.ts +1 -0
  16. package/dist/mesh/mesh-events.d.ts +9 -0
  17. package/dist/providers/chat-message-normalization.d.ts +11 -0
  18. package/dist/providers/cli-provider-instance.d.ts +3 -0
  19. package/dist/providers/provider-instance-manager.d.ts +1 -0
  20. package/dist/providers/provider-instance.d.ts +2 -0
  21. package/dist/repo-mesh-types.d.ts +27 -0
  22. package/dist/session-host/runtime-support.d.ts +2 -1
  23. package/dist/shared-types.d.ts +4 -0
  24. package/dist/types.d.ts +9 -0
  25. package/package.json +4 -5
  26. package/src/cli-adapters/provider-cli-adapter.ts +28 -7
  27. package/src/cli-adapters/provider-cli-runtime.ts +3 -2
  28. package/src/commands/chat-commands.ts +126 -11
  29. package/src/commands/cli-manager.ts +78 -5
  30. package/src/commands/handler.ts +13 -4
  31. package/src/commands/mesh-coordinator.ts +148 -5
  32. package/src/commands/router.d.ts +1 -0
  33. package/src/commands/router.ts +553 -34
  34. package/src/config/mesh-config.ts +23 -2
  35. package/src/git/git-commands.ts +5 -1
  36. package/src/git/git-types.ts +1 -0
  37. package/src/git/git-worktree.ts +214 -0
  38. package/src/git/index.ts +14 -0
  39. package/src/index.ts +3 -0
  40. package/src/mesh/coordinator-prompt.ts +29 -14
  41. package/src/mesh/mesh-events.ts +109 -43
  42. package/src/providers/chat-message-normalization.ts +80 -0
  43. package/src/providers/cli-provider-instance.d.ts +2 -0
  44. package/src/providers/cli-provider-instance.ts +93 -8
  45. package/src/providers/provider-instance-manager.ts +20 -1
  46. package/src/providers/provider-instance.ts +2 -0
  47. package/src/providers/read-chat-contract.ts +8 -0
  48. package/src/repo-mesh-types.ts +30 -0
  49. package/src/session-host/runtime-support.ts +55 -7
  50. package/src/shared-types.ts +4 -0
  51. package/src/status/builders.ts +17 -12
  52. package/src/status/reporter.ts +6 -0
  53. package/src/types.ts +9 -0
package/dist/index.js CHANGED
@@ -41,11 +41,140 @@ var init_repo_mesh_types = __esm({
41
41
  requireApprovalForPush: true,
42
42
  requireApprovalForDestructiveGit: true,
43
43
  dirtyWorkspaceBehavior: "warn",
44
- maxParallelTasks: 2
44
+ maxParallelTasks: 2,
45
+ sessionCleanupOnNodeRemove: "preserve"
45
46
  };
46
47
  }
47
48
  });
48
49
 
50
+ // src/git/git-worktree.ts
51
+ var git_worktree_exports = {};
52
+ __export(git_worktree_exports, {
53
+ createWorktree: () => createWorktree,
54
+ listWorktrees: () => listWorktrees,
55
+ parseWorktreeListOutput: () => parseWorktreeListOutput,
56
+ removeWorktree: () => removeWorktree,
57
+ resolveWorktreePath: () => resolveWorktreePath
58
+ });
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 ((0, import_node_fs2.existsSync)(targetDir)) {
69
+ throw new Error(`Worktree target directory already exists: ${targetDir}`);
70
+ }
71
+ await (0, import_promises3.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 (!(0, import_node_fs2.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 path4, import_promises3, import_node_fs2, import_node_child_process2, import_node_util2, 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
+ path4 = __toESM(require("path"));
167
+ import_promises3 = require("fs/promises");
168
+ import_node_fs2 = require("fs");
169
+ import_node_child_process2 = require("child_process");
170
+ import_node_util2 = require("util");
171
+ execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
172
+ WORKTREE_DIR_NAME = ".adhdev-worktrees";
173
+ GIT_TIMEOUT_MS = 3e4;
174
+ GIT_MAX_BUFFER = 4 * 1024 * 1024;
175
+ }
176
+ });
177
+
49
178
  // src/config/config.ts
50
179
  var config_exports = {};
51
180
  __export(config_exports, {
@@ -304,10 +433,10 @@ function getMeshConfigPath() {
304
433
  return (0, import_path2.join)(getConfigDir(), "meshes.json");
305
434
  }
306
435
  function loadMeshConfig() {
307
- const path26 = getMeshConfigPath();
308
- if (!(0, import_fs2.existsSync)(path26)) return { meshes: [] };
436
+ const path27 = getMeshConfigPath();
437
+ if (!(0, import_fs2.existsSync)(path27)) return { meshes: [] };
309
438
  try {
310
- const raw = JSON.parse((0, import_fs2.readFileSync)(path26, "utf-8"));
439
+ const raw = JSON.parse((0, import_fs2.readFileSync)(path27, "utf-8"));
311
440
  if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
312
441
  return raw;
313
442
  } catch {
@@ -315,16 +444,16 @@ function loadMeshConfig() {
315
444
  }
316
445
  }
317
446
  function saveMeshConfig(config) {
318
- const path26 = getMeshConfigPath();
319
- (0, import_fs2.writeFileSync)(path26, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
447
+ const path27 = getMeshConfigPath();
448
+ (0, import_fs2.writeFileSync)(path27, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
320
449
  }
321
450
  function normalizeRepoIdentity(remoteUrl) {
322
451
  let identity = remoteUrl.trim();
323
452
  if (identity.startsWith("http://") || identity.startsWith("https://")) {
324
453
  try {
325
454
  const url = new URL(identity);
326
- const path26 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
327
- return `${url.hostname}/${path26}`;
455
+ const path27 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
456
+ return `${url.hostname}/${path27}`;
328
457
  } catch {
329
458
  }
330
459
  }
@@ -332,6 +461,18 @@ function normalizeRepoIdentity(remoteUrl) {
332
461
  if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
333
462
  return identity;
334
463
  }
464
+ function mergeMeshPolicy(base, patch) {
465
+ const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
466
+ if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
467
+ policy.dirtyWorkspaceBehavior = "warn";
468
+ }
469
+ const maxParallelTasks = Number(policy.maxParallelTasks);
470
+ policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
471
+ if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
472
+ policy.sessionCleanupOnNodeRemove = "preserve";
473
+ }
474
+ return policy;
475
+ }
335
476
  function listMeshes() {
336
477
  return loadMeshConfig().meshes;
337
478
  }
@@ -355,7 +496,7 @@ function createMesh(opts) {
355
496
  repoIdentity,
356
497
  repoRemoteUrl: opts.repoRemoteUrl,
357
498
  defaultBranch: opts.defaultBranch,
358
- policy: { ...DEFAULT_MESH_POLICY, ...opts.policy },
499
+ policy: mergeMeshPolicy(void 0, opts.policy),
359
500
  coordinator: opts.coordinator || {},
360
501
  nodes: [],
361
502
  createdAt: now,
@@ -371,7 +512,7 @@ function updateMesh(meshId, opts) {
371
512
  if (!mesh) return void 0;
372
513
  if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
373
514
  if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
374
- if (opts.policy) mesh.policy = { ...mesh.policy, ...opts.policy };
515
+ if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
375
516
  if (opts.coordinator) mesh.coordinator = opts.coordinator;
376
517
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
377
518
  saveMeshConfig(config);
@@ -399,9 +540,12 @@ function addNode(meshId, opts) {
399
540
  id: `node_${(0, import_crypto3.randomUUID)().replace(/-/g, "")}`,
400
541
  workspace: opts.workspace.trim(),
401
542
  repoRoot: opts.repoRoot,
543
+ daemonId: opts.daemonId,
402
544
  userOverrides: opts.userOverrides || {},
403
545
  policy: opts.policy || {},
404
- isLocalWorktree: opts.isLocalWorktree
546
+ isLocalWorktree: opts.isLocalWorktree,
547
+ worktreeBranch: opts.worktreeBranch,
548
+ clonedFromNodeId: opts.clonedFromNodeId
405
549
  };
406
550
  mesh.nodes.push(node);
407
551
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -431,7 +575,7 @@ function updateNode(meshId, nodeId, opts) {
431
575
  saveMeshConfig(config);
432
576
  return node;
433
577
  }
434
- var import_fs2, import_path2, import_crypto3;
578
+ var import_fs2, import_path2, import_crypto3, SESSION_CLEANUP_MODES;
435
579
  var init_mesh_config = __esm({
436
580
  "src/config/mesh-config.ts"() {
437
581
  "use strict";
@@ -440,6 +584,7 @@ var init_mesh_config = __esm({
440
584
  import_crypto3 = require("crypto");
441
585
  init_config();
442
586
  init_repo_mesh_types();
587
+ SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
443
588
  }
444
589
  });
445
590
 
@@ -449,7 +594,7 @@ __export(coordinator_prompt_exports, {
449
594
  buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
450
595
  });
451
596
  function buildCoordinatorSystemPrompt(ctx) {
452
- const { mesh, status, userInstruction } = ctx;
597
+ const { mesh, status, userInstruction, coordinatorCliType } = ctx;
453
598
  const sections = [];
454
599
  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.
455
600
 
@@ -463,15 +608,15 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
463
608
  } else {
464
609
  sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
465
610
  }
466
- sections.push(buildPolicySection(mesh.policy));
611
+ sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
467
612
  sections.push(TOOLS_SECTION);
468
613
  sections.push(WORKFLOW_SECTION);
469
- sections.push(RULES_SECTION);
614
+ sections.push(buildRulesSection(coordinatorCliType));
470
615
  if (userInstruction) {
471
616
  sections.push(`## Additional Context
472
617
  ${userInstruction}`);
473
618
  }
474
- if (mesh.coordinator.systemPromptSuffix) {
619
+ if (mesh.coordinator?.systemPromptSuffix) {
475
620
  sections.push(mesh.coordinator.systemPromptSuffix);
476
621
  }
477
622
  return sections.join("\n\n");
@@ -516,10 +661,29 @@ function buildPolicySection(policy) {
516
661
  return `## Policy
517
662
  ${rules.join("\n")}`;
518
663
  }
519
- var TOOLS_SECTION, WORKFLOW_SECTION, RULES_SECTION;
664
+ function buildRulesSection(coordinatorCliType) {
665
+ const coordinatorNote = coordinatorCliType ? `
666
+ - **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.` : "";
667
+ return `## Rules
668
+
669
+ - **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.
670
+ - **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.
671
+ - **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.
672
+ - **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.
673
+ - **Don't inspect code.** Treat delegated agent summaries as self-reports, not verification. Verify side effects via \`mesh_git_status\` (including related repo freshness when configured), not by reading source files.
674
+ - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed. Never launch a duplicate session or second worker solely because \`mesh_read_chat\` has no final assistant message while the delegated session is still showing tool/terminal activity.
675
+ - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
676
+ - **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
677
+ - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
678
+ - **Never fabricate tool results.** Always call the actual tool; never pretend you did.
679
+ - **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
680
+ - **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
681
+ }
682
+ var TOOLS_SECTION, WORKFLOW_SECTION;
520
683
  var init_coordinator_prompt = __esm({
521
684
  "src/mesh/coordinator-prompt.ts"() {
522
685
  "use strict";
686
+ init_repo_mesh_types();
523
687
  TOOLS_SECTION = `## Available Tools
524
688
 
525
689
  | Tool | Purpose |
@@ -531,30 +695,23 @@ var init_coordinator_prompt = __esm({
531
695
  | \`mesh_read_chat\` | Read an agent's recent messages to check progress |
532
696
  | \`mesh_git_status\` | Check git status on a specific node |
533
697
  | \`mesh_checkpoint\` | Create a git checkpoint on a node |
534
- | \`mesh_approve\` | Approve/reject a pending agent action |`;
698
+ | \`mesh_approve\` | Approve/reject a pending agent action |
699
+ | \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
700
+ | \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |`;
535
701
  WORKFLOW_SECTION = `## Orchestration Workflow
536
702
 
537
703
  1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
538
704
  2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
539
705
  3. **Delegate** \u2014 For each task:
540
706
  a. Pick the best node (consider: health, dirty state, current workload).
541
- b. If no session exists, call \`mesh_launch_session\` to start one.
542
- 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.
543
- 4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
544
- 5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
707
+ b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
708
+ c. If no session exists, call \`mesh_launch_session\` to start one.
709
+ 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.
710
+ 4. **Monitor** \u2014 Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly just because the delegated session has not produced a final assistant message yet; tool/terminal activity means work may still be in progress. Do not call \`mesh_read_chat\` again within a few seconds for the same generating session; wait for the completion callback/status event instead unless you are debugging a real stall. Use at most one compact \`mesh_read_chat\` check after a completion/approval signal, an explicit user status request, or a real timeout/stall. Handle approvals via \`mesh_approve\`.
711
+ 5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
545
712
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
546
- 7. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
547
- RULES_SECTION = `## Rules
548
-
549
- - **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.
550
- - **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.
551
- - **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.
552
- - **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
553
- - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
554
- - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
555
- - **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
556
- - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
557
- - **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
713
+ 7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
714
+ 8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
558
715
  }
559
716
  });
560
717
 
@@ -573,13 +730,13 @@ function getDaemonLogDir() {
573
730
  return LOG_DIR;
574
731
  }
575
732
  function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
576
- return path9.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
733
+ return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
577
734
  }
578
735
  function checkDateRotation() {
579
736
  const today = getDateStr();
580
737
  if (today !== currentDate) {
581
738
  currentDate = today;
582
- currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
739
+ currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
583
740
  cleanOldLogs();
584
741
  }
585
742
  }
@@ -593,7 +750,7 @@ function cleanOldLogs() {
593
750
  const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
594
751
  if (dateMatch && dateMatch[1] < cutoffStr) {
595
752
  try {
596
- fs2.unlinkSync(path9.join(LOG_DIR, file));
753
+ fs2.unlinkSync(path10.join(LOG_DIR, file));
597
754
  } catch {
598
755
  }
599
756
  }
@@ -709,17 +866,17 @@ function installGlobalInterceptor() {
709
866
  writeToFile(`Log file: ${currentLogFile}`);
710
867
  writeToFile(`Log level: ${currentLevel}`);
711
868
  }
712
- var fs2, path9, os4, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
869
+ var fs2, path10, os4, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
713
870
  var init_logger = __esm({
714
871
  "src/logging/logger.ts"() {
715
872
  "use strict";
716
873
  fs2 = __toESM(require("fs"));
717
- path9 = __toESM(require("path"));
874
+ path10 = __toESM(require("path"));
718
875
  os4 = __toESM(require("os"));
719
876
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
720
877
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
721
878
  currentLevel = "info";
722
- 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");
879
+ 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");
723
880
  MAX_LOG_SIZE = 5 * 1024 * 1024;
724
881
  MAX_LOG_DAYS = 7;
725
882
  try {
@@ -727,16 +884,16 @@ var init_logger = __esm({
727
884
  } catch {
728
885
  }
729
886
  currentDate = getDateStr();
730
- currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
887
+ currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
731
888
  cleanOldLogs();
732
889
  try {
733
- const oldLog = path9.join(LOG_DIR, "daemon.log");
890
+ const oldLog = path10.join(LOG_DIR, "daemon.log");
734
891
  if (fs2.existsSync(oldLog)) {
735
892
  const stat2 = fs2.statSync(oldLog);
736
893
  const oldDate = stat2.mtime.toISOString().slice(0, 10);
737
- fs2.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
894
+ fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
738
895
  }
739
- const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
896
+ const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
740
897
  if (fs2.existsSync(oldLogBackup)) {
741
898
  fs2.unlinkSync(oldLogBackup);
742
899
  }
@@ -768,7 +925,7 @@ var init_logger = __esm({
768
925
  }
769
926
  };
770
927
  interceptorInstalled = false;
771
- LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
928
+ LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
772
929
  }
773
930
  });
774
931
 
@@ -1236,9 +1393,9 @@ function buildCliScreenSnapshot(text) {
1236
1393
  function findBinary(name) {
1237
1394
  const trimmed = String(name || "").trim();
1238
1395
  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);
1396
+ const expanded = trimmed.startsWith("~") ? path14.join(os9.homedir(), trimmed.slice(1)) : trimmed;
1397
+ if (path14.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
1398
+ return path14.isAbsolute(expanded) ? expanded : path14.resolve(expanded);
1242
1399
  }
1243
1400
  const isWin = os9.platform() === "win32";
1244
1401
  try {
@@ -1254,7 +1411,7 @@ function findBinary(name) {
1254
1411
  }
1255
1412
  }
1256
1413
  function isScriptBinary(binaryPath) {
1257
- if (!path13.isAbsolute(binaryPath)) return false;
1414
+ if (!path14.isAbsolute(binaryPath)) return false;
1258
1415
  try {
1259
1416
  const fs16 = require("fs");
1260
1417
  const resolved = fs16.realpathSync(binaryPath);
@@ -1270,7 +1427,7 @@ function isScriptBinary(binaryPath) {
1270
1427
  }
1271
1428
  }
1272
1429
  function looksLikeMachOOrElf(filePath) {
1273
- if (!path13.isAbsolute(filePath)) return false;
1430
+ if (!path14.isAbsolute(filePath)) return false;
1274
1431
  try {
1275
1432
  const fs16 = require("fs");
1276
1433
  const resolved = fs16.realpathSync(filePath);
@@ -1359,12 +1516,12 @@ function normalizeCliProviderForRuntime(raw) {
1359
1516
  }
1360
1517
  };
1361
1518
  }
1362
- var os9, path13, import_child_process4, buildCliSpawnEnv;
1519
+ var os9, path14, import_child_process4, buildCliSpawnEnv;
1363
1520
  var init_provider_cli_shared = __esm({
1364
1521
  "src/cli-adapters/provider-cli-shared.ts"() {
1365
1522
  "use strict";
1366
1523
  os9 = __toESM(require("os"));
1367
- path13 = __toESM(require("path"));
1524
+ path14 = __toESM(require("path"));
1368
1525
  import_child_process4 = require("child_process");
1369
1526
  init_spawn_env();
1370
1527
  buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
@@ -1487,7 +1644,7 @@ var init_provider_cli_config = __esm({
1487
1644
 
1488
1645
  // src/cli-adapters/provider-cli-runtime.ts
1489
1646
  function resolveCliSpawnPlan(options) {
1490
- const { provider, runtimeSettings, workingDir, extraArgs } = options;
1647
+ const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
1491
1648
  const { spawn: spawnConfig } = provider;
1492
1649
  const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
1493
1650
  const binaryPath = findBinary(configuredCommand);
@@ -1495,9 +1652,9 @@ function resolveCliSpawnPlan(options) {
1495
1652
  const allArgs = [...spawnConfig.args, ...extraArgs];
1496
1653
  let shellCmd;
1497
1654
  let shellArgs;
1498
- const useShellUnix = !isWin && (!!spawnConfig.shell || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1655
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1499
1656
  const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1500
- const useShellWin = !!spawnConfig.shell || isCmdShim || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1657
+ const useShellWin = !!spawnConfig.shell || isCmdShim || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1501
1658
  const useShell = isWin ? useShellWin : useShellUnix;
1502
1659
  if (useShell) {
1503
1660
  shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
@@ -1511,7 +1668,7 @@ function resolveCliSpawnPlan(options) {
1511
1668
  shellCmd = binaryPath;
1512
1669
  shellArgs = allArgs;
1513
1670
  }
1514
- const env = buildCliSpawnEnv(process.env, spawnConfig.env);
1671
+ const env = buildCliSpawnEnv(process.env, { ...spawnConfig.env || {}, ...extraEnv || {} });
1515
1672
  env.TERMINAL_CWD = workingDir;
1516
1673
  return {
1517
1674
  binaryPath,
@@ -1573,12 +1730,12 @@ function respondToCliTerminalQueries(options) {
1573
1730
  }
1574
1731
  return "";
1575
1732
  }
1576
- var os10, path14, import_session_host_core2;
1733
+ var os10, path15, import_session_host_core2;
1577
1734
  var init_provider_cli_runtime = __esm({
1578
1735
  "src/cli-adapters/provider-cli-runtime.ts"() {
1579
1736
  "use strict";
1580
1737
  os10 = __toESM(require("os"));
1581
- path14 = __toESM(require("path"));
1738
+ path15 = __toESM(require("path"));
1582
1739
  import_session_host_core2 = require("@adhdev/session-host-core");
1583
1740
  init_provider_cli_shared();
1584
1741
  }
@@ -1614,8 +1771,9 @@ var init_provider_cli_adapter = __esm({
1614
1771
  init_provider_cli_runtime();
1615
1772
  init_provider_cli_shared();
1616
1773
  ProviderCliAdapter = class _ProviderCliAdapter {
1617
- constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
1774
+ constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
1618
1775
  this.extraArgs = extraArgs;
1776
+ this.extraEnv = extraEnv;
1619
1777
  this.provider = provider;
1620
1778
  this.transportFactory = transportFactory;
1621
1779
  this.cliType = provider.type;
@@ -1766,8 +1924,9 @@ var init_provider_cli_adapter = __esm({
1766
1924
  const currentSnapshot = normalizeScreenSnapshot(screenText);
1767
1925
  const lastSnapshot = this.lastScreenSnapshot;
1768
1926
  if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
1769
- const staleSnapshotLooksActive = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel/i.test(lastSnapshot);
1770
- 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);
1927
+ 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;
1928
+ const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
1929
+ const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
1771
1930
  if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
1772
1931
  if (currentSnapshot.length >= lastSnapshot.length) return screenText;
1773
1932
  return `${screenText}
@@ -1930,7 +2089,8 @@ ${lastSnapshot}`;
1930
2089
  provider: this.provider,
1931
2090
  runtimeSettings: this.runtimeSettings,
1932
2091
  workingDir: this.workingDir,
1933
- extraArgs: this.extraArgs
2092
+ extraArgs: this.extraArgs,
2093
+ extraEnv: this.extraEnv
1934
2094
  });
1935
2095
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
1936
2096
  this.resetTraceSession();
@@ -3128,9 +3288,8 @@ ${lastSnapshot}`;
3128
3288
  };
3129
3289
  this.recordTrace("submit_echo_missing", diagnostic);
3130
3290
  if (this.requirePromptEchoBeforeSubmit) {
3131
- const message = `${this.cliName} prompt echo was not observed on the PTY screen before submit`;
3132
- LOG.warn("CLI", `[${this.cliType}] ${message} elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
3133
- completion.rejectOnce(new Error(message));
3291
+ 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)}`);
3292
+ this.submitSendKey(state, completion);
3134
3293
  return;
3135
3294
  }
3136
3295
  LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
@@ -3177,7 +3336,14 @@ ${lastSnapshot}`;
3177
3336
  })() : null;
3178
3337
  const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
3179
3338
  if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
3180
- throw new Error(`${this.cliName} is still processing the previous prompt`);
3339
+ const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
3340
+ const parsedHasActionableModal = Boolean(
3341
+ parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
3342
+ );
3343
+ const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
3344
+ if (!terminalLooksIdle) {
3345
+ throw new Error(`${this.cliName} is still processing the previous prompt`);
3346
+ }
3181
3347
  }
3182
3348
  if (this.isWaitingForResponse && !allowInputDuringGeneration) {
3183
3349
  if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
@@ -3727,12 +3893,14 @@ __export(index_exports, {
3727
3893
  createGitWorkspaceMonitor: () => createGitWorkspaceMonitor,
3728
3894
  createInteractionId: () => createInteractionId,
3729
3895
  createMesh: () => createMesh,
3896
+ createWorktree: () => createWorktree,
3730
3897
  deleteMesh: () => deleteMesh,
3731
3898
  detectAllVersions: () => detectAllVersions,
3732
3899
  detectCLIs: () => detectCLIs,
3733
3900
  detectIDEs: () => detectIDEs,
3734
3901
  ensureSessionHostReady: () => ensureSessionHostReady,
3735
3902
  execNpmCommandSync: () => execNpmCommandSync,
3903
+ filterUserFacingChatMessages: () => filterUserFacingChatMessages,
3736
3904
  findCdpManager: () => findCdpManager,
3737
3905
  flattenMessageParts: () => flattenMessageParts,
3738
3906
  forwardAgentStreamsToIdeInstance: () => forwardAgentStreamsToIdeInstance,
@@ -3774,11 +3942,13 @@ __export(index_exports, {
3774
3942
  isSessionHostLiveRuntime: () => isSessionHostLiveRuntime,
3775
3943
  isSessionHostRecoverySnapshot: () => isSessionHostRecoverySnapshot,
3776
3944
  isSetupComplete: () => isSetupComplete,
3945
+ isUserFacingChatMessage: () => isUserFacingChatMessage,
3777
3946
  killIdeProcess: () => killIdeProcess,
3778
3947
  launchIDE: () => launchIDE,
3779
3948
  launchWithCdp: () => launchWithCdp,
3780
3949
  listHostedCliRuntimes: () => listHostedCliRuntimes,
3781
3950
  listMeshes: () => listMeshes,
3951
+ listWorktrees: () => listWorktrees,
3782
3952
  loadConfig: () => loadConfig,
3783
3953
  loadState: () => loadState,
3784
3954
  logCommand: () => logCommand,
@@ -3798,6 +3968,7 @@ __export(index_exports, {
3798
3968
  normalizeSessionModalFields: () => normalizeSessionModalFields,
3799
3969
  parsePorcelainV2Status: () => parsePorcelainV2Status,
3800
3970
  parseProviderSourceConfigUpdate: () => parseProviderSourceConfigUpdate,
3971
+ parseWorktreeListOutput: () => parseWorktreeListOutput,
3801
3972
  partitionSessionHostDiagnosticsSessions: () => partitionSessionHostDiagnosticsSessions,
3802
3973
  partitionSessionHostRecords: () => partitionSessionHostRecords,
3803
3974
  prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
@@ -3807,6 +3978,7 @@ __export(index_exports, {
3807
3978
  recordDebugTrace: () => recordDebugTrace,
3808
3979
  registerExtensionProviders: () => registerExtensionProviders,
3809
3980
  removeNode: () => removeNode,
3981
+ removeWorktree: () => removeWorktree,
3810
3982
  resetConfig: () => resetConfig,
3811
3983
  resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
3812
3984
  resetState: () => resetState,
@@ -3816,6 +3988,7 @@ __export(index_exports, {
3816
3988
  resolveGitRepository: () => resolveGitRepository,
3817
3989
  resolveSessionHostAppName: () => resolveSessionHostAppName,
3818
3990
  resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
3991
+ resolveWorktreePath: () => resolveWorktreePath,
3819
3992
  runAsyncBatch: () => runAsyncBatch,
3820
3993
  runGit: () => runGit,
3821
3994
  saveConfig: () => saveConfig,
@@ -4739,6 +4912,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
4739
4912
  "dirty_index_required",
4740
4913
  "conflict",
4741
4914
  "invalid_args",
4915
+ "nothing_to_commit",
4742
4916
  "git_command_failed"
4743
4917
  ]);
4744
4918
  function failure(reason, error) {
@@ -4983,7 +5157,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
4983
5157
  } catch (err) {
4984
5158
  const output = (err?.stdout || "") + (err?.stderr || "");
4985
5159
  if (/nothing to commit/i.test(output)) {
4986
- throw new GitCommandError("git_command_failed", "Nothing to commit");
5160
+ throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
5161
+ stdout: err?.stdout,
5162
+ stderr: err?.stderr
5163
+ });
4987
5164
  }
4988
5165
  throw err;
4989
5166
  }
@@ -5175,20 +5352,23 @@ var TurnSnapshotTracker = class {
5175
5352
  }
5176
5353
  };
5177
5354
 
5355
+ // src/git/index.ts
5356
+ init_git_worktree();
5357
+
5178
5358
  // src/index.ts
5179
5359
  init_config();
5180
5360
 
5181
5361
  // src/config/workspaces.ts
5182
5362
  var fs = __toESM(require("fs"));
5183
5363
  var os = __toESM(require("os"));
5184
- var path4 = __toESM(require("path"));
5364
+ var path5 = __toESM(require("path"));
5185
5365
  var import_crypto2 = require("crypto");
5186
5366
  var MAX_WORKSPACES = 50;
5187
5367
  function expandPath(p) {
5188
5368
  const t = (p || "").trim();
5189
5369
  if (!t) return "";
5190
- if (t.startsWith("~")) return path4.join(os.homedir(), t.slice(1).replace(/^\//, ""));
5191
- return path4.resolve(t);
5370
+ if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
5371
+ return path5.resolve(t);
5192
5372
  }
5193
5373
  function validateWorkspacePath(absPath) {
5194
5374
  try {
@@ -5202,7 +5382,7 @@ function validateWorkspacePath(absPath) {
5202
5382
  }
5203
5383
  }
5204
5384
  function defaultWorkspaceLabel(absPath) {
5205
- const base = path4.basename(absPath) || absPath;
5385
+ const base = path5.basename(absPath) || absPath;
5206
5386
  return base;
5207
5387
  }
5208
5388
  function getDefaultWorkspacePath(config) {
@@ -5293,9 +5473,9 @@ function resolveIdeLaunchWorkspace(args, config) {
5293
5473
  return getDefaultWorkspacePath(config) || void 0;
5294
5474
  }
5295
5475
  function findWorkspaceByPath(config, rawPath) {
5296
- const abs = path4.resolve(expandPath(rawPath));
5476
+ const abs = path5.resolve(expandPath(rawPath));
5297
5477
  if (!abs) return void 0;
5298
- return (config.workspaces || []).find((w) => path4.resolve(expandPath(w.path)) === abs);
5478
+ return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
5299
5479
  }
5300
5480
  function addWorkspaceEntry(config, rawPath, label, options) {
5301
5481
  const abs = expandPath(rawPath);
@@ -5311,7 +5491,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
5311
5491
  const v = validateWorkspacePath(abs);
5312
5492
  if (!v.ok) return { error: v.error };
5313
5493
  const list = [...config.workspaces || []];
5314
- if (list.some((w) => path4.resolve(w.path) === abs)) {
5494
+ if (list.some((w) => path5.resolve(w.path) === abs)) {
5315
5495
  return { error: "Workspace already in list" };
5316
5496
  }
5317
5497
  if (list.length >= MAX_WORKSPACES) {
@@ -5345,7 +5525,7 @@ function setDefaultWorkspaceId(config, id) {
5345
5525
  }
5346
5526
 
5347
5527
  // src/config/recent-activity.ts
5348
- var path5 = __toESM(require("path"));
5528
+ var path6 = __toESM(require("path"));
5349
5529
 
5350
5530
  // src/providers/summary-metadata.ts
5351
5531
  function normalizeSummaryItem(item) {
@@ -5414,9 +5594,9 @@ var MAX_ACTIVITY = 30;
5414
5594
  function normalizeWorkspace(workspace) {
5415
5595
  if (!workspace) return "";
5416
5596
  try {
5417
- return path5.resolve(expandPath(workspace));
5597
+ return path6.resolve(expandPath(workspace));
5418
5598
  } catch {
5419
- return path5.resolve(workspace);
5599
+ return path6.resolve(workspace);
5420
5600
  }
5421
5601
  }
5422
5602
  function buildRecentActivityKey(entry) {
@@ -5584,14 +5764,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
5584
5764
  }
5585
5765
 
5586
5766
  // src/config/saved-sessions.ts
5587
- var path6 = __toESM(require("path"));
5767
+ var path7 = __toESM(require("path"));
5588
5768
  var MAX_SAVED_SESSIONS = 500;
5589
5769
  function normalizeWorkspace2(workspace) {
5590
5770
  if (!workspace) return "";
5591
5771
  try {
5592
- return path6.resolve(expandPath(workspace));
5772
+ return path7.resolve(expandPath(workspace));
5593
5773
  } catch {
5594
- return path6.resolve(workspace);
5774
+ return path7.resolve(workspace);
5595
5775
  }
5596
5776
  }
5597
5777
  function buildSavedProviderSessionKey(providerSessionId) {
@@ -5770,7 +5950,7 @@ function resetState() {
5770
5950
  var import_child_process = require("child_process");
5771
5951
  var import_fs4 = require("fs");
5772
5952
  var import_os2 = require("os");
5773
- var path7 = __toESM(require("path"));
5953
+ var path8 = __toESM(require("path"));
5774
5954
  var BUILTIN_IDE_DEFINITIONS = [];
5775
5955
  var registeredIDEs = /* @__PURE__ */ new Map();
5776
5956
  function registerIDEDefinition(def) {
@@ -5789,9 +5969,9 @@ function getMergedDefinitions() {
5789
5969
  function findCliCommand(command) {
5790
5970
  const trimmed = String(command || "").trim();
5791
5971
  if (!trimmed) return null;
5792
- if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5793
- const candidate = trimmed.startsWith("~") ? path7.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
5794
- const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
5972
+ if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5973
+ const candidate = trimmed.startsWith("~") ? path8.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
5974
+ const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
5795
5975
  return (0, import_fs4.existsSync)(resolved) ? resolved : null;
5796
5976
  }
5797
5977
  try {
@@ -5819,7 +5999,7 @@ function getIdeVersion(cliCommand) {
5819
5999
  function checkPathExists(paths) {
5820
6000
  const home = (0, import_os2.homedir)();
5821
6001
  for (const p of paths) {
5822
- const normalized = p.startsWith("~") ? path7.join(home, p.slice(1)) : p;
6002
+ const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
5823
6003
  if (normalized.includes("*")) {
5824
6004
  const username = home.split(/[\\/]/).pop() || "";
5825
6005
  const resolved = normalized.replace("*", username);
@@ -5831,19 +6011,19 @@ function checkPathExists(paths) {
5831
6011
  return null;
5832
6012
  }
5833
6013
  async function detectIDEs(providerLoader) {
5834
- const os21 = (0, import_os2.platform)();
6014
+ const os22 = (0, import_os2.platform)();
5835
6015
  const results = [];
5836
6016
  for (const def of getMergedDefinitions()) {
5837
6017
  const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
5838
- const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os21] || []) || []);
6018
+ const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
5839
6019
  let resolvedCli = cliPath;
5840
- if (!resolvedCli && appPath && os21 === "darwin") {
6020
+ if (!resolvedCli && appPath && os22 === "darwin") {
5841
6021
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
5842
6022
  if ((0, import_fs4.existsSync)(bundledCli)) resolvedCli = bundledCli;
5843
6023
  }
5844
- if (!resolvedCli && appPath && os21 === "win32") {
5845
- const { dirname: dirname8 } = await import("path");
5846
- const appDir = dirname8(appPath);
6024
+ if (!resolvedCli && appPath && os22 === "win32") {
6025
+ const { dirname: dirname9 } = await import("path");
6026
+ const appDir = dirname9(appPath);
5847
6027
  const candidates = [
5848
6028
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
5849
6029
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -5858,7 +6038,7 @@ async function detectIDEs(providerLoader) {
5858
6038
  }
5859
6039
  }
5860
6040
  }
5861
- const installed = os21 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
6041
+ const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
5862
6042
  const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
5863
6043
  results.push({
5864
6044
  id: def.id,
@@ -5877,7 +6057,7 @@ async function detectIDEs(providerLoader) {
5877
6057
  // src/detection/cli-detector.ts
5878
6058
  var import_child_process2 = require("child_process");
5879
6059
  var os2 = __toESM(require("os"));
5880
- var path8 = __toESM(require("path"));
6060
+ var path9 = __toESM(require("path"));
5881
6061
  var import_fs5 = require("fs");
5882
6062
  function parseVersion(raw) {
5883
6063
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
@@ -5890,18 +6070,18 @@ function shellQuote(value) {
5890
6070
  function expandHome(value) {
5891
6071
  const trimmed = value.trim();
5892
6072
  if (!trimmed.startsWith("~")) return trimmed;
5893
- return path8.join(os2.homedir(), trimmed.slice(1));
6073
+ return path9.join(os2.homedir(), trimmed.slice(1));
5894
6074
  }
5895
6075
  function isExplicitCommandPath(command) {
5896
6076
  const trimmed = command.trim();
5897
- return path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
6077
+ return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
5898
6078
  }
5899
6079
  function resolveCommandPath(command) {
5900
6080
  const trimmed = command.trim();
5901
6081
  if (!trimmed) return null;
5902
6082
  if (isExplicitCommandPath(trimmed)) {
5903
6083
  const expanded = expandHome(trimmed);
5904
- const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
6084
+ const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
5905
6085
  return (0, import_fs5.existsSync)(candidate) ? candidate : null;
5906
6086
  }
5907
6087
  return null;
@@ -7974,6 +8154,44 @@ function normalizeChatMessage(message) {
7974
8154
  function normalizeChatMessages(messages) {
7975
8155
  return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
7976
8156
  }
8157
+ function readMessageMeta(message) {
8158
+ const meta = message?.meta;
8159
+ return meta && typeof meta === "object" && !Array.isArray(meta) ? meta : null;
8160
+ }
8161
+ function readStringField(value) {
8162
+ return typeof value === "string" ? value.trim().toLowerCase() : "";
8163
+ }
8164
+ function readVisibilityField(message, meta) {
8165
+ const record = message;
8166
+ return readStringField(record.visibility ?? record.transcriptVisibility ?? meta?.visibility ?? meta?.transcriptVisibility);
8167
+ }
8168
+ function isExplicitlyHiddenFromTranscript(message, meta) {
8169
+ const record = message;
8170
+ const visibility = readVisibilityField(message, meta);
8171
+ const audience = readStringField(record.audience ?? meta?.audience);
8172
+ const source = readStringField(record.source ?? meta?.source);
8173
+ return visibility === "hidden" || visibility === "debug" || visibility === "internal" || audience === "debug" || audience === "trace" || audience === "internal" || source === "runtime_status" || source === "runtime_activity" || source === "provider_chrome" || source === "control" || record.internal === true || record.isInternal === true || record.debug === true || meta?.internal === true || meta?.isInternal === true || meta?.debug === true || meta?.statusOnly === true || meta?.controlOnly === true;
8174
+ }
8175
+ function isExplicitlyVisibleInTranscript(message, meta) {
8176
+ const record = message;
8177
+ const visibility = readVisibilityField(message, meta);
8178
+ const audience = readStringField(record.audience ?? meta?.audience);
8179
+ return visibility === "visible" || visibility === "user" || visibility === "chat" || audience === "chat" || record.userFacing === true || meta?.userFacing === true;
8180
+ }
8181
+ function isUserFacingChatMessage(message) {
8182
+ if (!message) return false;
8183
+ const meta = readMessageMeta(message);
8184
+ if (isExplicitlyHiddenFromTranscript(message, meta)) return false;
8185
+ if (isExplicitlyVisibleInTranscript(message, meta)) return true;
8186
+ const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
8187
+ const kind = resolveChatMessageKind(message);
8188
+ if (role === "user" || role === "human") return kind === "standard" || kind === "";
8189
+ if (role === "assistant") return kind === "standard" || kind === "";
8190
+ return false;
8191
+ }
8192
+ function filterUserFacingChatMessages(messages) {
8193
+ return (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
8194
+ }
7977
8195
 
7978
8196
  // src/providers/control-effects.ts
7979
8197
  function extractProviderControlValues(controls, data) {
@@ -8170,9 +8388,9 @@ ${cleanBody}`;
8170
8388
 
8171
8389
  // src/config/chat-history.ts
8172
8390
  var fs3 = __toESM(require("fs"));
8173
- var path10 = __toESM(require("path"));
8391
+ var path11 = __toESM(require("path"));
8174
8392
  var os5 = __toESM(require("os"));
8175
- var HISTORY_DIR = path10.join(os5.homedir(), ".adhdev", "history");
8393
+ var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
8176
8394
  var RETAIN_DAYS = 30;
8177
8395
  var SAVED_HISTORY_INDEX_VERSION = 1;
8178
8396
  var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
@@ -8335,7 +8553,7 @@ function extractSavedHistorySessionIdFromFile(file) {
8335
8553
  function buildSavedHistoryFileSignatureMap(dir, files) {
8336
8554
  return new Map(files.map((file) => {
8337
8555
  try {
8338
- const stat2 = fs3.statSync(path10.join(dir, file));
8556
+ const stat2 = fs3.statSync(path11.join(dir, file));
8339
8557
  return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
8340
8558
  } catch {
8341
8559
  return [file, `${file}:missing`];
@@ -8346,7 +8564,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
8346
8564
  return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
8347
8565
  }
8348
8566
  function getSavedHistoryIndexFilePath(dir) {
8349
- return path10.join(dir, SAVED_HISTORY_INDEX_FILE);
8567
+ return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
8350
8568
  }
8351
8569
  function getSavedHistoryIndexLockPath(dir) {
8352
8570
  return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
@@ -8448,7 +8666,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
8448
8666
  }
8449
8667
  for (const file of Array.from(currentEntries.keys())) {
8450
8668
  if (incomingFiles.has(file)) continue;
8451
- if (!fs3.existsSync(path10.join(dir, file))) {
8669
+ if (!fs3.existsSync(path11.join(dir, file))) {
8452
8670
  currentEntries.delete(file);
8453
8671
  }
8454
8672
  }
@@ -8474,7 +8692,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
8474
8692
  const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
8475
8693
  const files = listHistoryFiles(dir);
8476
8694
  for (const file of files) {
8477
- const stat2 = fs3.statSync(path10.join(dir, file));
8695
+ const stat2 = fs3.statSync(path11.join(dir, file));
8478
8696
  if (stat2.mtimeMs > indexStat.mtimeMs) return true;
8479
8697
  }
8480
8698
  return false;
@@ -8484,14 +8702,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
8484
8702
  }
8485
8703
  function buildSavedHistoryFileSignature(dir, file) {
8486
8704
  try {
8487
- const stat2 = fs3.statSync(path10.join(dir, file));
8705
+ const stat2 = fs3.statSync(path11.join(dir, file));
8488
8706
  return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
8489
8707
  } catch {
8490
8708
  return `${file}:missing`;
8491
8709
  }
8492
8710
  }
8493
8711
  function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
8494
- const filePath = path10.join(dir, file);
8712
+ const filePath = path11.join(dir, file);
8495
8713
  const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
8496
8714
  const currentEntry = entries.get(file) || null;
8497
8715
  const nextSummary = updater(currentEntry?.summary || null);
@@ -8564,7 +8782,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
8564
8782
  function computeSavedHistoryFileSummary(dir, file) {
8565
8783
  const historySessionId = extractSavedHistorySessionIdFromFile(file);
8566
8784
  if (!historySessionId) return null;
8567
- const filePath = path10.join(dir, file);
8785
+ const filePath = path11.join(dir, file);
8568
8786
  const content = fs3.readFileSync(filePath, "utf-8");
8569
8787
  const lines = content.split("\n").filter(Boolean);
8570
8788
  let messageCount = 0;
@@ -8651,7 +8869,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
8651
8869
  const summaryBySessionId = /* @__PURE__ */ new Map();
8652
8870
  const nextPersistedEntries = /* @__PURE__ */ new Map();
8653
8871
  for (const file of files.slice().sort()) {
8654
- const filePath = path10.join(dir, file);
8872
+ const filePath = path11.join(dir, file);
8655
8873
  const signature = fileSignatures.get(file) || `${file}:missing`;
8656
8874
  const cached = savedHistoryFileSummaryCache.get(filePath);
8657
8875
  const persisted = persistedEntries.get(file);
@@ -8771,12 +8989,12 @@ var ChatHistoryWriter = class {
8771
8989
  });
8772
8990
  }
8773
8991
  if (newMessages.length === 0) return;
8774
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8992
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8775
8993
  fs3.mkdirSync(dir, { recursive: true });
8776
8994
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8777
8995
  const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
8778
8996
  const fileName = `${filePrefix}${date}.jsonl`;
8779
- const filePath = path10.join(dir, fileName);
8997
+ const filePath = path11.join(dir, fileName);
8780
8998
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
8781
8999
  fs3.appendFileSync(filePath, lines, "utf-8");
8782
9000
  updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
@@ -8867,11 +9085,11 @@ var ChatHistoryWriter = class {
8867
9085
  const ws = String(workspace || "").trim();
8868
9086
  if (!id || !ws) return;
8869
9087
  try {
8870
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
9088
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8871
9089
  fs3.mkdirSync(dir, { recursive: true });
8872
9090
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8873
9091
  const fileName = `${this.sanitize(id)}_${date}.jsonl`;
8874
- const filePath = path10.join(dir, fileName);
9092
+ const filePath = path11.join(dir, fileName);
8875
9093
  const record = {
8876
9094
  ts: (/* @__PURE__ */ new Date()).toISOString(),
8877
9095
  receivedAt: Date.now(),
@@ -8917,14 +9135,14 @@ var ChatHistoryWriter = class {
8917
9135
  this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
8918
9136
  this.lastSeenCounts.delete(fromDedupKey);
8919
9137
  }
8920
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
9138
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8921
9139
  if (!fs3.existsSync(dir)) return;
8922
9140
  const fromPrefix = `${this.sanitize(fromId)}_`;
8923
9141
  const toPrefix = `${this.sanitize(toId)}_`;
8924
9142
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
8925
9143
  for (const file of files) {
8926
- const sourcePath = path10.join(dir, file);
8927
- const targetPath = path10.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
9144
+ const sourcePath = path11.join(dir, file);
9145
+ const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
8928
9146
  const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
8929
9147
  const rewritten = sourceLines.map((line) => {
8930
9148
  try {
@@ -8958,13 +9176,13 @@ var ChatHistoryWriter = class {
8958
9176
  const sessionId = String(historySessionId || "").trim();
8959
9177
  if (!sessionId) return;
8960
9178
  try {
8961
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
9179
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8962
9180
  if (!fs3.existsSync(dir)) return;
8963
9181
  const prefix = `${this.sanitize(sessionId)}_`;
8964
9182
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
8965
9183
  const seen = /* @__PURE__ */ new Set();
8966
9184
  for (const file of files) {
8967
- const filePath = path10.join(dir, file);
9185
+ const filePath = path11.join(dir, file);
8968
9186
  const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8969
9187
  const next = [];
8970
9188
  for (const line of lines) {
@@ -9018,11 +9236,11 @@ var ChatHistoryWriter = class {
9018
9236
  const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
9019
9237
  const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
9020
9238
  for (const dir of agentDirs) {
9021
- const dirPath = path10.join(HISTORY_DIR, dir.name);
9239
+ const dirPath = path11.join(HISTORY_DIR, dir.name);
9022
9240
  const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
9023
9241
  let removedAny = false;
9024
9242
  for (const file of files) {
9025
- const filePath = path10.join(dirPath, file);
9243
+ const filePath = path11.join(dirPath, file);
9026
9244
  const stat2 = fs3.statSync(filePath);
9027
9245
  if (stat2.mtimeMs < cutoff) {
9028
9246
  fs3.unlinkSync(filePath);
@@ -9072,13 +9290,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
9072
9290
  function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
9073
9291
  try {
9074
9292
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
9075
- const dir = path10.join(HISTORY_DIR, sanitized);
9293
+ const dir = path11.join(HISTORY_DIR, sanitized);
9076
9294
  if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
9077
9295
  const files = listHistoryFiles(dir, historySessionId);
9078
9296
  const allMessages = [];
9079
9297
  const seen = /* @__PURE__ */ new Set();
9080
9298
  for (const file of files) {
9081
- const filePath = path10.join(dir, file);
9299
+ const filePath = path11.join(dir, file);
9082
9300
  const content = fs3.readFileSync(filePath, "utf-8");
9083
9301
  const lines = content.trim().split("\n").filter(Boolean);
9084
9302
  for (let i = 0; i < lines.length; i++) {
@@ -9102,7 +9320,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
9102
9320
  function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
9103
9321
  try {
9104
9322
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
9105
- const dir = path10.join(HISTORY_DIR, sanitized);
9323
+ const dir = path11.join(HISTORY_DIR, sanitized);
9106
9324
  if (!fs3.existsSync(dir)) {
9107
9325
  savedHistorySessionCache.delete(sanitized);
9108
9326
  return { sessions: [], hasMore: false };
@@ -9163,11 +9381,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
9163
9381
  }
9164
9382
  function readExistingSessionStartRecord(agentType, historySessionId) {
9165
9383
  try {
9166
- const dir = path10.join(HISTORY_DIR, agentType);
9384
+ const dir = path11.join(HISTORY_DIR, agentType);
9167
9385
  if (!fs3.existsSync(dir)) return null;
9168
9386
  const files = listHistoryFiles(dir, historySessionId).sort();
9169
9387
  for (const file of files) {
9170
- const lines = fs3.readFileSync(path10.join(dir, file), "utf-8").split("\n").filter(Boolean);
9388
+ const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
9171
9389
  for (const line of lines) {
9172
9390
  try {
9173
9391
  const parsed = JSON.parse(line);
@@ -9187,16 +9405,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
9187
9405
  function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
9188
9406
  if (records.length === 0) return false;
9189
9407
  try {
9190
- const dir = path10.join(HISTORY_DIR, agentType);
9408
+ const dir = path11.join(HISTORY_DIR, agentType);
9191
9409
  fs3.mkdirSync(dir, { recursive: true });
9192
9410
  const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
9193
9411
  for (const file of fs3.readdirSync(dir)) {
9194
9412
  if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
9195
- fs3.unlinkSync(path10.join(dir, file));
9413
+ fs3.unlinkSync(path11.join(dir, file));
9196
9414
  }
9197
9415
  }
9198
9416
  const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
9199
- const filePath = path10.join(dir, `${prefix}${targetDate}.jsonl`);
9417
+ const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
9200
9418
  fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
9201
9419
  `, "utf-8");
9202
9420
  invalidatePersistedSavedHistoryIndex(agentType, dir);
@@ -9946,6 +10164,14 @@ function validateMessage(message, source, index) {
9946
10164
  if (typeof message.senderName === "string") normalized.senderName = message.senderName;
9947
10165
  if (typeof message._type === "string") normalized._type = message._type;
9948
10166
  if (typeof message._sub === "string") normalized._sub = message._sub;
10167
+ if (typeof message.visibility === "string") normalized.visibility = message.visibility;
10168
+ if (typeof message.transcriptVisibility === "string") normalized.transcriptVisibility = message.transcriptVisibility;
10169
+ if (typeof message.audience === "string") normalized.audience = message.audience;
10170
+ if (typeof message.source === "string") normalized.source = message.source;
10171
+ if (typeof message.userFacing === "boolean") normalized.userFacing = message.userFacing;
10172
+ if (typeof message.internal === "boolean") normalized.internal = message.internal;
10173
+ if (typeof message.isInternal === "boolean") normalized.isInternal = message.isInternal;
10174
+ if (typeof message.debug === "boolean") normalized.debug = message.debug;
9949
10175
  return normalized;
9950
10176
  }
9951
10177
  function validateModal(activeModal, status, source) {
@@ -11191,6 +11417,14 @@ function getActiveChatOptions(profile) {
11191
11417
  if (profile === "full") return {};
11192
11418
  return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
11193
11419
  }
11420
+ function resolveSessionStatus(activeChat, providerStatus) {
11421
+ const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
11422
+ const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
11423
+ if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
11424
+ if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
11425
+ if (topLevelStatus !== "idle") return topLevelStatus;
11426
+ return chatStatus;
11427
+ }
11194
11428
  function shouldIncludeSessionControls(profile) {
11195
11429
  return profile !== "live";
11196
11430
  }
@@ -11269,9 +11503,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
11269
11503
  providerName: state.name,
11270
11504
  kind: "workspace",
11271
11505
  transport: "cdp-page",
11272
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11273
- activeModal: activeChat?.activeModal || null
11274
- }),
11506
+ status: resolveSessionStatus(activeChat, state.status),
11275
11507
  title,
11276
11508
  workspace,
11277
11509
  ...git && { git },
@@ -11306,9 +11538,7 @@ function buildExtensionAgentSession(parent, ext, options) {
11306
11538
  providerSessionId: ext.providerSessionId,
11307
11539
  kind: "agent",
11308
11540
  transport: "cdp-webview",
11309
- status: normalizeManagedStatus(activeChat?.status || ext.status, {
11310
- activeModal: activeChat?.activeModal || null
11311
- }),
11541
+ status: resolveSessionStatus(activeChat, ext.status),
11312
11542
  title: activeChat?.title || ext.name,
11313
11543
  workspace,
11314
11544
  ...git && { git },
@@ -11358,9 +11588,7 @@ function buildCliSession(state, options) {
11358
11588
  providerSessionId: state.providerSessionId,
11359
11589
  kind: "agent",
11360
11590
  transport: "pty",
11361
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11362
- activeModal: activeChat?.activeModal || null
11363
- }),
11591
+ status: resolveSessionStatus(activeChat, state.status),
11364
11592
  title: activeChat?.title || state.name,
11365
11593
  workspace,
11366
11594
  ...git && { git },
@@ -11408,9 +11636,7 @@ function buildAcpSession(state, options) {
11408
11636
  providerName: state.name,
11409
11637
  kind: "agent",
11410
11638
  transport: "acp",
11411
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11412
- activeModal: activeChat?.activeModal || null
11413
- }),
11639
+ status: resolveSessionStatus(activeChat, state.status),
11414
11640
  title: activeChat?.title || state.name,
11415
11641
  workspace,
11416
11642
  ...git && { git },
@@ -11533,7 +11759,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
11533
11759
  // src/commands/chat-commands.ts
11534
11760
  var fs4 = __toESM(require("fs"));
11535
11761
  var os6 = __toESM(require("os"));
11536
- var path11 = __toESM(require("path"));
11762
+ var path12 = __toESM(require("path"));
11537
11763
  var import_node_crypto = require("crypto");
11538
11764
 
11539
11765
  // src/providers/provider-input-support.ts
@@ -11736,6 +11962,7 @@ function buildSessionModalDeliverySignature(payload) {
11736
11962
  // src/commands/chat-commands.ts
11737
11963
  var RECENT_SEND_WINDOW_MS = 1200;
11738
11964
  var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
11965
+ var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
11739
11966
  var recentSendByTarget = /* @__PURE__ */ new Map();
11740
11967
  function getCurrentProviderType(h, fallback = "") {
11741
11968
  return h.currentSession?.providerType || h.currentProviderType || fallback;
@@ -11788,6 +12015,16 @@ function buildSendInputSignature(input) {
11788
12015
  function getSendChatInputEnvelope(args) {
11789
12016
  return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
11790
12017
  }
12018
+ function sleep(ms) {
12019
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
12020
+ }
12021
+ async function waitOnceForFreshHermesCliStart(adapter, log) {
12022
+ if (adapter.cliType !== "hermes-cli") return;
12023
+ const status = typeof adapter.getStatus === "function" ? adapter.getStatus()?.status : void 0;
12024
+ if (status !== "starting") return;
12025
+ log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
12026
+ await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
12027
+ }
11791
12028
  function getHistorySessionId(h, args) {
11792
12029
  const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
11793
12030
  if (explicit) return explicit;
@@ -11842,7 +12079,7 @@ function normalizeReadChatTailLimit(args) {
11842
12079
  }
11843
12080
  function normalizeReadChatMessages(payload) {
11844
12081
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
11845
- return messages;
12082
+ return normalizeChatMessages(messages);
11846
12083
  }
11847
12084
  function deriveHistoryDedupKey(message) {
11848
12085
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -11896,6 +12133,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
11896
12133
  return raw;
11897
12134
  }
11898
12135
  }
12136
+ function isGeneratingLikeStatus(status) {
12137
+ return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
12138
+ }
12139
+ function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
12140
+ if (!isGeneratingLikeStatus(parsedStatus)) return false;
12141
+ if (hasNonEmptyModalButtons(activeModal)) return false;
12142
+ const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
12143
+ if (adapterRawStatus !== "idle") return false;
12144
+ if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
12145
+ return true;
12146
+ }
12147
+ function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
12148
+ if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
12149
+ return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
12150
+ }
12151
+ function finalizeStreamingMessagesWhenIdle(messages, status) {
12152
+ if (status !== "idle") return messages;
12153
+ return messages.map((message) => {
12154
+ const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
12155
+ const hasStreamingMeta = meta?.streaming === true;
12156
+ if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
12157
+ return {
12158
+ ...message,
12159
+ ...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
12160
+ ...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
12161
+ };
12162
+ });
12163
+ }
11899
12164
  function buildReadChatCommandResult(payload, args) {
11900
12165
  let validatedPayload;
11901
12166
  const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
@@ -11908,13 +12173,22 @@ function buildReadChatCommandResult(payload, args) {
11908
12173
  return { success: false, error: error?.message || String(error) };
11909
12174
  }
11910
12175
  const messages = normalizeReadChatMessages(validatedPayload);
11911
- const sync = buildFullTail(messages, normalizeReadChatTailLimit(args));
12176
+ const visibleMessages = filterUserFacingChatMessages(messages);
12177
+ const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
12178
+ const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
12179
+ const returnedDebugReadChat = debugReadChat ? {
12180
+ ...debugReadChat,
12181
+ fullMsgCount: typeof debugReadChat.fullMsgCount === "number" ? debugReadChat.fullMsgCount : messages.length,
12182
+ visibleMsgCount: visibleMessages.length,
12183
+ hiddenMsgCount,
12184
+ returnedMsgCount: sync.messages.length
12185
+ } : void 0;
11912
12186
  return {
11913
12187
  success: true,
11914
12188
  ...validatedPayload,
11915
12189
  messages: sync.messages,
11916
12190
  totalMessages: sync.totalMessages,
11917
- ...debugReadChat ? { debugReadChat } : {}
12191
+ ...returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}
11918
12192
  };
11919
12193
  }
11920
12194
  var DEFAULT_DEBUG_SANITIZE_OPTIONS = {
@@ -12044,7 +12318,7 @@ function buildDebugBundleText(bundle) {
12044
12318
  }
12045
12319
  function getChatDebugBundleDir() {
12046
12320
  const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
12047
- return override || path11.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
12321
+ return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
12048
12322
  }
12049
12323
  function safeBundleIdSegment(value, fallback) {
12050
12324
  const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
@@ -12060,6 +12334,14 @@ function buildChatDebugBundleSummary(bundle) {
12060
12334
  const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
12061
12335
  const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
12062
12336
  const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
12337
+ const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
12338
+ const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
12339
+ const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
12340
+ const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
12341
+ const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
12342
+ const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
12343
+ const cliStatus = typeof cli?.status === "string" ? cli.status : "";
12344
+ const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
12063
12345
  return {
12064
12346
  createdAt: bundle.createdAt,
12065
12347
  targetSessionId: target.targetSessionId,
@@ -12068,8 +12350,22 @@ function buildChatDebugBundleSummary(bundle) {
12068
12350
  readChatSuccess: readChat.success,
12069
12351
  readChatStatus: readChat.status,
12070
12352
  readChatTotalMessages: readChat.totalMessages,
12353
+ readChatReturnedMessages,
12071
12354
  cliStatus: cli?.status,
12355
+ cliParsedStatus: cliParsedStatus || void 0,
12072
12356
  cliMessageCount: cli?.messageCount,
12357
+ cliParsedMessageCount,
12358
+ cliPartialResponseChars: cliPartialResponse.length,
12359
+ parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
12360
+ parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
12361
+ readChatDebug: Object.keys(debugReadChat).length ? {
12362
+ adapterStatus: debugReadChat.adapterStatus,
12363
+ parsedStatus: debugReadChat.parsedStatus,
12364
+ returnedStatus: debugReadChat.returnedStatus,
12365
+ parsedMsgCount: debugReadChat.parsedMsgCount,
12366
+ returnedMsgCount: debugReadChat.returnedMsgCount,
12367
+ shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
12368
+ } : void 0,
12073
12369
  hasFrontendSnapshot: !!frontend
12074
12370
  };
12075
12371
  }
@@ -12077,7 +12373,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
12077
12373
  const bundleId = createChatDebugBundleId(targetSessionId);
12078
12374
  const dir = getChatDebugBundleDir();
12079
12375
  fs4.mkdirSync(dir, { recursive: true });
12080
- const savedPath = path11.join(dir, `${bundleId}.json`);
12376
+ const savedPath = path12.join(dir, `${bundleId}.json`);
12081
12377
  const json = `${JSON.stringify(bundle, null, 2)}
12082
12378
  `;
12083
12379
  fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
@@ -12307,7 +12603,7 @@ async function handleChatHistory(h, args) {
12307
12603
  }
12308
12604
  }
12309
12605
  async function handleReadChat(h, args) {
12310
- const provider = h.getProvider(args?.agentType);
12606
+ const provider = h.getProvider(args?.agentType || args?.providerType);
12311
12607
  const transport = getTargetTransport(h, provider);
12312
12608
  const historySessionId = getHistorySessionId(h, args);
12313
12609
  const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
@@ -12334,10 +12630,13 @@ async function handleReadChat(h, args) {
12334
12630
  const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
12335
12631
  const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
12336
12632
  const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
12337
- const returnedStatus = parsedRecord.status || "idle";
12338
- 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}`);
12633
+ const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
12634
+ const runtimeMessageMerger = getTargetInstance(h, args);
12635
+ const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
12636
+ const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
12637
+ 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}`);
12339
12638
  return buildReadChatCommandResult({
12340
- messages: parsedRecord.messages,
12639
+ messages: returnedMessages,
12341
12640
  status: returnedStatus,
12342
12641
  activeModal,
12343
12642
  debugReadChat: {
@@ -12348,7 +12647,7 @@ async function handleReadChat(h, args) {
12348
12647
  returnedStatus: String(returnedStatus || ""),
12349
12648
  shouldPreferAdapterMessages: false,
12350
12649
  parsedMsgCount: parsedRecord.messages.length,
12351
- returnedMsgCount: parsedRecord.messages.length
12650
+ returnedMsgCount: returnedMessages.length
12352
12651
  },
12353
12652
  ...title ? { title } : {},
12354
12653
  ...providerSessionId ? { providerSessionId } : {},
@@ -12594,6 +12893,7 @@ async function handleSendChat(h, args) {
12594
12893
  try {
12595
12894
  assertTextOnlyInput(provider, input);
12596
12895
  if (!text) return { success: false, error: "text required for PTY send" };
12896
+ await waitOnceForFreshHermesCliStart(adapter, _log);
12597
12897
  await adapter.sendMessage(text);
12598
12898
  return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
12599
12899
  } catch (e) {
@@ -13093,9 +13393,17 @@ async function handleResolveAction(h, args) {
13093
13393
  const targetState = targetInstance?.getState?.();
13094
13394
  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;
13095
13395
  const statusModal = status?.activeModal && Array.isArray(status.activeModal.buttons) && status.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? status.activeModal : null;
13096
- const effectiveModal = statusModal || surfacedModal;
13097
- const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" ? "waiting_approval" : status?.status;
13098
- 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"}`);
13396
+ const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
13397
+ try {
13398
+ return parseMaybeJson(adapter.getScriptParsedStatus());
13399
+ } catch {
13400
+ return null;
13401
+ }
13402
+ })() : null;
13403
+ 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;
13404
+ const effectiveModal = statusModal || surfacedModal || parsedModal;
13405
+ const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
13406
+ 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"}`);
13099
13407
  if (!effectiveModal) {
13100
13408
  return { success: false, error: "Not in approval state" };
13101
13409
  }
@@ -13221,7 +13529,7 @@ async function handleResolveAction(h, args) {
13221
13529
 
13222
13530
  // src/commands/cdp-commands.ts
13223
13531
  var fs5 = __toESM(require("fs"));
13224
- var path12 = __toESM(require("path"));
13532
+ var path13 = __toESM(require("path"));
13225
13533
  var os7 = __toESM(require("os"));
13226
13534
  var KEY_TO_VK = {
13227
13535
  Backspace: 8,
@@ -13478,25 +13786,25 @@ function resolveSafePath(requestedPath) {
13478
13786
  const inputPath = rawPath || ".";
13479
13787
  const home = os7.homedir();
13480
13788
  if (inputPath.startsWith("~")) {
13481
- return path12.resolve(path12.join(home, inputPath.slice(1)));
13789
+ return path13.resolve(path13.join(home, inputPath.slice(1)));
13482
13790
  }
13483
13791
  if (process.platform === "win32") {
13484
13792
  const normalized = normalizeWindowsRequestedPath(inputPath);
13485
- if (path12.win32.isAbsolute(normalized)) {
13486
- return path12.win32.normalize(normalized);
13793
+ if (path13.win32.isAbsolute(normalized)) {
13794
+ return path13.win32.normalize(normalized);
13487
13795
  }
13488
- return path12.win32.resolve(normalized);
13796
+ return path13.win32.resolve(normalized);
13489
13797
  }
13490
- if (path12.isAbsolute(inputPath)) {
13491
- return path12.normalize(inputPath);
13798
+ if (path13.isAbsolute(inputPath)) {
13799
+ return path13.normalize(inputPath);
13492
13800
  }
13493
- return path12.resolve(inputPath);
13801
+ return path13.resolve(inputPath);
13494
13802
  }
13495
13803
  function listDirectoryEntriesSafe(dirPath) {
13496
13804
  const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
13497
13805
  const files = [];
13498
13806
  for (const entry of entries) {
13499
- const entryPath = path12.join(dirPath, entry.name);
13807
+ const entryPath = path13.join(dirPath, entry.name);
13500
13808
  try {
13501
13809
  if (entry.isDirectory()) {
13502
13810
  files.push({ name: entry.name, type: "directory" });
@@ -13550,7 +13858,7 @@ async function handleFileRead(h, args) {
13550
13858
  async function handleFileWrite(h, args) {
13551
13859
  try {
13552
13860
  const filePath = resolveSafePath(args?.path);
13553
- fs5.mkdirSync(path12.dirname(filePath), { recursive: true });
13861
+ fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
13554
13862
  fs5.writeFileSync(filePath, args?.content || "", "utf-8");
13555
13863
  return { success: true, path: filePath };
13556
13864
  } catch (e) {
@@ -14334,9 +14642,11 @@ var DaemonCommandHandler = class {
14334
14642
  }
14335
14643
  const sessionLookupFailed = !!targetSessionId && !session;
14336
14644
  const managerKey = this.extractIdeType(args, sessionLookupFailed);
14337
- let providerType;
14645
+ let providerType = args?.agentType || args?.providerType;
14338
14646
  if (!sessionLookupFailed) {
14339
- providerType = session?.providerType || args?.agentType || args?.providerType || this.inferProviderType(managerKey);
14647
+ providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
14648
+ } else if (!providerType) {
14649
+ providerType = this.inferProviderType(managerKey);
14340
14650
  }
14341
14651
  return { session, managerKey, providerType, sessionLookupFailed };
14342
14652
  }
@@ -14416,7 +14726,8 @@ var DaemonCommandHandler = class {
14416
14726
  "pty_resize",
14417
14727
  "invoke_provider_script"
14418
14728
  ]);
14419
- if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd)) {
14729
+ 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);
14730
+ if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
14420
14731
  const result2 = {
14421
14732
  success: false,
14422
14733
  error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
@@ -14669,7 +14980,7 @@ var DaemonCommandHandler = class {
14669
14980
 
14670
14981
  // src/commands/cli-manager.ts
14671
14982
  var os13 = __toESM(require("os"));
14672
- var path16 = __toESM(require("path"));
14983
+ var path17 = __toESM(require("path"));
14673
14984
  var crypto4 = __toESM(require("crypto"));
14674
14985
  var import_fs6 = require("fs");
14675
14986
  var import_child_process6 = require("child_process");
@@ -14679,7 +14990,7 @@ init_config();
14679
14990
 
14680
14991
  // src/providers/cli-provider-instance.ts
14681
14992
  var os12 = __toESM(require("os"));
14682
- var path15 = __toESM(require("path"));
14993
+ var path16 = __toESM(require("path"));
14683
14994
  var crypto3 = __toESM(require("crypto"));
14684
14995
  var fs6 = __toESM(require("fs"));
14685
14996
  var import_node_module = require("module");
@@ -14738,7 +15049,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
14738
15049
  var CachedDatabaseSync = null;
14739
15050
  function getDatabaseSync() {
14740
15051
  if (CachedDatabaseSync) return CachedDatabaseSync;
14741
- const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path15.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
15052
+ const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
14742
15053
  const sqliteModule = requireFn(`node:${"sqlite"}`);
14743
15054
  CachedDatabaseSync = sqliteModule.DatabaseSync;
14744
15055
  if (!CachedDatabaseSync) {
@@ -14791,7 +15102,7 @@ var CliProviderInstance = class {
14791
15102
  this.providerSessionId = options?.providerSessionId;
14792
15103
  this.launchMode = options?.launchMode || "new";
14793
15104
  this.onProviderSessionResolved = options?.onProviderSessionResolved;
14794
- this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
15105
+ this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
14795
15106
  this.monitor = new StatusMonitor();
14796
15107
  this.historyWriter = new ChatHistoryWriter();
14797
15108
  }
@@ -15268,7 +15579,19 @@ var CliProviderInstance = class {
15268
15579
  }
15269
15580
  }
15270
15581
  pushEvent(event) {
15271
- this.events.push(event);
15582
+ const enrichedEvent = {
15583
+ ...event,
15584
+ instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
15585
+ targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
15586
+ providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
15587
+ workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
15588
+ providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
15589
+ };
15590
+ if (this.context?.emitProviderEvent) {
15591
+ this.context.emitProviderEvent(enrichedEvent);
15592
+ return;
15593
+ }
15594
+ this.events.push(enrichedEvent);
15272
15595
  }
15273
15596
  flushEvents() {
15274
15597
  const events = [...this.events];
@@ -15475,12 +15798,59 @@ ${effect.notification.body || ""}`.trim();
15475
15798
  );
15476
15799
  }
15477
15800
  }
15801
+ mergeRuntimeChatMessages(parsedMessages) {
15802
+ return this.mergeConversationMessages(parsedMessages);
15803
+ }
15478
15804
  mergeConversationMessages(parsedMessages) {
15479
15805
  if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
15480
- return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
15481
- const aTime = a.message.receivedAt || a.message.timestamp || 0;
15482
- const bTime = b.message.receivedAt || b.message.timestamp || 0;
15483
- if (aTime !== bTime) return aTime - bTime;
15806
+ const parsedEntries = parsedMessages.map((message, index) => ({
15807
+ message,
15808
+ index,
15809
+ source: "parsed"
15810
+ }));
15811
+ const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
15812
+ message: entry.message,
15813
+ index: parsedMessages.length + index,
15814
+ source: "runtime",
15815
+ runtimeKey: entry.key
15816
+ }));
15817
+ const getTime = (message) => {
15818
+ const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
15819
+ return Number.isFinite(value) && value > 0 ? value : 0;
15820
+ };
15821
+ const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
15822
+ const isRuntimeOverlay = (entry) => {
15823
+ if (entry.source !== "runtime") return false;
15824
+ const key = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
15825
+ if (key.startsWith("auto_approval:")) return true;
15826
+ return !isUserFacingChatMessage(entry.message);
15827
+ };
15828
+ const shouldKeepParsedBeforeUntimedRuntime = (message) => {
15829
+ const role = getRole(message);
15830
+ return role === "user" || role === "human";
15831
+ };
15832
+ const shouldKeepParsedAfterUntimedRuntime = (message) => {
15833
+ const role = getRole(message);
15834
+ if (role !== "assistant") return false;
15835
+ const kind = resolveChatMessageKind(message);
15836
+ return kind === "standard" || kind === "terminal";
15837
+ };
15838
+ return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
15839
+ const aTime = getTime(a.message);
15840
+ const bTime = getTime(b.message);
15841
+ if (aTime && bTime && aTime !== bTime) return aTime - bTime;
15842
+ if (a.source !== b.source && aTime !== bTime) {
15843
+ const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
15844
+ const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
15845
+ if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
15846
+ if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
15847
+ return a.source === "parsed" ? -1 : 1;
15848
+ }
15849
+ if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
15850
+ return a.source === "parsed" ? 1 : -1;
15851
+ }
15852
+ }
15853
+ }
15484
15854
  return a.index - b.index;
15485
15855
  }).map((entry) => entry.message));
15486
15856
  }
@@ -16804,11 +17174,11 @@ function shouldRestoreHostedRuntime(record, managerTag) {
16804
17174
  // src/commands/cli-manager.ts
16805
17175
  function isExplicitCommand(command) {
16806
17176
  const trimmed = command.trim();
16807
- return path16.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
17177
+ return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
16808
17178
  }
16809
17179
  function expandExecutable(command) {
16810
17180
  const trimmed = command.trim();
16811
- return trimmed.startsWith("~") ? path16.join(os13.homedir(), trimmed.slice(1)) : trimmed;
17181
+ return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
16812
17182
  }
16813
17183
  function commandExists(command) {
16814
17184
  const trimmed = command.trim();
@@ -16832,6 +17202,35 @@ function colorize(color, text) {
16832
17202
  const fn = chalkApi?.[color];
16833
17203
  return typeof fn === "function" ? fn(text) : text;
16834
17204
  }
17205
+ var COORDINATOR_DELEGATED_ENV_UNSETS = {
17206
+ ADHDEV_INLINE_MESH: "",
17207
+ ADHDEV_MCP_TRANSPORT: "",
17208
+ ADHDEV_MESH_ID: "",
17209
+ HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
17210
+ };
17211
+ function hasCliArg(args, flag) {
17212
+ return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
17213
+ }
17214
+ function ensureEmptyDelegatedMcpConfig(workspace) {
17215
+ const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
17216
+ (0, import_fs6.mkdirSync)(baseDir, { recursive: true });
17217
+ const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
17218
+ const filePath = path17.join(baseDir, `${workspaceHash}.json`);
17219
+ (0, import_fs6.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
17220
+ return filePath;
17221
+ }
17222
+ function buildCoordinatorDelegatedCliLaunchOptions(input) {
17223
+ const cliType = String(input.cliType || "").trim();
17224
+ const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
17225
+ const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
17226
+ if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
17227
+ cliArgs.unshift("--ignore-user-config");
17228
+ }
17229
+ if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
17230
+ cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
17231
+ }
17232
+ return { cliArgs, env };
17233
+ }
16835
17234
  function isUuid(value) {
16836
17235
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
16837
17236
  }
@@ -17002,7 +17401,7 @@ var DaemonCliManager = class {
17002
17401
  attachExisting
17003
17402
  }) || void 0;
17004
17403
  }
17005
- createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
17404
+ createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
17006
17405
  const normalizedType = this.providerLoader.resolveAlias(cliType);
17007
17406
  const provider = this.providerLoader.getMeta(normalizedType);
17008
17407
  if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
@@ -17016,7 +17415,7 @@ var DaemonCliManager = class {
17016
17415
  providerSessionId,
17017
17416
  attachExisting
17018
17417
  );
17019
- return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
17418
+ return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
17020
17419
  }
17021
17420
  throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
17022
17421
  }
@@ -17089,7 +17488,7 @@ var DaemonCliManager = class {
17089
17488
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
17090
17489
  const trimmed = (workingDir || "").trim();
17091
17490
  if (!trimmed) throw new Error("working directory required");
17092
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path16.resolve(trimmed);
17491
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
17093
17492
  const normalizedType = this.providerLoader.resolveAlias(cliType);
17094
17493
  const rawProvider = this.providerLoader.getByAlias(cliType);
17095
17494
  const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
@@ -17219,6 +17618,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
17219
17618
  {
17220
17619
  providerSessionId: sessionBinding.providerSessionId,
17221
17620
  launchMode: sessionBinding.launchMode,
17621
+ extraEnv: options?.extraEnv,
17222
17622
  onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
17223
17623
  this.persistRecentActivity({
17224
17624
  kind: "cli",
@@ -17239,7 +17639,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
17239
17639
  resolvedCliArgs,
17240
17640
  key,
17241
17641
  sessionBinding.providerSessionId,
17242
- false
17642
+ false,
17643
+ options?.extraEnv
17243
17644
  );
17244
17645
  try {
17245
17646
  await adapter.spawn();
@@ -17463,12 +17864,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
17463
17864
  const dir = resolved.path;
17464
17865
  const launchSource = resolved.source;
17465
17866
  if (!cliType) throw new Error("cliType required");
17867
+ const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
17868
+ const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
17869
+ cliType,
17870
+ workspace: dir,
17871
+ cliArgs: args?.cliArgs,
17872
+ env: args?.env
17873
+ }) : null;
17466
17874
  const started = await this.startSession(
17467
17875
  cliType,
17468
17876
  dir,
17469
- args?.cliArgs,
17877
+ delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
17470
17878
  args?.initialModel,
17471
- { resumeSessionId: args?.resumeSessionId, settingsOverride: args?.settings }
17879
+ {
17880
+ resumeSessionId: args?.resumeSessionId,
17881
+ settingsOverride,
17882
+ extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
17883
+ }
17472
17884
  );
17473
17885
  return {
17474
17886
  success: true,
@@ -17590,11 +18002,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
17590
18002
  var import_child_process7 = require("child_process");
17591
18003
  var net = __toESM(require("net"));
17592
18004
  var os15 = __toESM(require("os"));
17593
- var path18 = __toESM(require("path"));
18005
+ var path19 = __toESM(require("path"));
17594
18006
 
17595
18007
  // src/providers/provider-loader.ts
17596
18008
  var fs7 = __toESM(require("fs"));
17597
- var path17 = __toESM(require("path"));
18009
+ var path18 = __toESM(require("path"));
17598
18010
  var os14 = __toESM(require("os"));
17599
18011
  var chokidar = __toESM(require("chokidar"));
17600
18012
  init_logger();
@@ -17918,7 +18330,7 @@ var ProviderLoader = class _ProviderLoader {
17918
18330
  try {
17919
18331
  if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
17920
18332
  return ["ide", "extension", "cli", "acp"].some(
17921
- (category) => fs7.existsSync(path17.join(candidate, category))
18333
+ (category) => fs7.existsSync(path18.join(candidate, category))
17922
18334
  );
17923
18335
  } catch {
17924
18336
  return false;
@@ -17926,20 +18338,20 @@ var ProviderLoader = class _ProviderLoader {
17926
18338
  }
17927
18339
  static hasProviderRootMarker(candidate) {
17928
18340
  try {
17929
- return fs7.existsSync(path17.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
18341
+ return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
17930
18342
  } catch {
17931
18343
  return false;
17932
18344
  }
17933
18345
  }
17934
18346
  detectDefaultUserDir() {
17935
- const fallback = path17.join(os14.homedir(), ".adhdev", "providers");
18347
+ const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
17936
18348
  const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
17937
18349
  const visited = /* @__PURE__ */ new Set();
17938
18350
  for (const start of this.probeStarts) {
17939
- let current = path17.resolve(start);
18351
+ let current = path18.resolve(start);
17940
18352
  while (!visited.has(current)) {
17941
18353
  visited.add(current);
17942
- const siblingCandidate = path17.join(path17.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
18354
+ const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
17943
18355
  if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
17944
18356
  const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
17945
18357
  if (envOptIn || hasMarker) {
@@ -17961,7 +18373,7 @@ var ProviderLoader = class _ProviderLoader {
17961
18373
  return { path: siblingCandidate, source };
17962
18374
  }
17963
18375
  }
17964
- const parent = path17.dirname(current);
18376
+ const parent = path18.dirname(current);
17965
18377
  if (parent === current) break;
17966
18378
  current = parent;
17967
18379
  }
@@ -17971,11 +18383,11 @@ var ProviderLoader = class _ProviderLoader {
17971
18383
  constructor(options) {
17972
18384
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
17973
18385
  this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
17974
- this.defaultProvidersDir = path17.join(os14.homedir(), ".adhdev", "providers");
18386
+ this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
17975
18387
  const detected = this.detectDefaultUserDir();
17976
18388
  this.userDir = detected.path;
17977
18389
  this.userDirSource = detected.source;
17978
- this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
18390
+ this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
17979
18391
  this.disableUpstream = false;
17980
18392
  this.applySourceConfig({
17981
18393
  userDir: options?.userDir,
@@ -18034,7 +18446,7 @@ var ProviderLoader = class _ProviderLoader {
18034
18446
  this.userDir = detected.path;
18035
18447
  this.userDirSource = detected.source;
18036
18448
  }
18037
- this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
18449
+ this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
18038
18450
  this.disableUpstream = this.sourceMode === "no-upstream";
18039
18451
  if (this.explicitProviderDir) {
18040
18452
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
@@ -18048,7 +18460,7 @@ var ProviderLoader = class _ProviderLoader {
18048
18460
  * Canonical provider directory shape for a given root.
18049
18461
  */
18050
18462
  getProviderDir(root, category, type) {
18051
- return path17.join(root, category, type);
18463
+ return path18.join(root, category, type);
18052
18464
  }
18053
18465
  /**
18054
18466
  * Canonical user override directory for a provider.
@@ -18075,7 +18487,7 @@ var ProviderLoader = class _ProviderLoader {
18075
18487
  resolveProviderFile(type, ...segments) {
18076
18488
  const dir = this.findProviderDirInternal(type);
18077
18489
  if (!dir) return null;
18078
- return path17.join(dir, ...segments);
18490
+ return path18.join(dir, ...segments);
18079
18491
  }
18080
18492
  /**
18081
18493
  * Load all providers (3-tier priority)
@@ -18114,7 +18526,7 @@ var ProviderLoader = class _ProviderLoader {
18114
18526
  if (!fs7.existsSync(this.upstreamDir)) return false;
18115
18527
  try {
18116
18528
  return fs7.readdirSync(this.upstreamDir).some(
18117
- (d) => fs7.statSync(path17.join(this.upstreamDir, d)).isDirectory()
18529
+ (d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
18118
18530
  );
18119
18531
  } catch {
18120
18532
  return false;
@@ -18611,8 +19023,8 @@ var ProviderLoader = class _ProviderLoader {
18611
19023
  resolved._resolvedScriptDir = entry.scriptDir;
18612
19024
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
18613
19025
  if (providerDir) {
18614
- const fullDir = path17.join(providerDir, entry.scriptDir);
18615
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
19026
+ const fullDir = path18.join(providerDir, entry.scriptDir);
19027
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18616
19028
  }
18617
19029
  matched = true;
18618
19030
  }
@@ -18627,8 +19039,8 @@ var ProviderLoader = class _ProviderLoader {
18627
19039
  resolved._resolvedScriptDir = base.defaultScriptDir;
18628
19040
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
18629
19041
  if (providerDir) {
18630
- const fullDir = path17.join(providerDir, base.defaultScriptDir);
18631
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
19042
+ const fullDir = path18.join(providerDir, base.defaultScriptDir);
19043
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18632
19044
  }
18633
19045
  }
18634
19046
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -18645,8 +19057,8 @@ var ProviderLoader = class _ProviderLoader {
18645
19057
  resolved._resolvedScriptDir = dirOverride;
18646
19058
  resolved._resolvedScriptsSource = `versions:${range}`;
18647
19059
  if (providerDir) {
18648
- const fullDir = path17.join(providerDir, dirOverride);
18649
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
19060
+ const fullDir = path18.join(providerDir, dirOverride);
19061
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18650
19062
  }
18651
19063
  }
18652
19064
  } else if (override.scripts) {
@@ -18662,8 +19074,8 @@ var ProviderLoader = class _ProviderLoader {
18662
19074
  resolved._resolvedScriptDir = base.defaultScriptDir;
18663
19075
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
18664
19076
  if (providerDir) {
18665
- const fullDir = path17.join(providerDir, base.defaultScriptDir);
18666
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
19077
+ const fullDir = path18.join(providerDir, base.defaultScriptDir);
19078
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18667
19079
  }
18668
19080
  }
18669
19081
  }
@@ -18695,14 +19107,14 @@ var ProviderLoader = class _ProviderLoader {
18695
19107
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
18696
19108
  return null;
18697
19109
  }
18698
- const dir = path17.join(providerDir, scriptDir);
19110
+ const dir = path18.join(providerDir, scriptDir);
18699
19111
  if (!fs7.existsSync(dir)) {
18700
19112
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
18701
19113
  return null;
18702
19114
  }
18703
19115
  const cached = this.scriptsCache.get(dir);
18704
19116
  if (cached) return cached;
18705
- const scriptsJs = path17.join(dir, "scripts.js");
19117
+ const scriptsJs = path18.join(dir, "scripts.js");
18706
19118
  if (fs7.existsSync(scriptsJs)) {
18707
19119
  try {
18708
19120
  delete require.cache[require.resolve(scriptsJs)];
@@ -18744,7 +19156,7 @@ var ProviderLoader = class _ProviderLoader {
18744
19156
  return;
18745
19157
  }
18746
19158
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
18747
- this.log(`File changed: ${path17.basename(filePath)}, reloading...`);
19159
+ this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
18748
19160
  this.reload();
18749
19161
  }
18750
19162
  };
@@ -18799,7 +19211,7 @@ var ProviderLoader = class _ProviderLoader {
18799
19211
  }
18800
19212
  const https = require("https");
18801
19213
  const { execSync: execSync7 } = require("child_process");
18802
- const metaPath = path17.join(this.upstreamDir, _ProviderLoader.META_FILE);
19214
+ const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
18803
19215
  let prevEtag = "";
18804
19216
  let prevTimestamp = 0;
18805
19217
  try {
@@ -18859,17 +19271,17 @@ var ProviderLoader = class _ProviderLoader {
18859
19271
  return { updated: false };
18860
19272
  }
18861
19273
  this.log("Downloading latest providers from GitHub...");
18862
- const tmpTar = path17.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
18863
- const tmpExtract = path17.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
19274
+ const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
19275
+ const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
18864
19276
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
18865
19277
  fs7.mkdirSync(tmpExtract, { recursive: true });
18866
19278
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
18867
19279
  const extracted = fs7.readdirSync(tmpExtract);
18868
19280
  const rootDir = extracted.find(
18869
- (d) => fs7.statSync(path17.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
19281
+ (d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
18870
19282
  );
18871
19283
  if (!rootDir) throw new Error("Unexpected tarball structure");
18872
- const sourceDir = path17.join(tmpExtract, rootDir);
19284
+ const sourceDir = path18.join(tmpExtract, rootDir);
18873
19285
  const backupDir = this.upstreamDir + ".bak";
18874
19286
  if (fs7.existsSync(this.upstreamDir)) {
18875
19287
  if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
@@ -18944,8 +19356,8 @@ var ProviderLoader = class _ProviderLoader {
18944
19356
  copyDirRecursive(src, dest) {
18945
19357
  fs7.mkdirSync(dest, { recursive: true });
18946
19358
  for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
18947
- const srcPath = path17.join(src, entry.name);
18948
- const destPath = path17.join(dest, entry.name);
19359
+ const srcPath = path18.join(src, entry.name);
19360
+ const destPath = path18.join(dest, entry.name);
18949
19361
  if (entry.isDirectory()) {
18950
19362
  this.copyDirRecursive(srcPath, destPath);
18951
19363
  } else {
@@ -18956,7 +19368,7 @@ var ProviderLoader = class _ProviderLoader {
18956
19368
  /** .meta.json save */
18957
19369
  writeMeta(metaPath, etag, timestamp) {
18958
19370
  try {
18959
- fs7.mkdirSync(path17.dirname(metaPath), { recursive: true });
19371
+ fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
18960
19372
  fs7.writeFileSync(metaPath, JSON.stringify({
18961
19373
  etag,
18962
19374
  timestamp,
@@ -18973,7 +19385,7 @@ var ProviderLoader = class _ProviderLoader {
18973
19385
  const scan = (d) => {
18974
19386
  try {
18975
19387
  for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
18976
- if (entry.isDirectory()) scan(path17.join(d, entry.name));
19388
+ if (entry.isDirectory()) scan(path18.join(d, entry.name));
18977
19389
  else if (entry.name === "provider.json") count++;
18978
19390
  }
18979
19391
  } catch {
@@ -19201,17 +19613,17 @@ var ProviderLoader = class _ProviderLoader {
19201
19613
  for (const root of searchRoots) {
19202
19614
  if (!fs7.existsSync(root)) continue;
19203
19615
  const candidate = this.getProviderDir(root, cat, type);
19204
- if (fs7.existsSync(path17.join(candidate, "provider.json"))) return candidate;
19205
- const catDir = path17.join(root, cat);
19616
+ if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
19617
+ const catDir = path18.join(root, cat);
19206
19618
  if (fs7.existsSync(catDir)) {
19207
19619
  try {
19208
19620
  for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
19209
19621
  if (!entry.isDirectory()) continue;
19210
- const jsonPath = path17.join(catDir, entry.name, "provider.json");
19622
+ const jsonPath = path18.join(catDir, entry.name, "provider.json");
19211
19623
  if (fs7.existsSync(jsonPath)) {
19212
19624
  try {
19213
19625
  const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
19214
- if (data.type === type) return path17.join(catDir, entry.name);
19626
+ if (data.type === type) return path18.join(catDir, entry.name);
19215
19627
  } catch {
19216
19628
  }
19217
19629
  }
@@ -19228,7 +19640,7 @@ var ProviderLoader = class _ProviderLoader {
19228
19640
  * (template substitution is NOT applied here — scripts.js handles that)
19229
19641
  */
19230
19642
  buildScriptWrappersFromDir(dir) {
19231
- const scriptsJs = path17.join(dir, "scripts.js");
19643
+ const scriptsJs = path18.join(dir, "scripts.js");
19232
19644
  if (fs7.existsSync(scriptsJs)) {
19233
19645
  try {
19234
19646
  delete require.cache[require.resolve(scriptsJs)];
@@ -19242,7 +19654,7 @@ var ProviderLoader = class _ProviderLoader {
19242
19654
  for (const file of fs7.readdirSync(dir)) {
19243
19655
  if (!file.endsWith(".js")) continue;
19244
19656
  const scriptName = toCamel(file.replace(".js", ""));
19245
- const filePath = path17.join(dir, file);
19657
+ const filePath = path18.join(dir, file);
19246
19658
  result[scriptName] = (...args) => {
19247
19659
  try {
19248
19660
  let content = fs7.readFileSync(filePath, "utf-8");
@@ -19302,7 +19714,7 @@ var ProviderLoader = class _ProviderLoader {
19302
19714
  }
19303
19715
  const hasJson = entries.some((e) => e.name === "provider.json");
19304
19716
  if (hasJson) {
19305
- const jsonPath = path17.join(d, "provider.json");
19717
+ const jsonPath = path18.join(d, "provider.json");
19306
19718
  try {
19307
19719
  const raw = fs7.readFileSync(jsonPath, "utf-8");
19308
19720
  const mod = JSON.parse(raw);
@@ -19323,7 +19735,7 @@ var ProviderLoader = class _ProviderLoader {
19323
19735
  this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
19324
19736
  } else {
19325
19737
  const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
19326
- const scriptsPath = path17.join(d, "scripts.js");
19738
+ const scriptsPath = path18.join(d, "scripts.js");
19327
19739
  if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
19328
19740
  try {
19329
19741
  delete require.cache[require.resolve(scriptsPath)];
@@ -19349,7 +19761,7 @@ var ProviderLoader = class _ProviderLoader {
19349
19761
  if (!entry.isDirectory()) continue;
19350
19762
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
19351
19763
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
19352
- scan(path17.join(d, entry.name));
19764
+ scan(path18.join(d, entry.name));
19353
19765
  }
19354
19766
  }
19355
19767
  };
@@ -19674,8 +20086,8 @@ function detectCurrentWorkspace(ideId) {
19674
20086
  const appNameMap = getMacAppIdentifiers();
19675
20087
  const appName = appNameMap[ideId];
19676
20088
  if (appName) {
19677
- const storagePath = path18.join(
19678
- process.env.APPDATA || path18.join(os15.homedir(), "AppData", "Roaming"),
20089
+ const storagePath = path19.join(
20090
+ process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
19679
20091
  appName,
19680
20092
  "storage.json"
19681
20093
  );
@@ -19864,9 +20276,9 @@ init_logger();
19864
20276
 
19865
20277
  // src/logging/command-log.ts
19866
20278
  var fs8 = __toESM(require("fs"));
19867
- var path19 = __toESM(require("path"));
20279
+ var path20 = __toESM(require("path"));
19868
20280
  var os16 = __toESM(require("os"));
19869
- 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");
20281
+ 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");
19870
20282
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
19871
20283
  var MAX_DAYS = 7;
19872
20284
  try {
@@ -19904,13 +20316,13 @@ function getDateStr2() {
19904
20316
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
19905
20317
  }
19906
20318
  var currentDate2 = getDateStr2();
19907
- var currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20319
+ var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
19908
20320
  var writeCount2 = 0;
19909
20321
  function checkRotation() {
19910
20322
  const today = getDateStr2();
19911
20323
  if (today !== currentDate2) {
19912
20324
  currentDate2 = today;
19913
- currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20325
+ currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
19914
20326
  cleanOldFiles();
19915
20327
  }
19916
20328
  }
@@ -19924,7 +20336,7 @@ function cleanOldFiles() {
19924
20336
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
19925
20337
  if (dateMatch && dateMatch[1] < cutoffStr) {
19926
20338
  try {
19927
- fs8.unlinkSync(path19.join(LOG_DIR2, file));
20339
+ fs8.unlinkSync(path20.join(LOG_DIR2, file));
19928
20340
  } catch {
19929
20341
  }
19930
20342
  }
@@ -20007,14 +20419,66 @@ function getRecentCommands(count = 50) {
20007
20419
  cleanOldFiles();
20008
20420
 
20009
20421
  // src/commands/router.ts
20422
+ var yaml = __toESM(require("js-yaml"));
20010
20423
  init_logger();
20011
20424
 
20012
20425
  // src/commands/mesh-coordinator.ts
20013
- var import_node_fs2 = require("fs");
20426
+ var import_node_child_process3 = require("child_process");
20427
+ var import_node_fs3 = require("fs");
20014
20428
  var import_node_module2 = require("module");
20429
+ var os17 = __toESM(require("os"));
20015
20430
  var import_node_path = require("path");
20016
20431
  var DEFAULT_SERVER_NAME = "adhdev-mesh";
20017
20432
  var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
20433
+ var HERMES_CLI_TYPE = "hermes-cli";
20434
+ var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
20435
+ function isHermesProvider(provider, cliType) {
20436
+ const type = cliType?.trim() || provider?.type?.trim() || "";
20437
+ return type === HERMES_CLI_TYPE;
20438
+ }
20439
+ function resolveHermesMeshCoordinatorSetup(options) {
20440
+ const mcpServer = resolveAdhdevMcpServerLaunch({
20441
+ meshId: options.meshId,
20442
+ nodeExecutable: options.nodeExecutable,
20443
+ adhdevMcpEntryPath: options.adhdevMcpEntryPath
20444
+ });
20445
+ if (!mcpServer) {
20446
+ return {
20447
+ kind: "unsupported",
20448
+ reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
20449
+ };
20450
+ }
20451
+ const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
20452
+ if (!configPath.trim()) {
20453
+ return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
20454
+ }
20455
+ return {
20456
+ kind: "auto_import",
20457
+ serverName: DEFAULT_SERVER_NAME,
20458
+ configPath,
20459
+ configFormat: "hermes_config_yaml",
20460
+ mcpServer
20461
+ };
20462
+ }
20463
+ function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
20464
+ return {
20465
+ kind: "manual",
20466
+ serverName: DEFAULT_SERVER_NAME,
20467
+ configFormat: "hermes_config_yaml",
20468
+ configPathCommand: HERMES_MCP_CONFIG_PATH,
20469
+ requiresRestart: true,
20470
+ 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.",
20471
+ template: renderMeshCoordinatorTemplate(
20472
+ "mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
20473
+ {
20474
+ meshId,
20475
+ workspace,
20476
+ serverName: DEFAULT_SERVER_NAME,
20477
+ adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
20478
+ }
20479
+ )
20480
+ };
20481
+ }
20018
20482
  function resolveMeshCoordinatorSetup(options) {
20019
20483
  const { provider, meshId, workspace } = options;
20020
20484
  const config = provider?.meshCoordinator;
@@ -20024,6 +20488,9 @@ function resolveMeshCoordinatorSetup(options) {
20024
20488
  reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
20025
20489
  };
20026
20490
  }
20491
+ if (isHermesProvider(provider, options.cliType)) {
20492
+ return resolveHermesMeshCoordinatorSetup(options);
20493
+ }
20027
20494
  const mcpConfig = config.mcpConfig;
20028
20495
  if (!mcpConfig || mcpConfig.mode === "none") {
20029
20496
  return {
@@ -20033,8 +20500,8 @@ function resolveMeshCoordinatorSetup(options) {
20033
20500
  }
20034
20501
  const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
20035
20502
  if (mcpConfig.mode === "auto_import") {
20036
- const path26 = mcpConfig.path?.trim();
20037
- if (!path26) {
20503
+ const path27 = mcpConfig.path?.trim();
20504
+ if (!path27) {
20038
20505
  return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
20039
20506
  }
20040
20507
  const mcpServer = resolveAdhdevMcpServerLaunch({
@@ -20045,13 +20512,13 @@ function resolveMeshCoordinatorSetup(options) {
20045
20512
  if (!mcpServer) {
20046
20513
  return {
20047
20514
  kind: "unsupported",
20048
- reason: "Could not resolve the ADHDev MCP server entrypoint without relying on a PATH bin shim"
20515
+ reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
20049
20516
  };
20050
20517
  }
20051
20518
  return {
20052
20519
  kind: "auto_import",
20053
20520
  serverName,
20054
- configPath: (0, import_node_path.join)(workspace, path26),
20521
+ configPath: resolveMcpConfigPath(path27, workspace),
20055
20522
  configFormat: mcpConfig.format,
20056
20523
  mcpServer
20057
20524
  };
@@ -20085,14 +20552,85 @@ function resolveMeshCoordinatorSetup(options) {
20085
20552
  function renderMeshCoordinatorTemplate(template, values) {
20086
20553
  return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
20087
20554
  }
20555
+ function resolveMcpConfigPath(configPath, workspace) {
20556
+ const trimmed = configPath.trim();
20557
+ if (trimmed === "~") return os17.homedir();
20558
+ if (trimmed.startsWith("~/")) return (0, import_node_path.join)(os17.homedir(), trimmed.slice(2));
20559
+ if ((0, import_node_path.isAbsolute)(trimmed)) return trimmed;
20560
+ return (0, import_node_path.join)(workspace, trimmed);
20561
+ }
20088
20562
  function resolveAdhdevMcpServerLaunch(options) {
20089
20563
  const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
20090
20564
  if (!entryPath) return null;
20565
+ const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
20566
+ if (!nodeExecutable) return null;
20091
20567
  return {
20092
- command: options.nodeExecutable?.trim() || process.execPath,
20568
+ command: nodeExecutable,
20093
20569
  args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
20094
20570
  };
20095
20571
  }
20572
+ function resolveMcpNodeExecutable(explicitExecutable) {
20573
+ const explicit = explicitExecutable?.trim();
20574
+ if (explicit) return explicit;
20575
+ const candidates = [];
20576
+ const addCandidate = (candidate) => {
20577
+ const trimmed = candidate?.trim();
20578
+ if (!trimmed) return;
20579
+ const normalized = normalizeExistingPath(trimmed) || trimmed;
20580
+ if (!candidates.includes(normalized)) candidates.push(normalized);
20581
+ };
20582
+ addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
20583
+ addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
20584
+ addCandidate(process.env.npm_node_execpath);
20585
+ addNodeCandidatesFromPath(process.env.PATH, addCandidate);
20586
+ addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
20587
+ addCandidate("/opt/homebrew/bin/node");
20588
+ addCandidate("/usr/local/bin/node");
20589
+ addCandidate("/usr/bin/node");
20590
+ addCandidate(process.execPath);
20591
+ for (const candidate of candidates) {
20592
+ if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
20593
+ }
20594
+ return null;
20595
+ }
20596
+ function addNodeCandidatesFromPath(pathValue, addCandidate) {
20597
+ for (const entry of (pathValue || "").split(":")) {
20598
+ const dir = entry.trim();
20599
+ if (!dir) continue;
20600
+ addCandidate((0, import_node_path.join)(dir, "node"));
20601
+ }
20602
+ }
20603
+ function addNodeCandidatesFromNvm(homeDir, addCandidate) {
20604
+ const versionsDir = (0, import_node_path.join)(homeDir, ".nvm", "versions", "node");
20605
+ try {
20606
+ const versionDirs = (0, import_node_fs3.readdirSync)(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
20607
+ for (const versionDir of versionDirs) {
20608
+ addCandidate((0, import_node_path.join)(versionsDir, versionDir, "bin", "node"));
20609
+ }
20610
+ } catch {
20611
+ }
20612
+ }
20613
+ function compareNodeVersionNamesDescending(a, b) {
20614
+ const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
20615
+ const left = parse(a);
20616
+ const right = parse(b);
20617
+ for (let i = 0; i < Math.max(left.length, right.length); i++) {
20618
+ const diff = (right[i] || 0) - (left[i] || 0);
20619
+ if (diff !== 0) return diff;
20620
+ }
20621
+ return b.localeCompare(a);
20622
+ }
20623
+ function nodeRuntimeSupportsWebSocket(nodeExecutable) {
20624
+ try {
20625
+ (0, import_node_child_process3.execFileSync)(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
20626
+ stdio: "ignore",
20627
+ timeout: 3e3
20628
+ });
20629
+ return true;
20630
+ } catch {
20631
+ return false;
20632
+ }
20633
+ }
20096
20634
  function resolveAdhdevMcpEntryPath(explicitPath) {
20097
20635
  const explicit = explicitPath?.trim();
20098
20636
  if (explicit) return normalizeExistingPath(explicit) || explicit;
@@ -20128,15 +20666,109 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
20128
20666
  }
20129
20667
  function normalizeExistingPath(filePath) {
20130
20668
  try {
20131
- if (!(0, import_node_fs2.existsSync)(filePath)) return null;
20132
- return import_node_fs2.realpathSync.native(filePath);
20669
+ if (!(0, import_node_fs3.existsSync)(filePath)) return null;
20670
+ return import_node_fs3.realpathSync.native(filePath);
20133
20671
  } catch {
20134
20672
  return null;
20135
20673
  }
20136
20674
  }
20137
20675
 
20676
+ // src/mesh/mesh-events.ts
20677
+ init_mesh_config();
20678
+ init_logger();
20679
+ function readNonEmptyString(value) {
20680
+ return typeof value === "string" && value.trim() ? value.trim() : "";
20681
+ }
20682
+ function formatCompletionMetadata(event) {
20683
+ const parts = [
20684
+ readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
20685
+ readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
20686
+ readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
20687
+ ].filter(Boolean);
20688
+ return parts.length > 0 ? ` (${parts.join("; ")})` : "";
20689
+ }
20690
+ function buildMeshSystemMessage(args) {
20691
+ const metadata = formatCompletionMetadata(args.metadataEvent);
20692
+ if (args.event === "agent:generating_completed") {
20693
+ 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.`;
20694
+ }
20695
+ if (args.event === "agent:waiting_approval") {
20696
+ return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
20697
+ }
20698
+ return "";
20699
+ }
20700
+ function injectMeshSystemMessage(components, args) {
20701
+ const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
20702
+ const instState = inst.getState();
20703
+ if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
20704
+ if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
20705
+ return true;
20706
+ });
20707
+ if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
20708
+ const messageText = buildMeshSystemMessage({
20709
+ event: args.event,
20710
+ nodeLabel: args.nodeLabel,
20711
+ metadataEvent: args.metadataEvent
20712
+ });
20713
+ if (!messageText) return { success: false, error: "unsupported mesh event" };
20714
+ for (const coord of coordinatorInstances) {
20715
+ const coordState = coord.getState();
20716
+ LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
20717
+ coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
20718
+ }
20719
+ return { success: true, forwarded: coordinatorInstances.length };
20720
+ }
20721
+ function handleMeshForwardEvent(components, payload) {
20722
+ const eventName = readNonEmptyString(payload.event);
20723
+ if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
20724
+ return { success: false, error: "unsupported mesh event" };
20725
+ }
20726
+ const meshId = readNonEmptyString(payload.meshId);
20727
+ if (!meshId) return { success: false, error: "meshId required" };
20728
+ const nodeId = readNonEmptyString(payload.nodeId);
20729
+ const workspace = readNonEmptyString(payload.workspace);
20730
+ const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
20731
+ return injectMeshSystemMessage(components, {
20732
+ meshId,
20733
+ nodeLabel,
20734
+ event: eventName,
20735
+ metadataEvent: {
20736
+ targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
20737
+ providerType: readNonEmptyString(payload.providerType),
20738
+ providerSessionId: readNonEmptyString(payload.providerSessionId)
20739
+ }
20740
+ });
20741
+ }
20742
+ function setupMeshEventForwarding(components) {
20743
+ components.instanceManager.onEvent((event) => {
20744
+ if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
20745
+ const instanceId = readNonEmptyString(event.instanceId);
20746
+ if (!instanceId) return;
20747
+ const sourceInstance = components.instanceManager.getInstance(instanceId);
20748
+ if (!sourceInstance || sourceInstance.category !== "cli") return;
20749
+ const state = sourceInstance.getState();
20750
+ const workspace = readNonEmptyString(state.workspace);
20751
+ if (!workspace) return;
20752
+ const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
20753
+ const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
20754
+ const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
20755
+ const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
20756
+ if (!meshId) return;
20757
+ const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
20758
+ const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
20759
+ const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
20760
+ injectMeshSystemMessage(components, {
20761
+ meshId,
20762
+ sourceInstanceId: instanceId,
20763
+ nodeLabel,
20764
+ event: event.event,
20765
+ metadataEvent: event
20766
+ });
20767
+ });
20768
+ }
20769
+
20138
20770
  // src/status/snapshot.ts
20139
- var os17 = __toESM(require("os"));
20771
+ var os18 = __toESM(require("os"));
20140
20772
  init_config();
20141
20773
  init_terminal_screen();
20142
20774
  init_logger();
@@ -20192,8 +20824,8 @@ function buildAvailableProviders(providerLoader) {
20192
20824
  }
20193
20825
  function buildMachineInfo(profile = "full") {
20194
20826
  const base = {
20195
- hostname: os17.hostname(),
20196
- platform: os17.platform()
20827
+ hostname: os18.hostname(),
20828
+ platform: os18.platform()
20197
20829
  };
20198
20830
  if (profile === "live") {
20199
20831
  return base;
@@ -20202,23 +20834,23 @@ function buildMachineInfo(profile = "full") {
20202
20834
  const memSnap2 = getHostMemorySnapshot();
20203
20835
  return {
20204
20836
  ...base,
20205
- arch: os17.arch(),
20206
- cpus: os17.cpus().length,
20837
+ arch: os18.arch(),
20838
+ cpus: os18.cpus().length,
20207
20839
  totalMem: memSnap2.totalMem,
20208
- release: os17.release()
20840
+ release: os18.release()
20209
20841
  };
20210
20842
  }
20211
20843
  const memSnap = getHostMemorySnapshot();
20212
20844
  return {
20213
20845
  ...base,
20214
- arch: os17.arch(),
20215
- cpus: os17.cpus().length,
20846
+ arch: os18.arch(),
20847
+ cpus: os18.cpus().length,
20216
20848
  totalMem: memSnap.totalMem,
20217
20849
  freeMem: memSnap.freeMem,
20218
20850
  availableMem: memSnap.availableMem,
20219
- loadavg: os17.loadavg(),
20220
- uptime: os17.uptime(),
20221
- release: os17.release()
20851
+ loadavg: os18.loadavg(),
20852
+ uptime: os18.uptime(),
20853
+ release: os18.release()
20222
20854
  };
20223
20855
  }
20224
20856
  function parseMessageTime(value) {
@@ -20452,14 +21084,14 @@ function buildStatusSnapshot(options) {
20452
21084
  var import_child_process8 = require("child_process");
20453
21085
  var import_child_process9 = require("child_process");
20454
21086
  var fs9 = __toESM(require("fs"));
20455
- var os18 = __toESM(require("os"));
20456
- var path20 = __toESM(require("path"));
21087
+ var os19 = __toESM(require("os"));
21088
+ var path21 = __toESM(require("path"));
20457
21089
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
20458
21090
  function getUpgradeLogPath() {
20459
- const home = os18.homedir();
20460
- const dir = path20.join(home, ".adhdev");
21091
+ const home = os19.homedir();
21092
+ const dir = path21.join(home, ".adhdev");
20461
21093
  fs9.mkdirSync(dir, { recursive: true });
20462
- return path20.join(dir, "daemon-upgrade.log");
21094
+ return path21.join(dir, "daemon-upgrade.log");
20463
21095
  }
20464
21096
  function appendUpgradeLog(message) {
20465
21097
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -20470,14 +21102,14 @@ function appendUpgradeLog(message) {
20470
21102
  }
20471
21103
  }
20472
21104
  function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
20473
- const binDir = path20.dirname(nodeExecutable);
21105
+ const binDir = path21.dirname(nodeExecutable);
20474
21106
  if (platform10 === "win32") {
20475
- const npmCliPath = path20.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
21107
+ const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
20476
21108
  if (fs9.existsSync(npmCliPath)) {
20477
21109
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
20478
21110
  }
20479
21111
  for (const candidate of ["npm.exe", "npm"]) {
20480
- const candidatePath = path20.join(binDir, candidate);
21112
+ const candidatePath = path21.join(binDir, candidate);
20481
21113
  if (fs9.existsSync(candidatePath)) {
20482
21114
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
20483
21115
  }
@@ -20485,7 +21117,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
20485
21117
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
20486
21118
  }
20487
21119
  for (const candidate of ["npm"]) {
20488
- const candidatePath = path20.join(binDir, candidate);
21120
+ const candidatePath = path21.join(binDir, candidate);
20489
21121
  if (fs9.existsSync(candidatePath)) {
20490
21122
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
20491
21123
  }
@@ -20502,13 +21134,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20502
21134
  let currentDir = resolvedPath;
20503
21135
  try {
20504
21136
  if (fs9.statSync(resolvedPath).isFile()) {
20505
- currentDir = path20.dirname(resolvedPath);
21137
+ currentDir = path21.dirname(resolvedPath);
20506
21138
  }
20507
21139
  } catch {
20508
- currentDir = path20.dirname(resolvedPath);
21140
+ currentDir = path21.dirname(resolvedPath);
20509
21141
  }
20510
21142
  while (true) {
20511
- const packageJsonPath = path20.join(currentDir, "package.json");
21143
+ const packageJsonPath = path21.join(currentDir, "package.json");
20512
21144
  try {
20513
21145
  if (fs9.existsSync(packageJsonPath)) {
20514
21146
  const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
@@ -20519,7 +21151,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20519
21151
  }
20520
21152
  } catch {
20521
21153
  }
20522
- const parentDir = path20.dirname(currentDir);
21154
+ const parentDir = path21.dirname(currentDir);
20523
21155
  if (parentDir === currentDir) {
20524
21156
  return null;
20525
21157
  }
@@ -20527,13 +21159,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20527
21159
  }
20528
21160
  }
20529
21161
  function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
20530
- const nodeModulesDir = packageName.startsWith("@") ? path20.dirname(path20.dirname(packageRoot)) : path20.dirname(packageRoot);
20531
- if (path20.basename(nodeModulesDir) !== "node_modules") {
21162
+ const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
21163
+ if (path21.basename(nodeModulesDir) !== "node_modules") {
20532
21164
  return null;
20533
21165
  }
20534
- const maybeLibDir = path20.dirname(nodeModulesDir);
20535
- if (path20.basename(maybeLibDir) === "lib") {
20536
- return path20.dirname(maybeLibDir);
21166
+ const maybeLibDir = path21.dirname(nodeModulesDir);
21167
+ if (path21.basename(maybeLibDir) === "lib") {
21168
+ return path21.dirname(maybeLibDir);
20537
21169
  }
20538
21170
  return maybeLibDir;
20539
21171
  }
@@ -20648,7 +21280,7 @@ async function waitForPidExit(pid, timeoutMs) {
20648
21280
  }
20649
21281
  }
20650
21282
  function stopSessionHostProcesses(appName) {
20651
- const pidFile = path20.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
21283
+ const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
20652
21284
  try {
20653
21285
  if (fs9.existsSync(pidFile)) {
20654
21286
  const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
@@ -20665,7 +21297,7 @@ function stopSessionHostProcesses(appName) {
20665
21297
  }
20666
21298
  }
20667
21299
  function removeDaemonPidFile() {
20668
- const pidFile = path20.join(os18.homedir(), ".adhdev", "daemon.pid");
21300
+ const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
20669
21301
  try {
20670
21302
  fs9.unlinkSync(pidFile);
20671
21303
  } catch {
@@ -20676,7 +21308,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
20676
21308
  const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
20677
21309
  if (!npmRoot) return;
20678
21310
  const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
20679
- const binDir = process.platform === "win32" ? npmPrefix : path20.join(npmPrefix, "bin");
21311
+ const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
20680
21312
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
20681
21313
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
20682
21314
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -20684,25 +21316,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
20684
21316
  }
20685
21317
  if (pkgName.startsWith("@")) {
20686
21318
  const [scope, name] = pkgName.split("/");
20687
- const scopeDir = path20.join(npmRoot, scope);
21319
+ const scopeDir = path21.join(npmRoot, scope);
20688
21320
  if (!fs9.existsSync(scopeDir)) return;
20689
21321
  for (const entry of fs9.readdirSync(scopeDir)) {
20690
21322
  if (!entry.startsWith(`.${name}-`)) continue;
20691
- fs9.rmSync(path20.join(scopeDir, entry), { recursive: true, force: true });
20692
- appendUpgradeLog(`Removed stale scoped staging dir: ${path20.join(scopeDir, entry)}`);
21323
+ fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
21324
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
20693
21325
  }
20694
21326
  } else {
20695
21327
  for (const entry of fs9.readdirSync(npmRoot)) {
20696
21328
  if (!entry.startsWith(`.${pkgName}-`)) continue;
20697
- fs9.rmSync(path20.join(npmRoot, entry), { recursive: true, force: true });
20698
- appendUpgradeLog(`Removed stale staging dir: ${path20.join(npmRoot, entry)}`);
21329
+ fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
21330
+ appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
20699
21331
  }
20700
21332
  }
20701
21333
  if (fs9.existsSync(binDir)) {
20702
21334
  for (const entry of fs9.readdirSync(binDir)) {
20703
21335
  if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
20704
- fs9.rmSync(path20.join(binDir, entry), { recursive: true, force: true });
20705
- appendUpgradeLog(`Removed stale bin staging entry: ${path20.join(binDir, entry)}`);
21336
+ fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
21337
+ appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
20706
21338
  }
20707
21339
  }
20708
21340
  }
@@ -20803,6 +21435,56 @@ function normalizeReleaseChannel(value) {
20803
21435
  function resolveUpgradeChannel(args) {
20804
21436
  return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
20805
21437
  }
21438
+ function readProviderPriorityFromPolicy(policy) {
21439
+ const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
21440
+ const raw = record.providerPriority;
21441
+ if (!Array.isArray(raw)) return [];
21442
+ const seen = /* @__PURE__ */ new Set();
21443
+ return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
21444
+ if (seen.has(type)) return false;
21445
+ seen.add(type);
21446
+ return true;
21447
+ });
21448
+ }
21449
+ async function resolveProviderTypeFromPriority(args) {
21450
+ if (!args.providerPriority.length) {
21451
+ return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
21452
+ }
21453
+ const failed = [];
21454
+ for (const requestedType of args.providerPriority) {
21455
+ const normalizedType = args.providerLoader.resolveAlias(requestedType);
21456
+ if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
21457
+ failed.push(`${requestedType}: disabled`);
21458
+ continue;
21459
+ }
21460
+ const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
21461
+ args.providerLoader.setCliDetectionResults([{
21462
+ id: normalizedType,
21463
+ installed: !!detected,
21464
+ path: detected?.path
21465
+ }], false);
21466
+ args.onStatusChange?.();
21467
+ if (detected) return { providerType: normalizedType };
21468
+ failed.push(`${requestedType}: not detected`);
21469
+ }
21470
+ return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
21471
+ }
21472
+ function loadYamlModule() {
21473
+ return yaml;
21474
+ }
21475
+ function getMcpServersKey(format) {
21476
+ return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
21477
+ }
21478
+ function parseMeshCoordinatorMcpConfig(text, format) {
21479
+ if (!text.trim()) return {};
21480
+ if (format === "claude_mcp_json") return JSON.parse(text);
21481
+ const parsed = loadYamlModule().load(text);
21482
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
21483
+ }
21484
+ function serializeMeshCoordinatorMcpConfig(config, format) {
21485
+ if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
21486
+ return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
21487
+ }
20806
21488
  var CHAT_COMMANDS = [
20807
21489
  "send_chat",
20808
21490
  "new_chat",
@@ -20901,6 +21583,154 @@ var DaemonCommandRouter = class {
20901
21583
  constructor(deps) {
20902
21584
  this.deps = deps;
20903
21585
  }
21586
+ getCachedInlineMesh(meshId, inlineMesh) {
21587
+ if (inlineMesh && typeof inlineMesh === "object") {
21588
+ this.inlineMeshCache.set(meshId, inlineMesh);
21589
+ return inlineMesh;
21590
+ }
21591
+ return this.inlineMeshCache.get(meshId);
21592
+ }
21593
+ async getMeshForCommand(meshId, inlineMesh) {
21594
+ try {
21595
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21596
+ const mesh = getMesh3(meshId);
21597
+ if (mesh) return { mesh, inline: false };
21598
+ } catch {
21599
+ }
21600
+ const cached = this.getCachedInlineMesh(meshId, inlineMesh);
21601
+ return cached ? { mesh: cached, inline: true } : null;
21602
+ }
21603
+ updateInlineMeshNode(meshId, mesh, node) {
21604
+ if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
21605
+ const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
21606
+ if (idx >= 0) mesh.nodes[idx] = node;
21607
+ else mesh.nodes.push(node);
21608
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21609
+ this.inlineMeshCache.set(meshId, mesh);
21610
+ }
21611
+ removeInlineMeshNode(meshId, mesh, nodeId) {
21612
+ if (!mesh || !Array.isArray(mesh.nodes)) return false;
21613
+ const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
21614
+ if (idx === -1) return false;
21615
+ mesh.nodes.splice(idx, 1);
21616
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21617
+ this.inlineMeshCache.set(meshId, mesh);
21618
+ return true;
21619
+ }
21620
+ normalizeMeshSessionCleanupMode(value) {
21621
+ return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
21622
+ }
21623
+ sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
21624
+ const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
21625
+ if (!sessionId) return false;
21626
+ if (sessionIds?.size) return sessionIds.has(sessionId);
21627
+ const workspace = typeof node?.workspace === "string" ? node.workspace : "";
21628
+ if (workspace && record?.workspace === workspace) return true;
21629
+ if (record?.meta?.meshNodeId === nodeId) return true;
21630
+ return false;
21631
+ }
21632
+ isCompletedHostedSession(record) {
21633
+ return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
21634
+ }
21635
+ async cleanupMeshSessions(args) {
21636
+ if (args.mode === "preserve") {
21637
+ return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
21638
+ }
21639
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
21640
+ const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
21641
+ const sessions = await this.deps.sessionHostControl.listSessions();
21642
+ const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
21643
+ const hasExplicitSessionIds = !!requestedSessionIds?.size;
21644
+ const stoppedSessionIds = [];
21645
+ const deletedSessionIds = [];
21646
+ const skippedSessionIds = [];
21647
+ const skippedLiveSessionIds = [];
21648
+ const deleteUnsupportedSessionIds = [];
21649
+ const recordsRemainSessionIds = [];
21650
+ const errors = [];
21651
+ const matchedBySurfaceKind = {
21652
+ live_runtime: 0,
21653
+ recovery_snapshot: 0,
21654
+ inactive_record: 0
21655
+ };
21656
+ for (const record of matched) {
21657
+ const surfaceKind = getSessionHostSurfaceKind(record);
21658
+ matchedBySurfaceKind[surfaceKind] += 1;
21659
+ }
21660
+ for (const record of matched) {
21661
+ const sessionId = String(record.sessionId);
21662
+ const completed = this.isCompletedHostedSession(record);
21663
+ const surfaceKind = getSessionHostSurfaceKind(record);
21664
+ const liveRuntime = surfaceKind === "live_runtime";
21665
+ if (!hasExplicitSessionIds && liveRuntime) {
21666
+ skippedSessionIds.push(sessionId);
21667
+ skippedLiveSessionIds.push(sessionId);
21668
+ continue;
21669
+ }
21670
+ try {
21671
+ if (args.mode === "stop") {
21672
+ if (!completed) {
21673
+ if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
21674
+ stoppedSessionIds.push(sessionId);
21675
+ } else {
21676
+ skippedSessionIds.push(sessionId);
21677
+ }
21678
+ continue;
21679
+ }
21680
+ if (args.mode === "delete_stopped") {
21681
+ if (completed) {
21682
+ if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
21683
+ deletedSessionIds.push(sessionId);
21684
+ } else {
21685
+ skippedSessionIds.push(sessionId);
21686
+ }
21687
+ continue;
21688
+ }
21689
+ if (args.mode === "stop_and_delete") {
21690
+ if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
21691
+ deletedSessionIds.push(sessionId);
21692
+ continue;
21693
+ }
21694
+ } catch (e) {
21695
+ const message = e?.message || String(e);
21696
+ if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
21697
+ deleteUnsupportedSessionIds.push(sessionId);
21698
+ recordsRemainSessionIds.push(sessionId);
21699
+ if (args.mode === "stop_and_delete" && !completed) {
21700
+ try {
21701
+ await this.deps.sessionHostControl.stopSession(sessionId);
21702
+ stoppedSessionIds.push(sessionId);
21703
+ } catch (stopError) {
21704
+ errors.push({ sessionId, error: stopError?.message || String(stopError) });
21705
+ continue;
21706
+ }
21707
+ }
21708
+ skippedSessionIds.push(sessionId);
21709
+ continue;
21710
+ }
21711
+ errors.push({ sessionId, error: message });
21712
+ }
21713
+ }
21714
+ const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
21715
+ return {
21716
+ success: errors.length === 0,
21717
+ mode: args.mode,
21718
+ dryRun: args.dryRun === true,
21719
+ matchedCount: matched.length,
21720
+ matchedBySurfaceKind,
21721
+ stoppedSessionIds,
21722
+ deletedSessionIds,
21723
+ skippedSessionIds,
21724
+ skippedLiveSessionIds,
21725
+ ...deleteUnsupported ? {
21726
+ deleteUnsupported: true,
21727
+ effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
21728
+ deleteUnsupportedSessionIds,
21729
+ recordsRemainSessionIds
21730
+ } : {},
21731
+ ...errors.length ? { errors } : {}
21732
+ };
21733
+ }
20904
21734
  async traceSessionHostAction(action, args, run, summarizeResult) {
20905
21735
  const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
20906
21736
  const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
@@ -21020,6 +21850,9 @@ var DaemonCommandRouter = class {
21020
21850
  async executeDaemonCommand(cmd, args) {
21021
21851
  switch (cmd) {
21022
21852
  // ─── CLI / ACP commands ───
21853
+ case "mesh_forward_event": {
21854
+ return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
21855
+ }
21023
21856
  case "launch_cli":
21024
21857
  case "stop_cli":
21025
21858
  case "set_cli_view_mode":
@@ -21564,7 +22397,26 @@ var DaemonCommandRouter = class {
21564
22397
  if (!name) return { success: false, error: "name required" };
21565
22398
  try {
21566
22399
  const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21567
- const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
22400
+ const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
22401
+ return { success: true, mesh };
22402
+ } catch (e) {
22403
+ return { success: false, error: e.message };
22404
+ }
22405
+ }
22406
+ case "update_mesh": {
22407
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22408
+ if (!meshId) return { success: false, error: "meshId required" };
22409
+ try {
22410
+ const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22411
+ const patch = {};
22412
+ if (typeof args?.name === "string") patch.name = args.name;
22413
+ if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
22414
+ if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
22415
+ if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
22416
+ if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
22417
+ const mesh = updateMesh2(meshId, patch);
22418
+ if (!mesh) return { success: false, error: "Mesh not found" };
22419
+ this.inlineMeshCache.set(meshId, mesh);
21568
22420
  return { success: true, mesh };
21569
22421
  } catch (e) {
21570
22422
  return { success: false, error: e.message };
@@ -21588,21 +22440,164 @@ var DaemonCommandRouter = class {
21588
22440
  if (!workspace) return { success: false, error: "workspace required" };
21589
22441
  try {
21590
22442
  const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21591
- const node = addNode3(meshId, { workspace });
22443
+ const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
22444
+ const readOnly = args?.readOnly === true;
22445
+ const policy = {
22446
+ ...readOnly ? { readOnly: true } : {},
22447
+ ...providerPriority.length ? { providerPriority } : {}
22448
+ };
22449
+ const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
21592
22450
  if (!node) return { success: false, error: "Mesh not found" };
21593
22451
  return { success: true, node };
21594
22452
  } catch (e) {
21595
22453
  return { success: false, error: e.message };
21596
22454
  }
21597
22455
  }
22456
+ case "update_mesh_node": {
22457
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22458
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
22459
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
22460
+ try {
22461
+ const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22462
+ const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
22463
+ if (Array.isArray(args?.providerPriority)) {
22464
+ const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
22465
+ delete policy.provider_priority;
22466
+ if (providerPriority.length) {
22467
+ policy.providerPriority = providerPriority;
22468
+ } else {
22469
+ delete policy.providerPriority;
22470
+ }
22471
+ }
22472
+ const node = updateNode2(meshId, nodeId, { policy });
22473
+ if (!node) return { success: false, error: "Mesh node not found" };
22474
+ return { success: true, node };
22475
+ } catch (e) {
22476
+ return { success: false, error: e.message };
22477
+ }
22478
+ }
22479
+ case "cleanup_mesh_sessions": {
22480
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22481
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
22482
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
22483
+ try {
22484
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22485
+ const mesh = meshRecord?.mesh;
22486
+ if (!mesh) return { success: false, error: "Mesh not found" };
22487
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
22488
+ if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
22489
+ const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
22490
+ const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
22491
+ const result = await this.cleanupMeshSessions({
22492
+ meshId,
22493
+ nodeId,
22494
+ node,
22495
+ mode,
22496
+ sessionIds,
22497
+ dryRun: args?.dryRun === true
22498
+ });
22499
+ return result;
22500
+ } catch (e) {
22501
+ return { success: false, error: e.message };
22502
+ }
22503
+ }
21598
22504
  case "remove_mesh_node": {
21599
22505
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21600
22506
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
21601
22507
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
21602
22508
  try {
21603
- const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21604
- const removed = removeNode3(meshId, nodeId);
21605
- return { success: true, removed };
22509
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22510
+ const mesh = meshRecord?.mesh;
22511
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
22512
+ const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
22513
+ args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
22514
+ );
22515
+ let sessionCleanup;
22516
+ if (node && sessionCleanupMode !== "preserve") {
22517
+ sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
22518
+ if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
22519
+ }
22520
+ if (node?.isLocalWorktree && node.workspace) {
22521
+ try {
22522
+ const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
22523
+ const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
22524
+ if (repoRoot) {
22525
+ const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22526
+ await removeWorktree2(repoRoot, node.workspace);
22527
+ }
22528
+ } catch (e) {
22529
+ LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
22530
+ }
22531
+ }
22532
+ let removed = false;
22533
+ if (meshRecord?.inline) {
22534
+ removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
22535
+ } else {
22536
+ const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22537
+ removed = removeNode3(meshId, nodeId);
22538
+ }
22539
+ return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
22540
+ } catch (e) {
22541
+ return { success: false, error: e.message };
22542
+ }
22543
+ }
22544
+ case "clone_mesh_node": {
22545
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22546
+ const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
22547
+ const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
22548
+ const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
22549
+ if (!meshId) return { success: false, error: "meshId required" };
22550
+ if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
22551
+ if (!branch) return { success: false, error: "branch required" };
22552
+ try {
22553
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22554
+ const mesh = meshRecord?.mesh;
22555
+ if (!mesh) return { success: false, error: "Mesh not found" };
22556
+ const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
22557
+ if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
22558
+ const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
22559
+ const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22560
+ const result = await createWorktree2({
22561
+ repoRoot,
22562
+ branch,
22563
+ baseBranch,
22564
+ meshName: mesh.name
22565
+ });
22566
+ let node;
22567
+ if (meshRecord.inline) {
22568
+ const { randomUUID: randomUUID8 } = await import("crypto");
22569
+ node = {
22570
+ id: `node_${randomUUID8().replace(/-/g, "")}`,
22571
+ workspace: result.worktreePath,
22572
+ repoRoot: result.worktreePath,
22573
+ daemonId: sourceNode.daemonId,
22574
+ userOverrides: { ...sourceNode.userOverrides || {} },
22575
+ policy: { ...sourceNode.policy || {} },
22576
+ isLocalWorktree: true,
22577
+ worktreeBranch: result.branch,
22578
+ clonedFromNodeId: sourceNodeId
22579
+ };
22580
+ this.updateInlineMeshNode(meshId, mesh, node);
22581
+ } else {
22582
+ const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22583
+ node = addNode3(meshId, {
22584
+ workspace: result.worktreePath,
22585
+ repoRoot: result.worktreePath,
22586
+ daemonId: sourceNode.daemonId,
22587
+ userOverrides: { ...sourceNode.userOverrides || {} },
22588
+ isLocalWorktree: true,
22589
+ worktreeBranch: result.branch,
22590
+ clonedFromNodeId: sourceNodeId,
22591
+ policy: { ...sourceNode.policy || {} }
22592
+ });
22593
+ if (!node) return { success: false, error: "Failed to register worktree node" };
22594
+ }
22595
+ return {
22596
+ success: true,
22597
+ node,
22598
+ worktreePath: result.worktreePath,
22599
+ branch: result.branch
22600
+ };
21606
22601
  } catch (e) {
21607
22602
  return { success: false, error: e.message };
21608
22603
  }
@@ -21610,7 +22605,7 @@ var DaemonCommandRouter = class {
21610
22605
  // ─── Mesh Coordinator Launch ───
21611
22606
  case "launch_mesh_coordinator": {
21612
22607
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21613
- const cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "claude-cli";
22608
+ let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
21614
22609
  if (!meshId) return { success: false, error: "meshId required" };
21615
22610
  try {
21616
22611
  const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
@@ -21638,9 +22633,29 @@ var DaemonCommandRouter = class {
21638
22633
  }
21639
22634
  const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
21640
22635
  if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
22636
+ if (!cliType) {
22637
+ const resolved = await resolveProviderTypeFromPriority({
22638
+ nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
22639
+ providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
22640
+ providerLoader: this.deps.providerLoader,
22641
+ onStatusChange: this.deps.onStatusChange
22642
+ });
22643
+ if (!resolved.providerType) {
22644
+ return {
22645
+ success: false,
22646
+ code: "mesh_coordinator_provider_priority_unusable",
22647
+ error: resolved.error || "No usable provider found from node providerPriority",
22648
+ meshId,
22649
+ cliType,
22650
+ workspace
22651
+ };
22652
+ }
22653
+ cliType = resolved.providerType;
22654
+ }
21641
22655
  const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
21642
22656
  const coordinatorSetup = resolveMeshCoordinatorSetup({
21643
22657
  provider: providerMeta,
22658
+ cliType,
21644
22659
  meshId,
21645
22660
  workspace
21646
22661
  });
@@ -21665,7 +22680,8 @@ var DaemonCommandRouter = class {
21665
22680
  meshCoordinatorSetup: coordinatorSetup
21666
22681
  };
21667
22682
  }
21668
- if (coordinatorSetup.configFormat !== "claude_mcp_json") {
22683
+ const configFormat = coordinatorSetup.configFormat;
22684
+ if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
21669
22685
  return {
21670
22686
  success: false,
21671
22687
  code: "mesh_coordinator_unsupported",
@@ -21675,17 +22691,34 @@ var DaemonCommandRouter = class {
21675
22691
  workspace
21676
22692
  };
21677
22693
  }
21678
- const { existsSync: existsSync22, readFileSync: readFileSync15, writeFileSync: writeFileSync12, copyFileSync: copyFileSync3 } = await import("fs");
21679
- const mcpConfigPath = coordinatorSetup.configPath;
21680
- const hadExistingMcpConfig = existsSync22(mcpConfigPath);
21681
- let existingMcpConfig = {};
21682
- if (hadExistingMcpConfig) {
21683
- try {
21684
- existingMcpConfig = JSON.parse(readFileSync15(mcpConfigPath, "utf-8"));
21685
- copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
21686
- } catch {
21687
- }
22694
+ let systemPrompt = "";
22695
+ try {
22696
+ systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
22697
+ } catch (error) {
22698
+ const message = error?.message || String(error);
22699
+ LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
22700
+ return {
22701
+ success: false,
22702
+ code: "mesh_coordinator_prompt_failed",
22703
+ error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
22704
+ meshId,
22705
+ cliType,
22706
+ workspace
22707
+ };
21688
22708
  }
22709
+ const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
22710
+ const { dirname: dirname9 } = await import("path");
22711
+ const mcpConfigPath = coordinatorSetup.configPath;
22712
+ const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
22713
+ const returnManualFallback = (message) => ({
22714
+ success: false,
22715
+ code: "mesh_coordinator_manual_mcp_setup_required",
22716
+ error: message,
22717
+ meshId,
22718
+ cliType,
22719
+ workspace,
22720
+ meshCoordinatorSetup: hermesManualFallback
22721
+ });
21689
22722
  const mcpServerEntry = {
21690
22723
  command: coordinatorSetup.mcpServer.command,
21691
22724
  args: coordinatorSetup.mcpServer.args
@@ -21696,24 +22729,55 @@ var DaemonCommandRouter = class {
21696
22729
  ADHDEV_MCP_TRANSPORT: "ipc"
21697
22730
  };
21698
22731
  }
22732
+ try {
22733
+ mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
22734
+ } catch (error) {
22735
+ const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
22736
+ LOG.error("MeshCoordinator", message);
22737
+ if (hermesManualFallback) return returnManualFallback(message);
22738
+ return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
22739
+ }
22740
+ const hadExistingMcpConfig = existsSync23(mcpConfigPath);
22741
+ let existingMcpConfig = {};
22742
+ if (hadExistingMcpConfig) {
22743
+ try {
22744
+ existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
22745
+ copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
22746
+ } catch (error) {
22747
+ LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
22748
+ return {
22749
+ success: false,
22750
+ code: "mesh_coordinator_config_parse_failed",
22751
+ error: `Failed to parse existing MCP config at ${mcpConfigPath}`
22752
+ };
22753
+ }
22754
+ }
22755
+ const mcpServersKey = getMcpServersKey(configFormat);
22756
+ const existingServers = existingMcpConfig[mcpServersKey];
21699
22757
  const mcpConfig = {
21700
22758
  ...existingMcpConfig,
21701
- mcpServers: {
21702
- ...existingMcpConfig.mcpServers || {},
22759
+ [mcpServersKey]: {
22760
+ ...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
21703
22761
  [coordinatorSetup.serverName]: mcpServerEntry
21704
22762
  }
21705
22763
  };
21706
- writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
21707
- LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
21708
- let systemPrompt = "";
21709
22764
  try {
21710
- systemPrompt = buildCoordinatorSystemPrompt2({ mesh });
21711
- } catch {
21712
- 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).`;
22765
+ writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
22766
+ } catch (error) {
22767
+ const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
22768
+ LOG.error("MeshCoordinator", message);
22769
+ if (hermesManualFallback) return returnManualFallback(message);
22770
+ return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
21713
22771
  }
22772
+ LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
21714
22773
  const cliArgs = [];
22774
+ const launchEnv = {};
21715
22775
  if (systemPrompt) {
21716
- cliArgs.push("--append-system-prompt", systemPrompt);
22776
+ if (configFormat === "hermes_config_yaml") {
22777
+ launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
22778
+ } else {
22779
+ cliArgs.push("--append-system-prompt", systemPrompt);
22780
+ }
21717
22781
  }
21718
22782
  if (cliType === "claude-cli") {
21719
22783
  cliArgs.push("--mcp-config", coordinatorSetup.configPath);
@@ -21722,6 +22786,7 @@ var DaemonCommandRouter = class {
21722
22786
  cliType,
21723
22787
  dir: workspace,
21724
22788
  cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
22789
+ env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
21725
22790
  settings: {
21726
22791
  meshCoordinatorFor: meshId
21727
22792
  }
@@ -21901,6 +22966,12 @@ var DaemonStatusReporter = class {
21901
22966
  if (providerType) {
21902
22967
  payload.providerType = providerType;
21903
22968
  }
22969
+ if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
22970
+ payload.providerSessionId = event.providerSessionId.trim();
22971
+ }
22972
+ if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
22973
+ payload.workspaceName = event.workspaceName.trim();
22974
+ }
21904
22975
  if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
21905
22976
  payload.duration = event.duration;
21906
22977
  }
@@ -23148,7 +24219,10 @@ var ProviderInstanceManager = class {
23148
24219
  this.instances.get(id).dispose();
23149
24220
  }
23150
24221
  this.instances.set(id, instance);
23151
- await instance.init(context);
24222
+ await instance.init({
24223
+ ...context,
24224
+ emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
24225
+ });
23152
24226
  }
23153
24227
  /**
23154
24228
  * Instance remove
@@ -23310,6 +24384,17 @@ var ProviderInstanceManager = class {
23310
24384
  onEvent(listener) {
23311
24385
  this.eventListeners.push(listener);
23312
24386
  }
24387
+ emitProviderEvent(providerType, instanceId, event) {
24388
+ const payload = {
24389
+ ...event,
24390
+ providerType,
24391
+ instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
24392
+ targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
24393
+ };
24394
+ for (const listener of this.eventListeners) {
24395
+ listener(payload);
24396
+ }
24397
+ }
23313
24398
  emitPendingEvents(providerType, state, extra = {}) {
23314
24399
  for (const event of state.pendingEvents) {
23315
24400
  for (const listener of this.eventListeners) {
@@ -23382,11 +24467,11 @@ var ProviderInstanceManager = class {
23382
24467
 
23383
24468
  // src/providers/version-archive.ts
23384
24469
  var fs11 = __toESM(require("fs"));
23385
- var path21 = __toESM(require("path"));
23386
- var os19 = __toESM(require("os"));
24470
+ var path22 = __toESM(require("path"));
24471
+ var os20 = __toESM(require("os"));
23387
24472
  var import_child_process10 = require("child_process");
23388
24473
  var import_os3 = require("os");
23389
- var ARCHIVE_PATH = path21.join(os19.homedir(), ".adhdev", "version-history.json");
24474
+ var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
23390
24475
  var MAX_ENTRIES_PER_PROVIDER = 20;
23391
24476
  var VersionArchive = class {
23392
24477
  history = {};
@@ -23433,7 +24518,7 @@ var VersionArchive = class {
23433
24518
  }
23434
24519
  save() {
23435
24520
  try {
23436
- fs11.mkdirSync(path21.dirname(ARCHIVE_PATH), { recursive: true });
24521
+ fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
23437
24522
  fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
23438
24523
  } catch {
23439
24524
  }
@@ -23489,8 +24574,8 @@ function getVersion(binary, versionCommand) {
23489
24574
  function checkPathExists2(paths) {
23490
24575
  for (const p of paths) {
23491
24576
  if (p.includes("*")) {
23492
- const home = os19.homedir();
23493
- const resolved = p.replace(/\*/g, home.split(path21.sep).pop() || "");
24577
+ const home = os20.homedir();
24578
+ const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
23494
24579
  if (fs11.existsSync(resolved)) return resolved;
23495
24580
  } else {
23496
24581
  if (fs11.existsSync(p)) return p;
@@ -23500,7 +24585,7 @@ function checkPathExists2(paths) {
23500
24585
  }
23501
24586
  function getMacAppVersion(appPath) {
23502
24587
  if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
23503
- const plistPath = path21.join(appPath, "Contents", "Info.plist");
24588
+ const plistPath = path22.join(appPath, "Contents", "Info.plist");
23504
24589
  if (!fs11.existsSync(plistPath)) return null;
23505
24590
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
23506
24591
  return raw || null;
@@ -23526,7 +24611,7 @@ async function detectAllVersions(loader, archive) {
23526
24611
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
23527
24612
  let resolvedBin = cliBin;
23528
24613
  if (!resolvedBin && appPath && currentOs === "darwin") {
23529
- const bundled = path21.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
24614
+ const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
23530
24615
  if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
23531
24616
  }
23532
24617
  info.installed = !!(appPath || resolvedBin);
@@ -23567,7 +24652,7 @@ async function detectAllVersions(loader, archive) {
23567
24652
  // src/daemon/dev-server.ts
23568
24653
  var http2 = __toESM(require("http"));
23569
24654
  var fs15 = __toESM(require("fs"));
23570
- var path25 = __toESM(require("path"));
24655
+ var path26 = __toESM(require("path"));
23571
24656
  init_config();
23572
24657
 
23573
24658
  // src/daemon/scaffold-template.ts
@@ -23918,7 +25003,7 @@ init_logger();
23918
25003
 
23919
25004
  // src/daemon/dev-cdp-handlers.ts
23920
25005
  var fs12 = __toESM(require("fs"));
23921
- var path22 = __toESM(require("path"));
25006
+ var path23 = __toESM(require("path"));
23922
25007
  init_logger();
23923
25008
  async function handleCdpEvaluate(ctx, req, res) {
23924
25009
  const body = await ctx.readBody(req);
@@ -24097,17 +25182,17 @@ async function handleScriptHints(ctx, type, _req, res) {
24097
25182
  return;
24098
25183
  }
24099
25184
  let scriptsPath = "";
24100
- const directScripts = path22.join(dir, "scripts.js");
25185
+ const directScripts = path23.join(dir, "scripts.js");
24101
25186
  if (fs12.existsSync(directScripts)) {
24102
25187
  scriptsPath = directScripts;
24103
25188
  } else {
24104
- const scriptsDir = path22.join(dir, "scripts");
25189
+ const scriptsDir = path23.join(dir, "scripts");
24105
25190
  if (fs12.existsSync(scriptsDir)) {
24106
25191
  const versions = fs12.readdirSync(scriptsDir).filter((d) => {
24107
- return fs12.statSync(path22.join(scriptsDir, d)).isDirectory();
25192
+ return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
24108
25193
  }).sort().reverse();
24109
25194
  for (const ver of versions) {
24110
- const p = path22.join(scriptsDir, ver, "scripts.js");
25195
+ const p = path23.join(scriptsDir, ver, "scripts.js");
24111
25196
  if (fs12.existsSync(p)) {
24112
25197
  scriptsPath = p;
24113
25198
  break;
@@ -24936,7 +26021,7 @@ async function handleDomContext(ctx, type, req, res) {
24936
26021
 
24937
26022
  // src/daemon/dev-cli-debug.ts
24938
26023
  var fs13 = __toESM(require("fs"));
24939
- var path23 = __toESM(require("path"));
26024
+ var path24 = __toESM(require("path"));
24940
26025
  function slugifyFixtureName(value) {
24941
26026
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
24942
26027
  return normalized || `fixture-${Date.now()}`;
@@ -24946,11 +26031,11 @@ function getCliFixtureDir(ctx, type) {
24946
26031
  if (!providerDir) {
24947
26032
  throw new Error(`Provider directory not found for '${type}'`);
24948
26033
  }
24949
- return path23.join(providerDir, "fixtures");
26034
+ return path24.join(providerDir, "fixtures");
24950
26035
  }
24951
26036
  function readCliFixture(ctx, type, name) {
24952
26037
  const fixtureDir = getCliFixtureDir(ctx, type);
24953
- const filePath = path23.join(fixtureDir, `${name}.json`);
26038
+ const filePath = path24.join(fixtureDir, `${name}.json`);
24954
26039
  if (!fs13.existsSync(filePath)) {
24955
26040
  throw new Error(`Fixture not found: ${filePath}`);
24956
26041
  }
@@ -25118,7 +26203,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
25118
26203
  if (!adapter) return null;
25119
26204
  return { target, instance, adapter };
25120
26205
  }
25121
- function sleep(ms) {
26206
+ function sleep2(ms) {
25122
26207
  return new Promise((resolve16) => setTimeout(resolve16, ms));
25123
26208
  }
25124
26209
  async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
@@ -25135,7 +26220,7 @@ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
25135
26220
  return bundle;
25136
26221
  }
25137
26222
  }
25138
- await sleep(100);
26223
+ await sleep2(100);
25139
26224
  }
25140
26225
  return getCliTargetBundle(ctx, type, instanceId);
25141
26226
  }
@@ -25191,7 +26276,7 @@ async function runCliExerciseInternal(ctx, body) {
25191
26276
  const message = String(lastLaunchError.message || "");
25192
26277
  const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
25193
26278
  if (!retryable || attempt === 2) break;
25194
- await sleep(1e3);
26279
+ await sleep2(1e3);
25195
26280
  }
25196
26281
  }
25197
26282
  if (!launched) {
@@ -25254,16 +26339,16 @@ async function runCliExerciseInternal(ctx, body) {
25254
26339
  const modal = debug?.activeModal || trace?.activeModal || null;
25255
26340
  noteStatus(status);
25256
26341
  if (resolveActiveModalIfNeeded(status, modal)) {
25257
- await sleep(150);
26342
+ await sleep2(150);
25258
26343
  continue;
25259
26344
  }
25260
26345
  const startupParseGate = !!debug?.startupParseGate;
25261
26346
  if (status === "idle" && !startupParseGate) break;
25262
- await sleep(150);
26347
+ await sleep2(150);
25263
26348
  }
25264
26349
  ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
25265
26350
  while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
25266
- await sleep(150);
26351
+ await sleep2(150);
25267
26352
  bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
25268
26353
  if (!bundle) {
25269
26354
  throw new Error("CLI instance disappeared during exercise");
@@ -25717,7 +26802,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
25717
26802
  },
25718
26803
  notes: typeof body?.notes === "string" ? body.notes : void 0
25719
26804
  };
25720
- const filePath = path23.join(fixtureDir, `${name}.json`);
26805
+ const filePath = path24.join(fixtureDir, `${name}.json`);
25721
26806
  fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
25722
26807
  ctx.json(res, 200, {
25723
26808
  saved: true,
@@ -25741,7 +26826,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
25741
26826
  return;
25742
26827
  }
25743
26828
  const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
25744
- const fullPath = path23.join(fixtureDir, file);
26829
+ const fullPath = path24.join(fixtureDir, file);
25745
26830
  try {
25746
26831
  const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
25747
26832
  return {
@@ -25877,8 +26962,8 @@ async function handleCliRaw(ctx, req, res) {
25877
26962
 
25878
26963
  // src/daemon/dev-auto-implement.ts
25879
26964
  var fs14 = __toESM(require("fs"));
25880
- var path24 = __toESM(require("path"));
25881
- var os20 = __toESM(require("os"));
26965
+ var path25 = __toESM(require("path"));
26966
+ var os21 = __toESM(require("os"));
25882
26967
  function getAutoImplPid(ctx) {
25883
26968
  const pid = ctx.autoImplProcess?.pid;
25884
26969
  return typeof pid === "number" && pid > 0 ? pid : null;
@@ -25927,22 +27012,22 @@ function getLatestScriptVersionDir(scriptsDir) {
25927
27012
  if (!fs14.existsSync(scriptsDir)) return null;
25928
27013
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
25929
27014
  try {
25930
- return fs14.statSync(path24.join(scriptsDir, d)).isDirectory();
27015
+ return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
25931
27016
  } catch {
25932
27017
  return false;
25933
27018
  }
25934
27019
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
25935
27020
  if (versions.length === 0) return null;
25936
- return path24.join(scriptsDir, versions[0]);
27021
+ return path25.join(scriptsDir, versions[0]);
25937
27022
  }
25938
27023
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
25939
- const canonicalUserDir = path24.resolve(ctx.providerLoader.getUserProviderDir(category, type));
25940
- const desiredDir = requestedDir ? path24.resolve(requestedDir) : canonicalUserDir;
25941
- const upstreamRoot = path24.resolve(ctx.providerLoader.getUpstreamDir());
25942
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path24.sep}`)) {
27024
+ const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
27025
+ const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
27026
+ const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
27027
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
25943
27028
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
25944
27029
  }
25945
- if (path24.basename(desiredDir) !== type) {
27030
+ if (path25.basename(desiredDir) !== type) {
25946
27031
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
25947
27032
  }
25948
27033
  const sourceDir = ctx.findProviderDir(type);
@@ -25950,11 +27035,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
25950
27035
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
25951
27036
  }
25952
27037
  if (!fs14.existsSync(desiredDir)) {
25953
- fs14.mkdirSync(path24.dirname(desiredDir), { recursive: true });
27038
+ fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
25954
27039
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
25955
27040
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
25956
27041
  }
25957
- const providerJson = path24.join(desiredDir, "provider.json");
27042
+ const providerJson = path25.join(desiredDir, "provider.json");
25958
27043
  if (!fs14.existsSync(providerJson)) {
25959
27044
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
25960
27045
  }
@@ -25965,13 +27050,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
25965
27050
  const refDir = ctx.findProviderDir(referenceType);
25966
27051
  if (!refDir || !fs14.existsSync(refDir)) return {};
25967
27052
  const referenceScripts = {};
25968
- const scriptsDir = path24.join(refDir, "scripts");
27053
+ const scriptsDir = path25.join(refDir, "scripts");
25969
27054
  const latestDir = getLatestScriptVersionDir(scriptsDir);
25970
27055
  if (!latestDir) return referenceScripts;
25971
27056
  for (const file of fs14.readdirSync(latestDir)) {
25972
27057
  if (!file.endsWith(".js")) continue;
25973
27058
  try {
25974
- referenceScripts[file] = fs14.readFileSync(path24.join(latestDir, file), "utf-8");
27059
+ referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
25975
27060
  } catch {
25976
27061
  }
25977
27062
  }
@@ -26079,9 +27164,9 @@ async function handleAutoImplement(ctx, type, req, res) {
26079
27164
  });
26080
27165
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
26081
27166
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
26082
- const tmpDir = path24.join(os20.tmpdir(), "adhdev-autoimpl");
27167
+ const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
26083
27168
  if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
26084
- const promptFile = path24.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
27169
+ const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
26085
27170
  fs14.writeFileSync(promptFile, prompt, "utf-8");
26086
27171
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
26087
27172
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -26234,7 +27319,7 @@ async function handleAutoImplement(ctx, type, req, res) {
26234
27319
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
26235
27320
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
26236
27321
  let shellCmd;
26237
- const isWin = os20.platform() === "win32";
27322
+ const isWin = os21.platform() === "win32";
26238
27323
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
26239
27324
  const promptMode = autoImpl?.promptMode ?? "stdin";
26240
27325
  const extraArgs = autoImpl?.extraArgs ?? [];
@@ -26273,7 +27358,7 @@ async function handleAutoImplement(ctx, type, req, res) {
26273
27358
  try {
26274
27359
  const pty = require("node-pty");
26275
27360
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
26276
- const isWin2 = os20.platform() === "win32";
27361
+ const isWin2 = os21.platform() === "win32";
26277
27362
  child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
26278
27363
  name: "xterm-256color",
26279
27364
  cols: 120,
@@ -26513,7 +27598,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26513
27598
  setMode: "set_mode.js"
26514
27599
  };
26515
27600
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26516
- const scriptsDir = path24.join(providerDir, "scripts");
27601
+ const scriptsDir = path25.join(providerDir, "scripts");
26517
27602
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
26518
27603
  if (latestScriptsDir) {
26519
27604
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26524,7 +27609,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26524
27609
  for (const file of fs14.readdirSync(latestScriptsDir)) {
26525
27610
  if (file.endsWith(".js") && targetFileNames.has(file)) {
26526
27611
  try {
26527
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27612
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26528
27613
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26529
27614
  lines.push("```javascript");
26530
27615
  lines.push(content);
@@ -26541,7 +27626,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26541
27626
  lines.push("");
26542
27627
  for (const file of refFiles) {
26543
27628
  try {
26544
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27629
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26545
27630
  lines.push(`### \`${file}\` \u{1F512}`);
26546
27631
  lines.push("```javascript");
26547
27632
  lines.push(content);
@@ -26582,10 +27667,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26582
27667
  lines.push("");
26583
27668
  }
26584
27669
  }
26585
- const docsDir = path24.join(providerDir, "../../docs");
27670
+ const docsDir = path25.join(providerDir, "../../docs");
26586
27671
  const loadGuide = (name) => {
26587
27672
  try {
26588
- const p = path24.join(docsDir, name);
27673
+ const p = path25.join(docsDir, name);
26589
27674
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
26590
27675
  } catch {
26591
27676
  }
@@ -26822,7 +27907,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26822
27907
  parseApproval: "parse_approval.js"
26823
27908
  };
26824
27909
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26825
- const scriptsDir = path24.join(providerDir, "scripts");
27910
+ const scriptsDir = path25.join(providerDir, "scripts");
26826
27911
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
26827
27912
  if (latestScriptsDir) {
26828
27913
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26834,7 +27919,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26834
27919
  if (!file.endsWith(".js")) continue;
26835
27920
  if (!targetFileNames.has(file)) continue;
26836
27921
  try {
26837
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27922
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26838
27923
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26839
27924
  lines.push("```javascript");
26840
27925
  lines.push(content);
@@ -26850,7 +27935,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26850
27935
  lines.push("");
26851
27936
  for (const file of refFiles) {
26852
27937
  try {
26853
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27938
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26854
27939
  lines.push(`### \`${file}\` \u{1F512}`);
26855
27940
  lines.push("```javascript");
26856
27941
  lines.push(content);
@@ -26883,10 +27968,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26883
27968
  lines.push("");
26884
27969
  }
26885
27970
  }
26886
- const docsDir = path24.join(providerDir, "../../docs");
27971
+ const docsDir = path25.join(providerDir, "../../docs");
26887
27972
  const loadGuide = (name) => {
26888
27973
  try {
26889
- const p = path24.join(docsDir, name);
27974
+ const p = path25.join(docsDir, name);
26890
27975
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
26891
27976
  } catch {
26892
27977
  }
@@ -27333,8 +28418,8 @@ var DevServer = class _DevServer {
27333
28418
  }
27334
28419
  getEndpointList() {
27335
28420
  return this.routes.map((r) => {
27336
- const path26 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
27337
- return `${r.method.padEnd(5)} ${path26}`;
28421
+ const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
28422
+ return `${r.method.padEnd(5)} ${path27}`;
27338
28423
  });
27339
28424
  }
27340
28425
  async start(port = DEV_SERVER_PORT) {
@@ -27622,12 +28707,12 @@ var DevServer = class _DevServer {
27622
28707
  // ─── DevConsole SPA ───
27623
28708
  getConsoleDistDir() {
27624
28709
  const candidates = [
27625
- path25.resolve(__dirname, "../../web-devconsole/dist"),
27626
- path25.resolve(__dirname, "../../../web-devconsole/dist"),
27627
- path25.join(process.cwd(), "packages/web-devconsole/dist")
28710
+ path26.resolve(__dirname, "../../web-devconsole/dist"),
28711
+ path26.resolve(__dirname, "../../../web-devconsole/dist"),
28712
+ path26.join(process.cwd(), "packages/web-devconsole/dist")
27628
28713
  ];
27629
28714
  for (const dir of candidates) {
27630
- if (fs15.existsSync(path25.join(dir, "index.html"))) return dir;
28715
+ if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
27631
28716
  }
27632
28717
  return null;
27633
28718
  }
@@ -27637,7 +28722,7 @@ var DevServer = class _DevServer {
27637
28722
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
27638
28723
  return;
27639
28724
  }
27640
- const htmlPath = path25.join(distDir, "index.html");
28725
+ const htmlPath = path26.join(distDir, "index.html");
27641
28726
  try {
27642
28727
  const html = fs15.readFileSync(htmlPath, "utf-8");
27643
28728
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -27662,15 +28747,15 @@ var DevServer = class _DevServer {
27662
28747
  this.json(res, 404, { error: "Not found" });
27663
28748
  return;
27664
28749
  }
27665
- const safePath = path25.normalize(pathname).replace(/^\.\.\//, "");
27666
- const filePath = path25.join(distDir, safePath);
28750
+ const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
28751
+ const filePath = path26.join(distDir, safePath);
27667
28752
  if (!filePath.startsWith(distDir)) {
27668
28753
  this.json(res, 403, { error: "Forbidden" });
27669
28754
  return;
27670
28755
  }
27671
28756
  try {
27672
28757
  const content = fs15.readFileSync(filePath);
27673
- const ext = path25.extname(filePath);
28758
+ const ext = path26.extname(filePath);
27674
28759
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
27675
28760
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
27676
28761
  res.end(content);
@@ -27783,9 +28868,9 @@ var DevServer = class _DevServer {
27783
28868
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
27784
28869
  if (entry.isDirectory()) {
27785
28870
  files.push({ path: rel, size: 0, type: "dir" });
27786
- scan(path25.join(d, entry.name), rel);
28871
+ scan(path26.join(d, entry.name), rel);
27787
28872
  } else {
27788
- const stat2 = fs15.statSync(path25.join(d, entry.name));
28873
+ const stat2 = fs15.statSync(path26.join(d, entry.name));
27789
28874
  files.push({ path: rel, size: stat2.size, type: "file" });
27790
28875
  }
27791
28876
  }
@@ -27808,7 +28893,7 @@ var DevServer = class _DevServer {
27808
28893
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
27809
28894
  return;
27810
28895
  }
27811
- const fullPath = path25.resolve(dir, path25.normalize(filePath));
28896
+ const fullPath = path26.resolve(dir, path26.normalize(filePath));
27812
28897
  if (!fullPath.startsWith(dir)) {
27813
28898
  this.json(res, 403, { error: "Forbidden" });
27814
28899
  return;
@@ -27833,14 +28918,14 @@ var DevServer = class _DevServer {
27833
28918
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
27834
28919
  return;
27835
28920
  }
27836
- const fullPath = path25.resolve(dir, path25.normalize(filePath));
28921
+ const fullPath = path26.resolve(dir, path26.normalize(filePath));
27837
28922
  if (!fullPath.startsWith(dir)) {
27838
28923
  this.json(res, 403, { error: "Forbidden" });
27839
28924
  return;
27840
28925
  }
27841
28926
  try {
27842
28927
  if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
27843
- fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
28928
+ fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
27844
28929
  fs15.writeFileSync(fullPath, content, "utf-8");
27845
28930
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
27846
28931
  this.providerLoader.reload();
@@ -27857,7 +28942,7 @@ var DevServer = class _DevServer {
27857
28942
  return;
27858
28943
  }
27859
28944
  for (const name of ["scripts.js", "provider.json"]) {
27860
- const p = path25.join(dir, name);
28945
+ const p = path26.join(dir, name);
27861
28946
  if (fs15.existsSync(p)) {
27862
28947
  const source = fs15.readFileSync(p, "utf-8");
27863
28948
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -27878,8 +28963,8 @@ var DevServer = class _DevServer {
27878
28963
  this.json(res, 404, { error: `Provider not found: ${type}` });
27879
28964
  return;
27880
28965
  }
27881
- const target = fs15.existsSync(path25.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
27882
- const targetPath = path25.join(dir, target);
28966
+ const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
28967
+ const targetPath = path26.join(dir, target);
27883
28968
  try {
27884
28969
  if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
27885
28970
  fs15.writeFileSync(targetPath, source, "utf-8");
@@ -28026,7 +29111,7 @@ var DevServer = class _DevServer {
28026
29111
  }
28027
29112
  let targetDir;
28028
29113
  targetDir = this.providerLoader.getUserProviderDir(category, type);
28029
- const jsonPath = path25.join(targetDir, "provider.json");
29114
+ const jsonPath = path26.join(targetDir, "provider.json");
28030
29115
  if (fs15.existsSync(jsonPath)) {
28031
29116
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
28032
29117
  return;
@@ -28038,8 +29123,8 @@ var DevServer = class _DevServer {
28038
29123
  const createdFiles = ["provider.json"];
28039
29124
  if (result.files) {
28040
29125
  for (const [relPath, content] of Object.entries(result.files)) {
28041
- const fullPath = path25.join(targetDir, relPath);
28042
- fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
29126
+ const fullPath = path26.join(targetDir, relPath);
29127
+ fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
28043
29128
  fs15.writeFileSync(fullPath, content, "utf-8");
28044
29129
  createdFiles.push(relPath);
28045
29130
  }
@@ -28092,22 +29177,22 @@ var DevServer = class _DevServer {
28092
29177
  if (!fs15.existsSync(scriptsDir)) return null;
28093
29178
  const versions = fs15.readdirSync(scriptsDir).filter((d) => {
28094
29179
  try {
28095
- return fs15.statSync(path25.join(scriptsDir, d)).isDirectory();
29180
+ return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
28096
29181
  } catch {
28097
29182
  return false;
28098
29183
  }
28099
29184
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
28100
29185
  if (versions.length === 0) return null;
28101
- return path25.join(scriptsDir, versions[0]);
29186
+ return path26.join(scriptsDir, versions[0]);
28102
29187
  }
28103
29188
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
28104
- const canonicalUserDir = path25.resolve(this.providerLoader.getUserProviderDir(category, type));
28105
- const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
28106
- const upstreamRoot = path25.resolve(this.providerLoader.getUpstreamDir());
28107
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
29189
+ const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
29190
+ const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
29191
+ const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
29192
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
28108
29193
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
28109
29194
  }
28110
- if (path25.basename(desiredDir) !== type) {
29195
+ if (path26.basename(desiredDir) !== type) {
28111
29196
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
28112
29197
  }
28113
29198
  const sourceDir = this.findProviderDir(type);
@@ -28115,11 +29200,11 @@ var DevServer = class _DevServer {
28115
29200
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
28116
29201
  }
28117
29202
  if (!fs15.existsSync(desiredDir)) {
28118
- fs15.mkdirSync(path25.dirname(desiredDir), { recursive: true });
29203
+ fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
28119
29204
  fs15.cpSync(sourceDir, desiredDir, { recursive: true });
28120
29205
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
28121
29206
  }
28122
- const providerJson = path25.join(desiredDir, "provider.json");
29207
+ const providerJson = path26.join(desiredDir, "provider.json");
28123
29208
  if (!fs15.existsSync(providerJson)) {
28124
29209
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
28125
29210
  }
@@ -28155,7 +29240,7 @@ var DevServer = class _DevServer {
28155
29240
  setMode: "set_mode.js"
28156
29241
  };
28157
29242
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
28158
- const scriptsDir = path25.join(providerDir, "scripts");
29243
+ const scriptsDir = path26.join(providerDir, "scripts");
28159
29244
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
28160
29245
  if (latestScriptsDir) {
28161
29246
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -28166,7 +29251,7 @@ var DevServer = class _DevServer {
28166
29251
  for (const file of fs15.readdirSync(latestScriptsDir)) {
28167
29252
  if (file.endsWith(".js") && targetFileNames.has(file)) {
28168
29253
  try {
28169
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29254
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28170
29255
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
28171
29256
  lines.push("```javascript");
28172
29257
  lines.push(content);
@@ -28183,7 +29268,7 @@ var DevServer = class _DevServer {
28183
29268
  lines.push("");
28184
29269
  for (const file of refFiles) {
28185
29270
  try {
28186
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29271
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28187
29272
  lines.push(`### \`${file}\` \u{1F512}`);
28188
29273
  lines.push("```javascript");
28189
29274
  lines.push(content);
@@ -28224,10 +29309,10 @@ var DevServer = class _DevServer {
28224
29309
  lines.push("");
28225
29310
  }
28226
29311
  }
28227
- const docsDir = path25.join(providerDir, "../../docs");
29312
+ const docsDir = path26.join(providerDir, "../../docs");
28228
29313
  const loadGuide = (name) => {
28229
29314
  try {
28230
- const p = path25.join(docsDir, name);
29315
+ const p = path26.join(docsDir, name);
28231
29316
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
28232
29317
  } catch {
28233
29318
  }
@@ -28401,7 +29486,7 @@ var DevServer = class _DevServer {
28401
29486
  parseApproval: "parse_approval.js"
28402
29487
  };
28403
29488
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
28404
- const scriptsDir = path25.join(providerDir, "scripts");
29489
+ const scriptsDir = path26.join(providerDir, "scripts");
28405
29490
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
28406
29491
  if (latestScriptsDir) {
28407
29492
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -28413,7 +29498,7 @@ var DevServer = class _DevServer {
28413
29498
  if (!file.endsWith(".js")) continue;
28414
29499
  if (!targetFileNames.has(file)) continue;
28415
29500
  try {
28416
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29501
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28417
29502
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
28418
29503
  lines.push("```javascript");
28419
29504
  lines.push(content);
@@ -28429,7 +29514,7 @@ var DevServer = class _DevServer {
28429
29514
  lines.push("");
28430
29515
  for (const file of refFiles) {
28431
29516
  try {
28432
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29517
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28433
29518
  lines.push(`### \`${file}\` \u{1F512}`);
28434
29519
  lines.push("```javascript");
28435
29520
  lines.push(content);
@@ -28462,10 +29547,10 @@ var DevServer = class _DevServer {
28462
29547
  lines.push("");
28463
29548
  }
28464
29549
  }
28465
- const docsDir = path25.join(providerDir, "../../docs");
29550
+ const docsDir = path26.join(providerDir, "../../docs");
28466
29551
  const loadGuide = (name) => {
28467
29552
  try {
28468
- const p = path25.join(docsDir, name);
29553
+ const p = path26.join(docsDir, name);
28469
29554
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
28470
29555
  } catch {
28471
29556
  }
@@ -29151,29 +30236,58 @@ function resolveSessionHostAppName(options = {}) {
29151
30236
  var import_session_host_core4 = require("@adhdev/session-host-core");
29152
30237
  var STARTUP_TIMEOUT_MS = DEFAULT_SESSION_HOST_READY_TIMEOUT_MS;
29153
30238
  var STARTUP_POLL_MS = 200;
29154
- async function canConnect(endpoint) {
30239
+ var SessionHostCompatibilityError = class extends Error {
30240
+ constructor(message) {
30241
+ super(message);
30242
+ this.name = "SessionHostCompatibilityError";
30243
+ }
30244
+ };
30245
+ function getMissingRequestTypes(diagnostics, requiredRequestTypes) {
30246
+ const supported = new Set(diagnostics?.supportedRequestTypes || []);
30247
+ return requiredRequestTypes.filter((requestType) => !supported.has(requestType));
30248
+ }
30249
+ async function assertRequiredRequestTypes(client, requiredRequestTypes) {
30250
+ if (requiredRequestTypes.length === 0) return;
30251
+ const response = await client.request({
30252
+ type: "get_host_diagnostics",
30253
+ payload: { includeSessions: false }
30254
+ });
30255
+ const missing = getMissingRequestTypes(response.success ? response.result : void 0, requiredRequestTypes);
30256
+ if (missing.length > 0) {
30257
+ const detail = response.success ? "" : ` (${response.error || "capability probe failed"})`;
30258
+ throw new SessionHostCompatibilityError(
30259
+ `Session host does not support required request types: ${missing.join(", ")}${detail}`
30260
+ );
30261
+ }
30262
+ }
30263
+ async function canConnect(endpoint, requiredRequestTypes = []) {
29155
30264
  const client = new import_session_host_core4.SessionHostClient({ endpoint });
29156
30265
  try {
29157
30266
  await client.connect();
29158
- await client.close();
30267
+ await assertRequiredRequestTypes(client, requiredRequestTypes);
29159
30268
  return true;
29160
- } catch {
30269
+ } catch (error) {
30270
+ if (error instanceof SessionHostCompatibilityError) throw error;
29161
30271
  return false;
30272
+ } finally {
30273
+ await client.close().catch(() => {
30274
+ });
29162
30275
  }
29163
30276
  }
29164
- async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
30277
+ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS, requiredRequestTypes = []) {
29165
30278
  const deadline = Date.now() + timeoutMs;
29166
30279
  while (Date.now() < deadline) {
29167
- if (await canConnect(endpoint)) return;
30280
+ if (await canConnect(endpoint, requiredRequestTypes)) return;
29168
30281
  await new Promise((resolve16) => setTimeout(resolve16, STARTUP_POLL_MS));
29169
30282
  }
29170
30283
  throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
29171
30284
  }
29172
30285
  async function ensureSessionHostReady(options) {
29173
30286
  const endpoint = (0, import_session_host_core4.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
29174
- if (await canConnect(endpoint)) return endpoint;
30287
+ const requiredRequestTypes = options.requiredRequestTypes || [];
30288
+ if (await canConnect(endpoint, requiredRequestTypes)) return endpoint;
29175
30289
  options.spawnHost();
29176
- await waitForReady(endpoint, options.timeoutMs);
30290
+ await waitForReady(endpoint, options.timeoutMs, requiredRequestTypes);
29177
30291
  return endpoint;
29178
30292
  }
29179
30293
  async function listHostedCliRuntimes(endpoint) {
@@ -29465,48 +30579,6 @@ var SessionRegistry = class {
29465
30579
  // src/boot/daemon-lifecycle.ts
29466
30580
  init_logger();
29467
30581
  init_config();
29468
-
29469
- // src/mesh/mesh-events.ts
29470
- init_mesh_config();
29471
- init_logger();
29472
- function setupMeshEventForwarding(components) {
29473
- components.instanceManager.onEvent((event) => {
29474
- if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
29475
- const instanceId = event.instanceId;
29476
- if (!instanceId) return;
29477
- const sourceInstance = components.instanceManager.getInstance(instanceId);
29478
- if (!sourceInstance || sourceInstance.category !== "cli") return;
29479
- const state = sourceInstance.getState();
29480
- const workspace = state.workspace;
29481
- if (!workspace) return;
29482
- const mesh = getMeshByRepo(workspace);
29483
- if (!mesh) return;
29484
- const allInstances = components.instanceManager.getByCategory("cli");
29485
- const coordinatorInstances = allInstances.filter((inst) => {
29486
- const instState = inst.getState();
29487
- if (instState.settings?.meshCoordinatorFor !== mesh.id) return false;
29488
- if (instState.instanceId === instanceId) return false;
29489
- return true;
29490
- });
29491
- if (coordinatorInstances.length === 0) return;
29492
- const targetNode = mesh.nodes.find((n) => n.workspace === workspace);
29493
- const nodeLabel = targetNode ? `Node '${targetNode.id}'` : `Agent at ${workspace}`;
29494
- let messageText = "";
29495
- if (event.event === "agent:generating_completed") {
29496
- messageText = `[System] ${nodeLabel} has completed its task and is now idle. You may use mesh_read_chat to review its progress.`;
29497
- } else if (event.event === "agent:waiting_approval") {
29498
- messageText = `[System] ${nodeLabel} is waiting for approval to proceed. You may use mesh_read_chat and mesh_approve to handle it.`;
29499
- }
29500
- if (!messageText) return;
29501
- for (const coord of coordinatorInstances) {
29502
- const coordState = coord.getState();
29503
- LOG.info("MeshEvents", `Forwarding event from ${workspace} to coordinator ${coordState.instanceId}`);
29504
- coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
29505
- }
29506
- });
29507
- }
29508
-
29509
- // src/boot/daemon-lifecycle.ts
29510
30582
  async function initDaemonComponents(config) {
29511
30583
  installGlobalInterceptor();
29512
30584
  const appConfig = loadConfig();
@@ -29813,12 +30885,14 @@ async function shutdownDaemonComponents(components) {
29813
30885
  createGitWorkspaceMonitor,
29814
30886
  createInteractionId,
29815
30887
  createMesh,
30888
+ createWorktree,
29816
30889
  deleteMesh,
29817
30890
  detectAllVersions,
29818
30891
  detectCLIs,
29819
30892
  detectIDEs,
29820
30893
  ensureSessionHostReady,
29821
30894
  execNpmCommandSync,
30895
+ filterUserFacingChatMessages,
29822
30896
  findCdpManager,
29823
30897
  flattenMessageParts,
29824
30898
  forwardAgentStreamsToIdeInstance,
@@ -29860,11 +30934,13 @@ async function shutdownDaemonComponents(components) {
29860
30934
  isSessionHostLiveRuntime,
29861
30935
  isSessionHostRecoverySnapshot,
29862
30936
  isSetupComplete,
30937
+ isUserFacingChatMessage,
29863
30938
  killIdeProcess,
29864
30939
  launchIDE,
29865
30940
  launchWithCdp,
29866
30941
  listHostedCliRuntimes,
29867
30942
  listMeshes,
30943
+ listWorktrees,
29868
30944
  loadConfig,
29869
30945
  loadState,
29870
30946
  logCommand,
@@ -29884,6 +30960,7 @@ async function shutdownDaemonComponents(components) {
29884
30960
  normalizeSessionModalFields,
29885
30961
  parsePorcelainV2Status,
29886
30962
  parseProviderSourceConfigUpdate,
30963
+ parseWorktreeListOutput,
29887
30964
  partitionSessionHostDiagnosticsSessions,
29888
30965
  partitionSessionHostRecords,
29889
30966
  prepareSessionChatTailUpdate,
@@ -29893,6 +30970,7 @@ async function shutdownDaemonComponents(components) {
29893
30970
  recordDebugTrace,
29894
30971
  registerExtensionProviders,
29895
30972
  removeNode,
30973
+ removeWorktree,
29896
30974
  resetConfig,
29897
30975
  resetDebugRuntimeConfig,
29898
30976
  resetState,
@@ -29902,6 +30980,7 @@ async function shutdownDaemonComponents(components) {
29902
30980
  resolveGitRepository,
29903
30981
  resolveSessionHostAppName,
29904
30982
  resolveSessionHostAppNameResolution,
30983
+ resolveWorktreePath,
29905
30984
  runAsyncBatch,
29906
30985
  runGit,
29907
30986
  saveConfig,