@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.mjs CHANGED
@@ -36,11 +36,140 @@ var init_repo_mesh_types = __esm({
36
36
  requireApprovalForPush: true,
37
37
  requireApprovalForDestructiveGit: true,
38
38
  dirtyWorkspaceBehavior: "warn",
39
- maxParallelTasks: 2
39
+ maxParallelTasks: 2,
40
+ sessionCleanupOnNodeRemove: "preserve"
40
41
  };
41
42
  }
42
43
  });
43
44
 
45
+ // src/git/git-worktree.ts
46
+ var git_worktree_exports = {};
47
+ __export(git_worktree_exports, {
48
+ createWorktree: () => createWorktree,
49
+ listWorktrees: () => listWorktrees,
50
+ parseWorktreeListOutput: () => parseWorktreeListOutput,
51
+ removeWorktree: () => removeWorktree,
52
+ resolveWorktreePath: () => resolveWorktreePath
53
+ });
54
+ import * as path4 from "path";
55
+ import { mkdir } from "fs/promises";
56
+ import { existsSync } from "fs";
57
+ import { execFile as execFile2 } from "child_process";
58
+ import { promisify as promisify2 } from "util";
59
+ function resolveWorktreePath(repoRoot, meshName, branch) {
60
+ const safeBranch = branch.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
61
+ const safeMeshName = meshName.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
62
+ const parentDir = path4.dirname(repoRoot);
63
+ return path4.join(parentDir, WORKTREE_DIR_NAME, safeMeshName, safeBranch);
64
+ }
65
+ async function createWorktree(opts) {
66
+ const { repoRoot, branch, baseBranch, meshName } = opts;
67
+ const targetDir = opts.targetDir || resolveWorktreePath(repoRoot, meshName, branch);
68
+ if (existsSync(targetDir)) {
69
+ throw new Error(`Worktree target directory already exists: ${targetDir}`);
70
+ }
71
+ await mkdir(path4.dirname(targetDir), { recursive: true });
72
+ const args = ["worktree", "add", targetDir, "-b", branch];
73
+ if (baseBranch) {
74
+ args.push(baseBranch);
75
+ }
76
+ try {
77
+ await execFileAsync2("git", args, {
78
+ cwd: repoRoot,
79
+ encoding: "utf8",
80
+ timeout: GIT_TIMEOUT_MS,
81
+ maxBuffer: GIT_MAX_BUFFER,
82
+ windowsHide: true
83
+ });
84
+ } catch (error) {
85
+ const stderr = typeof error.stderr === "string" ? error.stderr : "";
86
+ if (/already exists/i.test(stderr)) {
87
+ throw new Error(`Branch '${branch}' already exists or is checked out in another worktree`);
88
+ }
89
+ throw new Error(`git worktree add failed: ${stderr.trim() || error.message}`);
90
+ }
91
+ return {
92
+ success: true,
93
+ worktreePath: targetDir,
94
+ branch
95
+ };
96
+ }
97
+ async function removeWorktree(repoRoot, worktreePath) {
98
+ if (!existsSync(worktreePath)) {
99
+ await pruneWorktrees(repoRoot);
100
+ return { success: true, removedPath: worktreePath };
101
+ }
102
+ try {
103
+ await execFileAsync2("git", ["worktree", "remove", worktreePath, "--force"], {
104
+ cwd: repoRoot,
105
+ encoding: "utf8",
106
+ timeout: GIT_TIMEOUT_MS,
107
+ maxBuffer: GIT_MAX_BUFFER,
108
+ windowsHide: true
109
+ });
110
+ } catch (error) {
111
+ const stderr = typeof error.stderr === "string" ? error.stderr : "";
112
+ throw new Error(`git worktree remove failed: ${stderr.trim() || error.message}`);
113
+ }
114
+ return { success: true, removedPath: worktreePath };
115
+ }
116
+ async function listWorktrees(repoRoot) {
117
+ const { stdout } = await execFileAsync2("git", ["worktree", "list", "--porcelain"], {
118
+ cwd: repoRoot,
119
+ encoding: "utf8",
120
+ timeout: GIT_TIMEOUT_MS,
121
+ maxBuffer: GIT_MAX_BUFFER,
122
+ windowsHide: true
123
+ });
124
+ return parseWorktreeListOutput(stdout);
125
+ }
126
+ function parseWorktreeListOutput(output) {
127
+ const entries = [];
128
+ const blocks = output.trim().split(/\n\n+/);
129
+ for (const block of blocks) {
130
+ if (!block.trim()) continue;
131
+ const lines = block.trim().split("\n");
132
+ const entry = { path: "", head: "", branch: null, bare: false };
133
+ for (const line of lines) {
134
+ if (line.startsWith("worktree ")) {
135
+ entry.path = line.slice("worktree ".length).trim();
136
+ } else if (line.startsWith("HEAD ")) {
137
+ entry.head = line.slice("HEAD ".length).trim();
138
+ } else if (line.startsWith("branch ")) {
139
+ const ref = line.slice("branch ".length).trim();
140
+ entry.branch = ref.replace(/^refs\/heads\//, "");
141
+ } else if (line === "bare") {
142
+ entry.bare = true;
143
+ }
144
+ }
145
+ if (entry.path) {
146
+ entries.push(entry);
147
+ }
148
+ }
149
+ return entries;
150
+ }
151
+ async function pruneWorktrees(repoRoot) {
152
+ try {
153
+ await execFileAsync2("git", ["worktree", "prune"], {
154
+ cwd: repoRoot,
155
+ encoding: "utf8",
156
+ timeout: GIT_TIMEOUT_MS,
157
+ windowsHide: true
158
+ });
159
+ } catch {
160
+ }
161
+ }
162
+ var execFileAsync2, WORKTREE_DIR_NAME, GIT_TIMEOUT_MS, GIT_MAX_BUFFER;
163
+ var init_git_worktree = __esm({
164
+ "src/git/git-worktree.ts"() {
165
+ "use strict";
166
+ execFileAsync2 = promisify2(execFile2);
167
+ WORKTREE_DIR_NAME = ".adhdev-worktrees";
168
+ GIT_TIMEOUT_MS = 3e4;
169
+ GIT_MAX_BUFFER = 4 * 1024 * 1024;
170
+ }
171
+ });
172
+
44
173
  // src/config/config.ts
45
174
  var config_exports = {};
46
175
  __export(config_exports, {
@@ -56,8 +185,8 @@ __export(config_exports, {
56
185
  updateConfig: () => updateConfig
57
186
  });
58
187
  import { homedir } from "os";
59
- import { join } from "path";
60
- import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
188
+ import { join as join2 } from "path";
189
+ import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
61
190
  import { randomUUID } from "crypto";
62
191
  function resolveProviderSourceMode(providerSourceMode, legacyDisableUpstream) {
63
192
  if (providerSourceMode === "normal" || providerSourceMode === "no-upstream") {
@@ -151,18 +280,18 @@ function ensureMachineId(config) {
151
280
  };
152
281
  }
153
282
  function getConfigDir() {
154
- const dir = join(homedir(), ".adhdev");
155
- if (!existsSync(dir)) {
283
+ const dir = join2(homedir(), ".adhdev");
284
+ if (!existsSync2(dir)) {
156
285
  mkdirSync(dir, { recursive: true });
157
286
  }
158
287
  return dir;
159
288
  }
160
289
  function getConfigPath() {
161
- return join(getConfigDir(), "config.json");
290
+ return join2(getConfigDir(), "config.json");
162
291
  }
163
292
  function migrateStateToStateFile(raw) {
164
- const statePath = join(getConfigDir(), "state.json");
165
- if (existsSync(statePath)) return;
293
+ const statePath = join2(getConfigDir(), "state.json");
294
+ if (existsSync2(statePath)) return;
166
295
  const recentActivity = Array.isArray(raw.recentActivity) ? raw.recentActivity : [];
167
296
  const savedProviderSessions = Array.isArray(raw.savedProviderSessions) ? raw.savedProviderSessions : [];
168
297
  const legacySessionReads = isPlainObject(raw.recentSessionReads) ? raw.recentSessionReads : {};
@@ -186,7 +315,7 @@ function migrateStateToStateFile(raw) {
186
315
  }
187
316
  function loadConfig() {
188
317
  const configPath = getConfigPath();
189
- if (!existsSync(configPath)) {
318
+ if (!existsSync2(configPath)) {
190
319
  const initialized = ensureMachineId({ ...DEFAULT_CONFIG });
191
320
  try {
192
321
  saveConfig(initialized.config);
@@ -217,7 +346,7 @@ function saveConfig(config) {
217
346
  const configPath = getConfigPath();
218
347
  const dir = getConfigDir();
219
348
  const normalized = normalizeConfig(config);
220
- if (!existsSync(dir)) {
349
+ if (!existsSync2(dir)) {
221
350
  mkdirSync(dir, { recursive: true, mode: 448 });
222
351
  }
223
352
  writeFileSync(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
@@ -295,17 +424,17 @@ __export(mesh_config_exports, {
295
424
  updateMesh: () => updateMesh,
296
425
  updateNode: () => updateNode
297
426
  });
298
- import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
299
- import { join as join3 } from "path";
427
+ import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
428
+ import { join as join4 } from "path";
300
429
  import { randomUUID as randomUUID3 } from "crypto";
301
430
  function getMeshConfigPath() {
302
- return join3(getConfigDir(), "meshes.json");
431
+ return join4(getConfigDir(), "meshes.json");
303
432
  }
304
433
  function loadMeshConfig() {
305
- const path26 = getMeshConfigPath();
306
- if (!existsSync3(path26)) return { meshes: [] };
434
+ const path27 = getMeshConfigPath();
435
+ if (!existsSync4(path27)) return { meshes: [] };
307
436
  try {
308
- const raw = JSON.parse(readFileSync2(path26, "utf-8"));
437
+ const raw = JSON.parse(readFileSync2(path27, "utf-8"));
309
438
  if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
310
439
  return raw;
311
440
  } catch {
@@ -313,16 +442,16 @@ function loadMeshConfig() {
313
442
  }
314
443
  }
315
444
  function saveMeshConfig(config) {
316
- const path26 = getMeshConfigPath();
317
- writeFileSync2(path26, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
445
+ const path27 = getMeshConfigPath();
446
+ writeFileSync2(path27, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
318
447
  }
319
448
  function normalizeRepoIdentity(remoteUrl) {
320
449
  let identity = remoteUrl.trim();
321
450
  if (identity.startsWith("http://") || identity.startsWith("https://")) {
322
451
  try {
323
452
  const url = new URL(identity);
324
- const path26 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
325
- return `${url.hostname}/${path26}`;
453
+ const path27 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
454
+ return `${url.hostname}/${path27}`;
326
455
  } catch {
327
456
  }
328
457
  }
@@ -330,6 +459,18 @@ function normalizeRepoIdentity(remoteUrl) {
330
459
  if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
331
460
  return identity;
332
461
  }
462
+ function mergeMeshPolicy(base, patch) {
463
+ const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
464
+ if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
465
+ policy.dirtyWorkspaceBehavior = "warn";
466
+ }
467
+ const maxParallelTasks = Number(policy.maxParallelTasks);
468
+ policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
469
+ if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
470
+ policy.sessionCleanupOnNodeRemove = "preserve";
471
+ }
472
+ return policy;
473
+ }
333
474
  function listMeshes() {
334
475
  return loadMeshConfig().meshes;
335
476
  }
@@ -353,7 +494,7 @@ function createMesh(opts) {
353
494
  repoIdentity,
354
495
  repoRemoteUrl: opts.repoRemoteUrl,
355
496
  defaultBranch: opts.defaultBranch,
356
- policy: { ...DEFAULT_MESH_POLICY, ...opts.policy },
497
+ policy: mergeMeshPolicy(void 0, opts.policy),
357
498
  coordinator: opts.coordinator || {},
358
499
  nodes: [],
359
500
  createdAt: now,
@@ -369,7 +510,7 @@ function updateMesh(meshId, opts) {
369
510
  if (!mesh) return void 0;
370
511
  if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
371
512
  if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
372
- if (opts.policy) mesh.policy = { ...mesh.policy, ...opts.policy };
513
+ if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
373
514
  if (opts.coordinator) mesh.coordinator = opts.coordinator;
374
515
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
375
516
  saveMeshConfig(config);
@@ -397,9 +538,12 @@ function addNode(meshId, opts) {
397
538
  id: `node_${randomUUID3().replace(/-/g, "")}`,
398
539
  workspace: opts.workspace.trim(),
399
540
  repoRoot: opts.repoRoot,
541
+ daemonId: opts.daemonId,
400
542
  userOverrides: opts.userOverrides || {},
401
543
  policy: opts.policy || {},
402
- isLocalWorktree: opts.isLocalWorktree
544
+ isLocalWorktree: opts.isLocalWorktree,
545
+ worktreeBranch: opts.worktreeBranch,
546
+ clonedFromNodeId: opts.clonedFromNodeId
403
547
  };
404
548
  mesh.nodes.push(node);
405
549
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -429,11 +573,13 @@ function updateNode(meshId, nodeId, opts) {
429
573
  saveMeshConfig(config);
430
574
  return node;
431
575
  }
576
+ var SESSION_CLEANUP_MODES;
432
577
  var init_mesh_config = __esm({
433
578
  "src/config/mesh-config.ts"() {
434
579
  "use strict";
435
580
  init_config();
436
581
  init_repo_mesh_types();
582
+ SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
437
583
  }
438
584
  });
439
585
 
@@ -443,7 +589,7 @@ __export(coordinator_prompt_exports, {
443
589
  buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
444
590
  });
445
591
  function buildCoordinatorSystemPrompt(ctx) {
446
- const { mesh, status, userInstruction } = ctx;
592
+ const { mesh, status, userInstruction, coordinatorCliType } = ctx;
447
593
  const sections = [];
448
594
  sections.push(`You are a **Repo Mesh Coordinator** \u2014 a technical team lead who orchestrates work across multiple agent sessions on a shared Git repository.
449
595
 
@@ -457,15 +603,15 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
457
603
  } else {
458
604
  sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
459
605
  }
460
- sections.push(buildPolicySection(mesh.policy));
606
+ sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
461
607
  sections.push(TOOLS_SECTION);
462
608
  sections.push(WORKFLOW_SECTION);
463
- sections.push(RULES_SECTION);
609
+ sections.push(buildRulesSection(coordinatorCliType));
464
610
  if (userInstruction) {
465
611
  sections.push(`## Additional Context
466
612
  ${userInstruction}`);
467
613
  }
468
- if (mesh.coordinator.systemPromptSuffix) {
614
+ if (mesh.coordinator?.systemPromptSuffix) {
469
615
  sections.push(mesh.coordinator.systemPromptSuffix);
470
616
  }
471
617
  return sections.join("\n\n");
@@ -510,10 +656,29 @@ function buildPolicySection(policy) {
510
656
  return `## Policy
511
657
  ${rules.join("\n")}`;
512
658
  }
513
- var TOOLS_SECTION, WORKFLOW_SECTION, RULES_SECTION;
659
+ function buildRulesSection(coordinatorCliType) {
660
+ const coordinatorNote = coordinatorCliType ? `
661
+ - **Coordinator runtime is not a delegation default.** This coordinator is running as \`${coordinatorCliType}\`, but delegated node sessions must follow the user's requested provider, not the coordinator's own runtime.` : "";
662
+ return `## Rules
663
+
664
+ - **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
665
+ - **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
666
+ - **Respect explicit provider requests.** If the user names an agent/provider, pass the matching provider type to \`mesh_launch_session\`: Hermes \u2192 \`hermes-cli\`, Claude Code/Claude \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`. Never substitute \`claude-cli\` just because the coordinator itself is Claude Code.
667
+ - **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
668
+ - **Don't inspect code.** 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.
669
+ - **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.
670
+ - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
671
+ - **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
672
+ - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
673
+ - **Never fabricate tool results.** Always call the actual tool; never pretend you did.
674
+ - **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
675
+ - **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
676
+ }
677
+ var TOOLS_SECTION, WORKFLOW_SECTION;
514
678
  var init_coordinator_prompt = __esm({
515
679
  "src/mesh/coordinator-prompt.ts"() {
516
680
  "use strict";
681
+ init_repo_mesh_types();
517
682
  TOOLS_SECTION = `## Available Tools
518
683
 
519
684
  | Tool | Purpose |
@@ -525,36 +690,29 @@ var init_coordinator_prompt = __esm({
525
690
  | \`mesh_read_chat\` | Read an agent's recent messages to check progress |
526
691
  | \`mesh_git_status\` | Check git status on a specific node |
527
692
  | \`mesh_checkpoint\` | Create a git checkpoint on a node |
528
- | \`mesh_approve\` | Approve/reject a pending agent action |`;
693
+ | \`mesh_approve\` | Approve/reject a pending agent action |
694
+ | \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
695
+ | \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |`;
529
696
  WORKFLOW_SECTION = `## Orchestration Workflow
530
697
 
531
698
  1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
532
699
  2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
533
700
  3. **Delegate** \u2014 For each task:
534
701
  a. Pick the best node (consider: health, dirty state, current workload).
535
- b. If no session exists, call \`mesh_launch_session\` to start one.
536
- c. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
537
- 4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
538
- 5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
702
+ b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
703
+ c. If no session exists, call \`mesh_launch_session\` to start one.
704
+ d. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
705
+ 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\`.
706
+ 5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
539
707
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
540
- 7. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
541
- RULES_SECTION = `## Rules
542
-
543
- - **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
544
- - **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
545
- - **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
546
- - **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
547
- - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
548
- - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
549
- - **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
550
- - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
551
- - **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
708
+ 7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
709
+ 8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
552
710
  }
553
711
  });
554
712
 
555
713
  // src/logging/logger.ts
556
714
  import * as fs2 from "fs";
557
- import * as path9 from "path";
715
+ import * as path10 from "path";
558
716
  import * as os4 from "os";
559
717
  function setLogLevel(level) {
560
718
  currentLevel = level;
@@ -570,13 +728,13 @@ function getDaemonLogDir() {
570
728
  return LOG_DIR;
571
729
  }
572
730
  function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
573
- return path9.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
731
+ return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
574
732
  }
575
733
  function checkDateRotation() {
576
734
  const today = getDateStr();
577
735
  if (today !== currentDate) {
578
736
  currentDate = today;
579
- currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
737
+ currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
580
738
  cleanOldLogs();
581
739
  }
582
740
  }
@@ -590,7 +748,7 @@ function cleanOldLogs() {
590
748
  const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
591
749
  if (dateMatch && dateMatch[1] < cutoffStr) {
592
750
  try {
593
- fs2.unlinkSync(path9.join(LOG_DIR, file));
751
+ fs2.unlinkSync(path10.join(LOG_DIR, file));
594
752
  } catch {
595
753
  }
596
754
  }
@@ -713,7 +871,7 @@ var init_logger = __esm({
713
871
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
714
872
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
715
873
  currentLevel = "info";
716
- LOG_DIR = process.platform === "win32" ? path9.join(process.env.LOCALAPPDATA || process.env.APPDATA || path9.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path9.join(os4.homedir(), "Library", "Logs", "adhdev") : path9.join(os4.homedir(), ".local", "share", "adhdev", "logs");
874
+ LOG_DIR = process.platform === "win32" ? path10.join(process.env.LOCALAPPDATA || process.env.APPDATA || path10.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path10.join(os4.homedir(), "Library", "Logs", "adhdev") : path10.join(os4.homedir(), ".local", "share", "adhdev", "logs");
717
875
  MAX_LOG_SIZE = 5 * 1024 * 1024;
718
876
  MAX_LOG_DAYS = 7;
719
877
  try {
@@ -721,16 +879,16 @@ var init_logger = __esm({
721
879
  } catch {
722
880
  }
723
881
  currentDate = getDateStr();
724
- currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
882
+ currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
725
883
  cleanOldLogs();
726
884
  try {
727
- const oldLog = path9.join(LOG_DIR, "daemon.log");
885
+ const oldLog = path10.join(LOG_DIR, "daemon.log");
728
886
  if (fs2.existsSync(oldLog)) {
729
887
  const stat2 = fs2.statSync(oldLog);
730
888
  const oldDate = stat2.mtime.toISOString().slice(0, 10);
731
- fs2.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
889
+ fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
732
890
  }
733
- const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
891
+ const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
734
892
  if (fs2.existsSync(oldLogBackup)) {
735
893
  fs2.unlinkSync(oldLogBackup);
736
894
  }
@@ -762,7 +920,7 @@ var init_logger = __esm({
762
920
  }
763
921
  };
764
922
  interceptorInstalled = false;
765
- LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
923
+ LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
766
924
  }
767
925
  });
768
926
 
@@ -1171,7 +1329,7 @@ var init_pty_transport = __esm({
1171
1329
 
1172
1330
  // src/cli-adapters/provider-cli-shared.ts
1173
1331
  import * as os9 from "os";
1174
- import * as path13 from "path";
1332
+ import * as path14 from "path";
1175
1333
  import { execSync as execSync3 } from "child_process";
1176
1334
  function stripAnsi(str) {
1177
1335
  return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
@@ -1236,9 +1394,9 @@ function buildCliScreenSnapshot(text) {
1236
1394
  function findBinary(name) {
1237
1395
  const trimmed = String(name || "").trim();
1238
1396
  if (!trimmed) return trimmed;
1239
- const expanded = trimmed.startsWith("~") ? path13.join(os9.homedir(), trimmed.slice(1)) : trimmed;
1240
- if (path13.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
1241
- return path13.isAbsolute(expanded) ? expanded : path13.resolve(expanded);
1397
+ const expanded = trimmed.startsWith("~") ? path14.join(os9.homedir(), trimmed.slice(1)) : trimmed;
1398
+ if (path14.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
1399
+ return path14.isAbsolute(expanded) ? expanded : path14.resolve(expanded);
1242
1400
  }
1243
1401
  const isWin = os9.platform() === "win32";
1244
1402
  try {
@@ -1254,7 +1412,7 @@ function findBinary(name) {
1254
1412
  }
1255
1413
  }
1256
1414
  function isScriptBinary(binaryPath) {
1257
- if (!path13.isAbsolute(binaryPath)) return false;
1415
+ if (!path14.isAbsolute(binaryPath)) return false;
1258
1416
  try {
1259
1417
  const fs16 = __require("fs");
1260
1418
  const resolved = fs16.realpathSync(binaryPath);
@@ -1270,7 +1428,7 @@ function isScriptBinary(binaryPath) {
1270
1428
  }
1271
1429
  }
1272
1430
  function looksLikeMachOOrElf(filePath) {
1273
- if (!path13.isAbsolute(filePath)) return false;
1431
+ if (!path14.isAbsolute(filePath)) return false;
1274
1432
  try {
1275
1433
  const fs16 = __require("fs");
1276
1434
  const resolved = fs16.realpathSync(filePath);
@@ -1484,10 +1642,10 @@ var init_provider_cli_config = __esm({
1484
1642
 
1485
1643
  // src/cli-adapters/provider-cli-runtime.ts
1486
1644
  import * as os10 from "os";
1487
- import * as path14 from "path";
1645
+ import * as path15 from "path";
1488
1646
  import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from "@adhdev/session-host-core";
1489
1647
  function resolveCliSpawnPlan(options) {
1490
- const { provider, runtimeSettings, workingDir, extraArgs } = options;
1648
+ const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
1491
1649
  const { spawn: spawnConfig } = provider;
1492
1650
  const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
1493
1651
  const binaryPath = findBinary(configuredCommand);
@@ -1495,9 +1653,9 @@ function resolveCliSpawnPlan(options) {
1495
1653
  const allArgs = [...spawnConfig.args, ...extraArgs];
1496
1654
  let shellCmd;
1497
1655
  let shellArgs;
1498
- const useShellUnix = !isWin && (!!spawnConfig.shell || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1656
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1499
1657
  const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1500
- const useShellWin = !!spawnConfig.shell || isCmdShim || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1658
+ const useShellWin = !!spawnConfig.shell || isCmdShim || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1501
1659
  const useShell = isWin ? useShellWin : useShellUnix;
1502
1660
  if (useShell) {
1503
1661
  shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
@@ -1511,7 +1669,7 @@ function resolveCliSpawnPlan(options) {
1511
1669
  shellCmd = binaryPath;
1512
1670
  shellArgs = allArgs;
1513
1671
  }
1514
- const env = buildCliSpawnEnv(process.env, spawnConfig.env);
1672
+ const env = buildCliSpawnEnv(process.env, { ...spawnConfig.env || {}, ...extraEnv || {} });
1515
1673
  env.TERMINAL_CWD = workingDir;
1516
1674
  return {
1517
1675
  binaryPath,
@@ -1610,8 +1768,9 @@ var init_provider_cli_adapter = __esm({
1610
1768
  init_provider_cli_runtime();
1611
1769
  init_provider_cli_shared();
1612
1770
  ProviderCliAdapter = class _ProviderCliAdapter {
1613
- constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
1771
+ constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
1614
1772
  this.extraArgs = extraArgs;
1773
+ this.extraEnv = extraEnv;
1615
1774
  this.provider = provider;
1616
1775
  this.transportFactory = transportFactory;
1617
1776
  this.cliType = provider.type;
@@ -1762,8 +1921,9 @@ var init_provider_cli_adapter = __esm({
1762
1921
  const currentSnapshot = normalizeScreenSnapshot(screenText);
1763
1922
  const lastSnapshot = this.lastScreenSnapshot;
1764
1923
  if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
1765
- const staleSnapshotLooksActive = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel/i.test(lastSnapshot);
1766
- const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:\n|\r|$)/.test(screenText) && !/\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel/i.test(screenText);
1924
+ const activeScreenPattern = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel|Enter to confirm\s*[·•-]\s*Esc to cancel|\b(?:MCP servers?|tool calls?)\b[^\n\r]{0,160}\brequire approval\b/i;
1925
+ const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
1926
+ const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
1767
1927
  if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
1768
1928
  if (currentSnapshot.length >= lastSnapshot.length) return screenText;
1769
1929
  return `${screenText}
@@ -1926,7 +2086,8 @@ ${lastSnapshot}`;
1926
2086
  provider: this.provider,
1927
2087
  runtimeSettings: this.runtimeSettings,
1928
2088
  workingDir: this.workingDir,
1929
- extraArgs: this.extraArgs
2089
+ extraArgs: this.extraArgs,
2090
+ extraEnv: this.extraEnv
1930
2091
  });
1931
2092
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
1932
2093
  this.resetTraceSession();
@@ -3124,9 +3285,8 @@ ${lastSnapshot}`;
3124
3285
  };
3125
3286
  this.recordTrace("submit_echo_missing", diagnostic);
3126
3287
  if (this.requirePromptEchoBeforeSubmit) {
3127
- const message = `${this.cliName} prompt echo was not observed on the PTY screen before submit`;
3128
- LOG.warn("CLI", `[${this.cliType}] ${message} elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
3129
- completion.rejectOnce(new Error(message));
3288
+ LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending guarded submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
3289
+ this.submitSendKey(state, completion);
3130
3290
  return;
3131
3291
  }
3132
3292
  LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
@@ -3173,7 +3333,14 @@ ${lastSnapshot}`;
3173
3333
  })() : null;
3174
3334
  const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
3175
3335
  if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
3176
- throw new Error(`${this.cliName} is still processing the previous prompt`);
3336
+ const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
3337
+ const parsedHasActionableModal = Boolean(
3338
+ parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
3339
+ );
3340
+ const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
3341
+ if (!terminalLooksIdle) {
3342
+ throw new Error(`${this.cliName} is still processing the previous prompt`);
3343
+ }
3177
3344
  }
3178
3345
  if (this.isWaitingForResponse && !allowInputDuringGeneration) {
3179
3346
  if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
@@ -4547,6 +4714,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
4547
4714
  "dirty_index_required",
4548
4715
  "conflict",
4549
4716
  "invalid_args",
4717
+ "nothing_to_commit",
4550
4718
  "git_command_failed"
4551
4719
  ]);
4552
4720
  function failure(reason, error) {
@@ -4791,7 +4959,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
4791
4959
  } catch (err) {
4792
4960
  const output = (err?.stdout || "") + (err?.stderr || "");
4793
4961
  if (/nothing to commit/i.test(output)) {
4794
- throw new GitCommandError("git_command_failed", "Nothing to commit");
4962
+ throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
4963
+ stdout: err?.stdout,
4964
+ stderr: err?.stderr
4965
+ });
4795
4966
  }
4796
4967
  throw err;
4797
4968
  }
@@ -4983,20 +5154,23 @@ var TurnSnapshotTracker = class {
4983
5154
  }
4984
5155
  };
4985
5156
 
5157
+ // src/git/index.ts
5158
+ init_git_worktree();
5159
+
4986
5160
  // src/index.ts
4987
5161
  init_config();
4988
5162
 
4989
5163
  // src/config/workspaces.ts
4990
5164
  import * as fs from "fs";
4991
5165
  import * as os from "os";
4992
- import * as path4 from "path";
5166
+ import * as path5 from "path";
4993
5167
  import { randomUUID as randomUUID2 } from "crypto";
4994
5168
  var MAX_WORKSPACES = 50;
4995
5169
  function expandPath(p) {
4996
5170
  const t = (p || "").trim();
4997
5171
  if (!t) return "";
4998
- if (t.startsWith("~")) return path4.join(os.homedir(), t.slice(1).replace(/^\//, ""));
4999
- return path4.resolve(t);
5172
+ if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
5173
+ return path5.resolve(t);
5000
5174
  }
5001
5175
  function validateWorkspacePath(absPath) {
5002
5176
  try {
@@ -5010,7 +5184,7 @@ function validateWorkspacePath(absPath) {
5010
5184
  }
5011
5185
  }
5012
5186
  function defaultWorkspaceLabel(absPath) {
5013
- const base = path4.basename(absPath) || absPath;
5187
+ const base = path5.basename(absPath) || absPath;
5014
5188
  return base;
5015
5189
  }
5016
5190
  function getDefaultWorkspacePath(config) {
@@ -5101,9 +5275,9 @@ function resolveIdeLaunchWorkspace(args, config) {
5101
5275
  return getDefaultWorkspacePath(config) || void 0;
5102
5276
  }
5103
5277
  function findWorkspaceByPath(config, rawPath) {
5104
- const abs = path4.resolve(expandPath(rawPath));
5278
+ const abs = path5.resolve(expandPath(rawPath));
5105
5279
  if (!abs) return void 0;
5106
- return (config.workspaces || []).find((w) => path4.resolve(expandPath(w.path)) === abs);
5280
+ return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
5107
5281
  }
5108
5282
  function addWorkspaceEntry(config, rawPath, label, options) {
5109
5283
  const abs = expandPath(rawPath);
@@ -5119,7 +5293,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
5119
5293
  const v = validateWorkspacePath(abs);
5120
5294
  if (!v.ok) return { error: v.error };
5121
5295
  const list = [...config.workspaces || []];
5122
- if (list.some((w) => path4.resolve(w.path) === abs)) {
5296
+ if (list.some((w) => path5.resolve(w.path) === abs)) {
5123
5297
  return { error: "Workspace already in list" };
5124
5298
  }
5125
5299
  if (list.length >= MAX_WORKSPACES) {
@@ -5153,7 +5327,7 @@ function setDefaultWorkspaceId(config, id) {
5153
5327
  }
5154
5328
 
5155
5329
  // src/config/recent-activity.ts
5156
- import * as path5 from "path";
5330
+ import * as path6 from "path";
5157
5331
 
5158
5332
  // src/providers/summary-metadata.ts
5159
5333
  function normalizeSummaryItem(item) {
@@ -5222,9 +5396,9 @@ var MAX_ACTIVITY = 30;
5222
5396
  function normalizeWorkspace(workspace) {
5223
5397
  if (!workspace) return "";
5224
5398
  try {
5225
- return path5.resolve(expandPath(workspace));
5399
+ return path6.resolve(expandPath(workspace));
5226
5400
  } catch {
5227
- return path5.resolve(workspace);
5401
+ return path6.resolve(workspace);
5228
5402
  }
5229
5403
  }
5230
5404
  function buildRecentActivityKey(entry) {
@@ -5392,14 +5566,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
5392
5566
  }
5393
5567
 
5394
5568
  // src/config/saved-sessions.ts
5395
- import * as path6 from "path";
5569
+ import * as path7 from "path";
5396
5570
  var MAX_SAVED_SESSIONS = 500;
5397
5571
  function normalizeWorkspace2(workspace) {
5398
5572
  if (!workspace) return "";
5399
5573
  try {
5400
- return path6.resolve(expandPath(workspace));
5574
+ return path7.resolve(expandPath(workspace));
5401
5575
  } catch {
5402
- return path6.resolve(workspace);
5576
+ return path7.resolve(workspace);
5403
5577
  }
5404
5578
  }
5405
5579
  function buildSavedProviderSessionKey(providerSessionId) {
@@ -5505,8 +5679,8 @@ async function syncMeshes(transport) {
5505
5679
 
5506
5680
  // src/config/state-store.ts
5507
5681
  init_config();
5508
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5509
- import { join as join4 } from "path";
5682
+ import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5683
+ import { join as join5 } from "path";
5510
5684
  var DEFAULT_STATE = {
5511
5685
  recentActivity: [],
5512
5686
  savedProviderSessions: [],
@@ -5519,7 +5693,7 @@ function isPlainObject2(value) {
5519
5693
  return !!value && typeof value === "object" && !Array.isArray(value);
5520
5694
  }
5521
5695
  function getStatePath() {
5522
- return join4(getConfigDir(), "state.json");
5696
+ return join5(getConfigDir(), "state.json");
5523
5697
  }
5524
5698
  function normalizeState(raw) {
5525
5699
  const parsed = isPlainObject2(raw) ? raw : {};
@@ -5555,7 +5729,7 @@ function normalizeState(raw) {
5555
5729
  }
5556
5730
  function loadState() {
5557
5731
  const statePath = getStatePath();
5558
- if (!existsSync4(statePath)) {
5732
+ if (!existsSync5(statePath)) {
5559
5733
  return { ...DEFAULT_STATE };
5560
5734
  }
5561
5735
  try {
@@ -5576,9 +5750,9 @@ function resetState() {
5576
5750
 
5577
5751
  // src/detection/ide-detector.ts
5578
5752
  import { execSync } from "child_process";
5579
- import { existsSync as existsSync5 } from "fs";
5753
+ import { existsSync as existsSync6 } from "fs";
5580
5754
  import { platform, homedir as homedir3 } from "os";
5581
- import * as path7 from "path";
5755
+ import * as path8 from "path";
5582
5756
  var BUILTIN_IDE_DEFINITIONS = [];
5583
5757
  var registeredIDEs = /* @__PURE__ */ new Map();
5584
5758
  function registerIDEDefinition(def) {
@@ -5597,10 +5771,10 @@ function getMergedDefinitions() {
5597
5771
  function findCliCommand(command) {
5598
5772
  const trimmed = String(command || "").trim();
5599
5773
  if (!trimmed) return null;
5600
- if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5601
- const candidate = trimmed.startsWith("~") ? path7.join(homedir3(), trimmed.slice(1)) : trimmed;
5602
- const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
5603
- return existsSync5(resolved) ? resolved : null;
5774
+ if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5775
+ const candidate = trimmed.startsWith("~") ? path8.join(homedir3(), trimmed.slice(1)) : trimmed;
5776
+ const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
5777
+ return existsSync6(resolved) ? resolved : null;
5604
5778
  }
5605
5779
  try {
5606
5780
  const result = execSync(
@@ -5627,31 +5801,31 @@ function getIdeVersion(cliCommand) {
5627
5801
  function checkPathExists(paths) {
5628
5802
  const home = homedir3();
5629
5803
  for (const p of paths) {
5630
- const normalized = p.startsWith("~") ? path7.join(home, p.slice(1)) : p;
5804
+ const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
5631
5805
  if (normalized.includes("*")) {
5632
5806
  const username = home.split(/[\\/]/).pop() || "";
5633
5807
  const resolved = normalized.replace("*", username);
5634
- if (existsSync5(resolved)) return resolved;
5808
+ if (existsSync6(resolved)) return resolved;
5635
5809
  } else {
5636
- if (existsSync5(normalized)) return normalized;
5810
+ if (existsSync6(normalized)) return normalized;
5637
5811
  }
5638
5812
  }
5639
5813
  return null;
5640
5814
  }
5641
5815
  async function detectIDEs(providerLoader) {
5642
- const os21 = platform();
5816
+ const os22 = platform();
5643
5817
  const results = [];
5644
5818
  for (const def of getMergedDefinitions()) {
5645
5819
  const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
5646
- const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os21] || []) || []);
5820
+ const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
5647
5821
  let resolvedCli = cliPath;
5648
- if (!resolvedCli && appPath && os21 === "darwin") {
5822
+ if (!resolvedCli && appPath && os22 === "darwin") {
5649
5823
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
5650
- if (existsSync5(bundledCli)) resolvedCli = bundledCli;
5824
+ if (existsSync6(bundledCli)) resolvedCli = bundledCli;
5651
5825
  }
5652
- if (!resolvedCli && appPath && os21 === "win32") {
5653
- const { dirname: dirname8 } = await import("path");
5654
- const appDir = dirname8(appPath);
5826
+ if (!resolvedCli && appPath && os22 === "win32") {
5827
+ const { dirname: dirname9 } = await import("path");
5828
+ const appDir = dirname9(appPath);
5655
5829
  const candidates = [
5656
5830
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
5657
5831
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -5660,13 +5834,13 @@ async function detectIDEs(providerLoader) {
5660
5834
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
5661
5835
  ];
5662
5836
  for (const c of candidates) {
5663
- if (existsSync5(c)) {
5837
+ if (existsSync6(c)) {
5664
5838
  resolvedCli = c;
5665
5839
  break;
5666
5840
  }
5667
5841
  }
5668
5842
  }
5669
- const installed = os21 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
5843
+ const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
5670
5844
  const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
5671
5845
  results.push({
5672
5846
  id: def.id,
@@ -5685,8 +5859,8 @@ async function detectIDEs(providerLoader) {
5685
5859
  // src/detection/cli-detector.ts
5686
5860
  import { exec } from "child_process";
5687
5861
  import * as os2 from "os";
5688
- import * as path8 from "path";
5689
- import { existsSync as existsSync6 } from "fs";
5862
+ import * as path9 from "path";
5863
+ import { existsSync as existsSync7 } from "fs";
5690
5864
  function parseVersion(raw) {
5691
5865
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
5692
5866
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
@@ -5698,19 +5872,19 @@ function shellQuote(value) {
5698
5872
  function expandHome(value) {
5699
5873
  const trimmed = value.trim();
5700
5874
  if (!trimmed.startsWith("~")) return trimmed;
5701
- return path8.join(os2.homedir(), trimmed.slice(1));
5875
+ return path9.join(os2.homedir(), trimmed.slice(1));
5702
5876
  }
5703
5877
  function isExplicitCommandPath(command) {
5704
5878
  const trimmed = command.trim();
5705
- return path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
5879
+ return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
5706
5880
  }
5707
5881
  function resolveCommandPath(command) {
5708
5882
  const trimmed = command.trim();
5709
5883
  if (!trimmed) return null;
5710
5884
  if (isExplicitCommandPath(trimmed)) {
5711
5885
  const expanded = expandHome(trimmed);
5712
- const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
5713
- return existsSync6(candidate) ? candidate : null;
5886
+ const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
5887
+ return existsSync7(candidate) ? candidate : null;
5714
5888
  }
5715
5889
  return null;
5716
5890
  }
@@ -7782,6 +7956,44 @@ function normalizeChatMessage(message) {
7782
7956
  function normalizeChatMessages(messages) {
7783
7957
  return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
7784
7958
  }
7959
+ function readMessageMeta(message) {
7960
+ const meta = message?.meta;
7961
+ return meta && typeof meta === "object" && !Array.isArray(meta) ? meta : null;
7962
+ }
7963
+ function readStringField(value) {
7964
+ return typeof value === "string" ? value.trim().toLowerCase() : "";
7965
+ }
7966
+ function readVisibilityField(message, meta) {
7967
+ const record = message;
7968
+ return readStringField(record.visibility ?? record.transcriptVisibility ?? meta?.visibility ?? meta?.transcriptVisibility);
7969
+ }
7970
+ function isExplicitlyHiddenFromTranscript(message, meta) {
7971
+ const record = message;
7972
+ const visibility = readVisibilityField(message, meta);
7973
+ const audience = readStringField(record.audience ?? meta?.audience);
7974
+ const source = readStringField(record.source ?? meta?.source);
7975
+ 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;
7976
+ }
7977
+ function isExplicitlyVisibleInTranscript(message, meta) {
7978
+ const record = message;
7979
+ const visibility = readVisibilityField(message, meta);
7980
+ const audience = readStringField(record.audience ?? meta?.audience);
7981
+ return visibility === "visible" || visibility === "user" || visibility === "chat" || audience === "chat" || record.userFacing === true || meta?.userFacing === true;
7982
+ }
7983
+ function isUserFacingChatMessage(message) {
7984
+ if (!message) return false;
7985
+ const meta = readMessageMeta(message);
7986
+ if (isExplicitlyHiddenFromTranscript(message, meta)) return false;
7987
+ if (isExplicitlyVisibleInTranscript(message, meta)) return true;
7988
+ const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
7989
+ const kind = resolveChatMessageKind(message);
7990
+ if (role === "user" || role === "human") return kind === "standard" || kind === "";
7991
+ if (role === "assistant") return kind === "standard" || kind === "";
7992
+ return false;
7993
+ }
7994
+ function filterUserFacingChatMessages(messages) {
7995
+ return (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
7996
+ }
7785
7997
 
7786
7998
  // src/providers/control-effects.ts
7787
7999
  function extractProviderControlValues(controls, data) {
@@ -7978,9 +8190,9 @@ ${cleanBody}`;
7978
8190
 
7979
8191
  // src/config/chat-history.ts
7980
8192
  import * as fs3 from "fs";
7981
- import * as path10 from "path";
8193
+ import * as path11 from "path";
7982
8194
  import * as os5 from "os";
7983
- var HISTORY_DIR = path10.join(os5.homedir(), ".adhdev", "history");
8195
+ var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
7984
8196
  var RETAIN_DAYS = 30;
7985
8197
  var SAVED_HISTORY_INDEX_VERSION = 1;
7986
8198
  var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
@@ -8143,7 +8355,7 @@ function extractSavedHistorySessionIdFromFile(file) {
8143
8355
  function buildSavedHistoryFileSignatureMap(dir, files) {
8144
8356
  return new Map(files.map((file) => {
8145
8357
  try {
8146
- const stat2 = fs3.statSync(path10.join(dir, file));
8358
+ const stat2 = fs3.statSync(path11.join(dir, file));
8147
8359
  return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
8148
8360
  } catch {
8149
8361
  return [file, `${file}:missing`];
@@ -8154,7 +8366,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
8154
8366
  return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
8155
8367
  }
8156
8368
  function getSavedHistoryIndexFilePath(dir) {
8157
- return path10.join(dir, SAVED_HISTORY_INDEX_FILE);
8369
+ return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
8158
8370
  }
8159
8371
  function getSavedHistoryIndexLockPath(dir) {
8160
8372
  return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
@@ -8256,7 +8468,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
8256
8468
  }
8257
8469
  for (const file of Array.from(currentEntries.keys())) {
8258
8470
  if (incomingFiles.has(file)) continue;
8259
- if (!fs3.existsSync(path10.join(dir, file))) {
8471
+ if (!fs3.existsSync(path11.join(dir, file))) {
8260
8472
  currentEntries.delete(file);
8261
8473
  }
8262
8474
  }
@@ -8282,7 +8494,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
8282
8494
  const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
8283
8495
  const files = listHistoryFiles(dir);
8284
8496
  for (const file of files) {
8285
- const stat2 = fs3.statSync(path10.join(dir, file));
8497
+ const stat2 = fs3.statSync(path11.join(dir, file));
8286
8498
  if (stat2.mtimeMs > indexStat.mtimeMs) return true;
8287
8499
  }
8288
8500
  return false;
@@ -8292,14 +8504,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
8292
8504
  }
8293
8505
  function buildSavedHistoryFileSignature(dir, file) {
8294
8506
  try {
8295
- const stat2 = fs3.statSync(path10.join(dir, file));
8507
+ const stat2 = fs3.statSync(path11.join(dir, file));
8296
8508
  return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
8297
8509
  } catch {
8298
8510
  return `${file}:missing`;
8299
8511
  }
8300
8512
  }
8301
8513
  function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
8302
- const filePath = path10.join(dir, file);
8514
+ const filePath = path11.join(dir, file);
8303
8515
  const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
8304
8516
  const currentEntry = entries.get(file) || null;
8305
8517
  const nextSummary = updater(currentEntry?.summary || null);
@@ -8372,7 +8584,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
8372
8584
  function computeSavedHistoryFileSummary(dir, file) {
8373
8585
  const historySessionId = extractSavedHistorySessionIdFromFile(file);
8374
8586
  if (!historySessionId) return null;
8375
- const filePath = path10.join(dir, file);
8587
+ const filePath = path11.join(dir, file);
8376
8588
  const content = fs3.readFileSync(filePath, "utf-8");
8377
8589
  const lines = content.split("\n").filter(Boolean);
8378
8590
  let messageCount = 0;
@@ -8459,7 +8671,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
8459
8671
  const summaryBySessionId = /* @__PURE__ */ new Map();
8460
8672
  const nextPersistedEntries = /* @__PURE__ */ new Map();
8461
8673
  for (const file of files.slice().sort()) {
8462
- const filePath = path10.join(dir, file);
8674
+ const filePath = path11.join(dir, file);
8463
8675
  const signature = fileSignatures.get(file) || `${file}:missing`;
8464
8676
  const cached = savedHistoryFileSummaryCache.get(filePath);
8465
8677
  const persisted = persistedEntries.get(file);
@@ -8579,12 +8791,12 @@ var ChatHistoryWriter = class {
8579
8791
  });
8580
8792
  }
8581
8793
  if (newMessages.length === 0) return;
8582
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8794
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8583
8795
  fs3.mkdirSync(dir, { recursive: true });
8584
8796
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8585
8797
  const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
8586
8798
  const fileName = `${filePrefix}${date}.jsonl`;
8587
- const filePath = path10.join(dir, fileName);
8799
+ const filePath = path11.join(dir, fileName);
8588
8800
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
8589
8801
  fs3.appendFileSync(filePath, lines, "utf-8");
8590
8802
  updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
@@ -8675,11 +8887,11 @@ var ChatHistoryWriter = class {
8675
8887
  const ws = String(workspace || "").trim();
8676
8888
  if (!id || !ws) return;
8677
8889
  try {
8678
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8890
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8679
8891
  fs3.mkdirSync(dir, { recursive: true });
8680
8892
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8681
8893
  const fileName = `${this.sanitize(id)}_${date}.jsonl`;
8682
- const filePath = path10.join(dir, fileName);
8894
+ const filePath = path11.join(dir, fileName);
8683
8895
  const record = {
8684
8896
  ts: (/* @__PURE__ */ new Date()).toISOString(),
8685
8897
  receivedAt: Date.now(),
@@ -8725,14 +8937,14 @@ var ChatHistoryWriter = class {
8725
8937
  this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
8726
8938
  this.lastSeenCounts.delete(fromDedupKey);
8727
8939
  }
8728
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8940
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8729
8941
  if (!fs3.existsSync(dir)) return;
8730
8942
  const fromPrefix = `${this.sanitize(fromId)}_`;
8731
8943
  const toPrefix = `${this.sanitize(toId)}_`;
8732
8944
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
8733
8945
  for (const file of files) {
8734
- const sourcePath = path10.join(dir, file);
8735
- const targetPath = path10.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
8946
+ const sourcePath = path11.join(dir, file);
8947
+ const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
8736
8948
  const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
8737
8949
  const rewritten = sourceLines.map((line) => {
8738
8950
  try {
@@ -8766,13 +8978,13 @@ var ChatHistoryWriter = class {
8766
8978
  const sessionId = String(historySessionId || "").trim();
8767
8979
  if (!sessionId) return;
8768
8980
  try {
8769
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8981
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8770
8982
  if (!fs3.existsSync(dir)) return;
8771
8983
  const prefix = `${this.sanitize(sessionId)}_`;
8772
8984
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
8773
8985
  const seen = /* @__PURE__ */ new Set();
8774
8986
  for (const file of files) {
8775
- const filePath = path10.join(dir, file);
8987
+ const filePath = path11.join(dir, file);
8776
8988
  const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8777
8989
  const next = [];
8778
8990
  for (const line of lines) {
@@ -8826,11 +9038,11 @@ var ChatHistoryWriter = class {
8826
9038
  const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
8827
9039
  const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
8828
9040
  for (const dir of agentDirs) {
8829
- const dirPath = path10.join(HISTORY_DIR, dir.name);
9041
+ const dirPath = path11.join(HISTORY_DIR, dir.name);
8830
9042
  const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
8831
9043
  let removedAny = false;
8832
9044
  for (const file of files) {
8833
- const filePath = path10.join(dirPath, file);
9045
+ const filePath = path11.join(dirPath, file);
8834
9046
  const stat2 = fs3.statSync(filePath);
8835
9047
  if (stat2.mtimeMs < cutoff) {
8836
9048
  fs3.unlinkSync(filePath);
@@ -8880,13 +9092,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
8880
9092
  function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
8881
9093
  try {
8882
9094
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
8883
- const dir = path10.join(HISTORY_DIR, sanitized);
9095
+ const dir = path11.join(HISTORY_DIR, sanitized);
8884
9096
  if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
8885
9097
  const files = listHistoryFiles(dir, historySessionId);
8886
9098
  const allMessages = [];
8887
9099
  const seen = /* @__PURE__ */ new Set();
8888
9100
  for (const file of files) {
8889
- const filePath = path10.join(dir, file);
9101
+ const filePath = path11.join(dir, file);
8890
9102
  const content = fs3.readFileSync(filePath, "utf-8");
8891
9103
  const lines = content.trim().split("\n").filter(Boolean);
8892
9104
  for (let i = 0; i < lines.length; i++) {
@@ -8910,7 +9122,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
8910
9122
  function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
8911
9123
  try {
8912
9124
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
8913
- const dir = path10.join(HISTORY_DIR, sanitized);
9125
+ const dir = path11.join(HISTORY_DIR, sanitized);
8914
9126
  if (!fs3.existsSync(dir)) {
8915
9127
  savedHistorySessionCache.delete(sanitized);
8916
9128
  return { sessions: [], hasMore: false };
@@ -8971,11 +9183,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
8971
9183
  }
8972
9184
  function readExistingSessionStartRecord(agentType, historySessionId) {
8973
9185
  try {
8974
- const dir = path10.join(HISTORY_DIR, agentType);
9186
+ const dir = path11.join(HISTORY_DIR, agentType);
8975
9187
  if (!fs3.existsSync(dir)) return null;
8976
9188
  const files = listHistoryFiles(dir, historySessionId).sort();
8977
9189
  for (const file of files) {
8978
- const lines = fs3.readFileSync(path10.join(dir, file), "utf-8").split("\n").filter(Boolean);
9190
+ const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
8979
9191
  for (const line of lines) {
8980
9192
  try {
8981
9193
  const parsed = JSON.parse(line);
@@ -8995,16 +9207,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
8995
9207
  function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
8996
9208
  if (records.length === 0) return false;
8997
9209
  try {
8998
- const dir = path10.join(HISTORY_DIR, agentType);
9210
+ const dir = path11.join(HISTORY_DIR, agentType);
8999
9211
  fs3.mkdirSync(dir, { recursive: true });
9000
9212
  const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
9001
9213
  for (const file of fs3.readdirSync(dir)) {
9002
9214
  if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
9003
- fs3.unlinkSync(path10.join(dir, file));
9215
+ fs3.unlinkSync(path11.join(dir, file));
9004
9216
  }
9005
9217
  }
9006
9218
  const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
9007
- const filePath = path10.join(dir, `${prefix}${targetDate}.jsonl`);
9219
+ const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
9008
9220
  fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
9009
9221
  `, "utf-8");
9010
9222
  invalidatePersistedSavedHistoryIndex(agentType, dir);
@@ -9754,6 +9966,14 @@ function validateMessage(message, source, index) {
9754
9966
  if (typeof message.senderName === "string") normalized.senderName = message.senderName;
9755
9967
  if (typeof message._type === "string") normalized._type = message._type;
9756
9968
  if (typeof message._sub === "string") normalized._sub = message._sub;
9969
+ if (typeof message.visibility === "string") normalized.visibility = message.visibility;
9970
+ if (typeof message.transcriptVisibility === "string") normalized.transcriptVisibility = message.transcriptVisibility;
9971
+ if (typeof message.audience === "string") normalized.audience = message.audience;
9972
+ if (typeof message.source === "string") normalized.source = message.source;
9973
+ if (typeof message.userFacing === "boolean") normalized.userFacing = message.userFacing;
9974
+ if (typeof message.internal === "boolean") normalized.internal = message.internal;
9975
+ if (typeof message.isInternal === "boolean") normalized.isInternal = message.isInternal;
9976
+ if (typeof message.debug === "boolean") normalized.debug = message.debug;
9757
9977
  return normalized;
9758
9978
  }
9759
9979
  function validateModal(activeModal, status, source) {
@@ -10999,6 +11219,14 @@ function getActiveChatOptions(profile) {
10999
11219
  if (profile === "full") return {};
11000
11220
  return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
11001
11221
  }
11222
+ function resolveSessionStatus(activeChat, providerStatus) {
11223
+ const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
11224
+ const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
11225
+ if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
11226
+ if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
11227
+ if (topLevelStatus !== "idle") return topLevelStatus;
11228
+ return chatStatus;
11229
+ }
11002
11230
  function shouldIncludeSessionControls(profile) {
11003
11231
  return profile !== "live";
11004
11232
  }
@@ -11077,9 +11305,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
11077
11305
  providerName: state.name,
11078
11306
  kind: "workspace",
11079
11307
  transport: "cdp-page",
11080
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11081
- activeModal: activeChat?.activeModal || null
11082
- }),
11308
+ status: resolveSessionStatus(activeChat, state.status),
11083
11309
  title,
11084
11310
  workspace,
11085
11311
  ...git && { git },
@@ -11114,9 +11340,7 @@ function buildExtensionAgentSession(parent, ext, options) {
11114
11340
  providerSessionId: ext.providerSessionId,
11115
11341
  kind: "agent",
11116
11342
  transport: "cdp-webview",
11117
- status: normalizeManagedStatus(activeChat?.status || ext.status, {
11118
- activeModal: activeChat?.activeModal || null
11119
- }),
11343
+ status: resolveSessionStatus(activeChat, ext.status),
11120
11344
  title: activeChat?.title || ext.name,
11121
11345
  workspace,
11122
11346
  ...git && { git },
@@ -11166,9 +11390,7 @@ function buildCliSession(state, options) {
11166
11390
  providerSessionId: state.providerSessionId,
11167
11391
  kind: "agent",
11168
11392
  transport: "pty",
11169
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11170
- activeModal: activeChat?.activeModal || null
11171
- }),
11393
+ status: resolveSessionStatus(activeChat, state.status),
11172
11394
  title: activeChat?.title || state.name,
11173
11395
  workspace,
11174
11396
  ...git && { git },
@@ -11216,9 +11438,7 @@ function buildAcpSession(state, options) {
11216
11438
  providerName: state.name,
11217
11439
  kind: "agent",
11218
11440
  transport: "acp",
11219
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11220
- activeModal: activeChat?.activeModal || null
11221
- }),
11441
+ status: resolveSessionStatus(activeChat, state.status),
11222
11442
  title: activeChat?.title || state.name,
11223
11443
  workspace,
11224
11444
  ...git && { git },
@@ -11341,7 +11561,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
11341
11561
  // src/commands/chat-commands.ts
11342
11562
  import * as fs4 from "fs";
11343
11563
  import * as os6 from "os";
11344
- import * as path11 from "path";
11564
+ import * as path12 from "path";
11345
11565
  import { randomUUID as randomUUID5 } from "crypto";
11346
11566
 
11347
11567
  // src/providers/provider-input-support.ts
@@ -11544,6 +11764,7 @@ function buildSessionModalDeliverySignature(payload) {
11544
11764
  // src/commands/chat-commands.ts
11545
11765
  var RECENT_SEND_WINDOW_MS = 1200;
11546
11766
  var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
11767
+ var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
11547
11768
  var recentSendByTarget = /* @__PURE__ */ new Map();
11548
11769
  function getCurrentProviderType(h, fallback = "") {
11549
11770
  return h.currentSession?.providerType || h.currentProviderType || fallback;
@@ -11596,6 +11817,16 @@ function buildSendInputSignature(input) {
11596
11817
  function getSendChatInputEnvelope(args) {
11597
11818
  return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
11598
11819
  }
11820
+ function sleep(ms) {
11821
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
11822
+ }
11823
+ async function waitOnceForFreshHermesCliStart(adapter, log) {
11824
+ if (adapter.cliType !== "hermes-cli") return;
11825
+ const status = typeof adapter.getStatus === "function" ? adapter.getStatus()?.status : void 0;
11826
+ if (status !== "starting") return;
11827
+ log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
11828
+ await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
11829
+ }
11599
11830
  function getHistorySessionId(h, args) {
11600
11831
  const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
11601
11832
  if (explicit) return explicit;
@@ -11650,7 +11881,7 @@ function normalizeReadChatTailLimit(args) {
11650
11881
  }
11651
11882
  function normalizeReadChatMessages(payload) {
11652
11883
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
11653
- return messages;
11884
+ return normalizeChatMessages(messages);
11654
11885
  }
11655
11886
  function deriveHistoryDedupKey(message) {
11656
11887
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -11704,6 +11935,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
11704
11935
  return raw;
11705
11936
  }
11706
11937
  }
11938
+ function isGeneratingLikeStatus(status) {
11939
+ return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
11940
+ }
11941
+ function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
11942
+ if (!isGeneratingLikeStatus(parsedStatus)) return false;
11943
+ if (hasNonEmptyModalButtons(activeModal)) return false;
11944
+ const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
11945
+ if (adapterRawStatus !== "idle") return false;
11946
+ if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
11947
+ return true;
11948
+ }
11949
+ function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
11950
+ if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
11951
+ return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
11952
+ }
11953
+ function finalizeStreamingMessagesWhenIdle(messages, status) {
11954
+ if (status !== "idle") return messages;
11955
+ return messages.map((message) => {
11956
+ const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
11957
+ const hasStreamingMeta = meta?.streaming === true;
11958
+ if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
11959
+ return {
11960
+ ...message,
11961
+ ...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
11962
+ ...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
11963
+ };
11964
+ });
11965
+ }
11707
11966
  function buildReadChatCommandResult(payload, args) {
11708
11967
  let validatedPayload;
11709
11968
  const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
@@ -11716,13 +11975,22 @@ function buildReadChatCommandResult(payload, args) {
11716
11975
  return { success: false, error: error?.message || String(error) };
11717
11976
  }
11718
11977
  const messages = normalizeReadChatMessages(validatedPayload);
11719
- const sync = buildFullTail(messages, normalizeReadChatTailLimit(args));
11978
+ const visibleMessages = filterUserFacingChatMessages(messages);
11979
+ const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
11980
+ const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
11981
+ const returnedDebugReadChat = debugReadChat ? {
11982
+ ...debugReadChat,
11983
+ fullMsgCount: typeof debugReadChat.fullMsgCount === "number" ? debugReadChat.fullMsgCount : messages.length,
11984
+ visibleMsgCount: visibleMessages.length,
11985
+ hiddenMsgCount,
11986
+ returnedMsgCount: sync.messages.length
11987
+ } : void 0;
11720
11988
  return {
11721
11989
  success: true,
11722
11990
  ...validatedPayload,
11723
11991
  messages: sync.messages,
11724
11992
  totalMessages: sync.totalMessages,
11725
- ...debugReadChat ? { debugReadChat } : {}
11993
+ ...returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}
11726
11994
  };
11727
11995
  }
11728
11996
  var DEFAULT_DEBUG_SANITIZE_OPTIONS = {
@@ -11852,7 +12120,7 @@ function buildDebugBundleText(bundle) {
11852
12120
  }
11853
12121
  function getChatDebugBundleDir() {
11854
12122
  const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
11855
- return override || path11.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
12123
+ return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
11856
12124
  }
11857
12125
  function safeBundleIdSegment(value, fallback) {
11858
12126
  const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
@@ -11868,6 +12136,14 @@ function buildChatDebugBundleSummary(bundle) {
11868
12136
  const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
11869
12137
  const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
11870
12138
  const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
12139
+ const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
12140
+ const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
12141
+ const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
12142
+ const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
12143
+ const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
12144
+ const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
12145
+ const cliStatus = typeof cli?.status === "string" ? cli.status : "";
12146
+ const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
11871
12147
  return {
11872
12148
  createdAt: bundle.createdAt,
11873
12149
  targetSessionId: target.targetSessionId,
@@ -11876,8 +12152,22 @@ function buildChatDebugBundleSummary(bundle) {
11876
12152
  readChatSuccess: readChat.success,
11877
12153
  readChatStatus: readChat.status,
11878
12154
  readChatTotalMessages: readChat.totalMessages,
12155
+ readChatReturnedMessages,
11879
12156
  cliStatus: cli?.status,
12157
+ cliParsedStatus: cliParsedStatus || void 0,
11880
12158
  cliMessageCount: cli?.messageCount,
12159
+ cliParsedMessageCount,
12160
+ cliPartialResponseChars: cliPartialResponse.length,
12161
+ parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
12162
+ parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
12163
+ readChatDebug: Object.keys(debugReadChat).length ? {
12164
+ adapterStatus: debugReadChat.adapterStatus,
12165
+ parsedStatus: debugReadChat.parsedStatus,
12166
+ returnedStatus: debugReadChat.returnedStatus,
12167
+ parsedMsgCount: debugReadChat.parsedMsgCount,
12168
+ returnedMsgCount: debugReadChat.returnedMsgCount,
12169
+ shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
12170
+ } : void 0,
11881
12171
  hasFrontendSnapshot: !!frontend
11882
12172
  };
11883
12173
  }
@@ -11885,7 +12175,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
11885
12175
  const bundleId = createChatDebugBundleId(targetSessionId);
11886
12176
  const dir = getChatDebugBundleDir();
11887
12177
  fs4.mkdirSync(dir, { recursive: true });
11888
- const savedPath = path11.join(dir, `${bundleId}.json`);
12178
+ const savedPath = path12.join(dir, `${bundleId}.json`);
11889
12179
  const json = `${JSON.stringify(bundle, null, 2)}
11890
12180
  `;
11891
12181
  fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
@@ -12115,7 +12405,7 @@ async function handleChatHistory(h, args) {
12115
12405
  }
12116
12406
  }
12117
12407
  async function handleReadChat(h, args) {
12118
- const provider = h.getProvider(args?.agentType);
12408
+ const provider = h.getProvider(args?.agentType || args?.providerType);
12119
12409
  const transport = getTargetTransport(h, provider);
12120
12410
  const historySessionId = getHistorySessionId(h, args);
12121
12411
  const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
@@ -12142,10 +12432,13 @@ async function handleReadChat(h, args) {
12142
12432
  const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
12143
12433
  const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
12144
12434
  const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
12145
- const returnedStatus = parsedRecord.status || "idle";
12146
- LOG.debug("Command", `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord.status || "")} parsedMsgCount=${parsedRecord.messages.length}`);
12435
+ const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
12436
+ const runtimeMessageMerger = getTargetInstance(h, args);
12437
+ const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
12438
+ const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
12439
+ LOG.debug("Command", `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord.status || "")} parsedMsgCount=${parsedRecord.messages.length} returnedMsgCount=${returnedMessages.length}`);
12147
12440
  return buildReadChatCommandResult({
12148
- messages: parsedRecord.messages,
12441
+ messages: returnedMessages,
12149
12442
  status: returnedStatus,
12150
12443
  activeModal,
12151
12444
  debugReadChat: {
@@ -12156,7 +12449,7 @@ async function handleReadChat(h, args) {
12156
12449
  returnedStatus: String(returnedStatus || ""),
12157
12450
  shouldPreferAdapterMessages: false,
12158
12451
  parsedMsgCount: parsedRecord.messages.length,
12159
- returnedMsgCount: parsedRecord.messages.length
12452
+ returnedMsgCount: returnedMessages.length
12160
12453
  },
12161
12454
  ...title ? { title } : {},
12162
12455
  ...providerSessionId ? { providerSessionId } : {},
@@ -12402,6 +12695,7 @@ async function handleSendChat(h, args) {
12402
12695
  try {
12403
12696
  assertTextOnlyInput(provider, input);
12404
12697
  if (!text) return { success: false, error: "text required for PTY send" };
12698
+ await waitOnceForFreshHermesCliStart(adapter, _log);
12405
12699
  await adapter.sendMessage(text);
12406
12700
  return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
12407
12701
  } catch (e) {
@@ -12901,9 +13195,17 @@ async function handleResolveAction(h, args) {
12901
13195
  const targetState = targetInstance?.getState?.();
12902
13196
  const surfacedModal = targetState?.activeChat?.activeModal && Array.isArray(targetState.activeChat.activeModal.buttons) && targetState.activeChat.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? targetState.activeChat.activeModal : null;
12903
13197
  const statusModal = status?.activeModal && Array.isArray(status.activeModal.buttons) && status.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? status.activeModal : null;
12904
- const effectiveModal = statusModal || surfacedModal;
12905
- const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" ? "waiting_approval" : status?.status;
12906
- LOG.info("Command", `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || "")} rawStatus=${String(status?.status || "")} effectiveStatus=${String(effectiveStatus || "")} statusModal=${statusModal ? "yes" : "no"} surfacedModal=${surfacedModal ? "yes" : "no"} instance=${targetInstance ? "yes" : "no"}`);
13198
+ const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
13199
+ try {
13200
+ return parseMaybeJson(adapter.getScriptParsedStatus());
13201
+ } catch {
13202
+ return null;
13203
+ }
13204
+ })() : null;
13205
+ 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;
13206
+ const effectiveModal = statusModal || surfacedModal || parsedModal;
13207
+ const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
13208
+ LOG.info("Command", `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || "")} rawStatus=${String(status?.status || "")} effectiveStatus=${String(effectiveStatus || "")} statusModal=${statusModal ? "yes" : "no"} surfacedModal=${surfacedModal ? "yes" : "no"} parsedModal=${parsedModal ? "yes" : "no"} instance=${targetInstance ? "yes" : "no"}`);
12907
13209
  if (!effectiveModal) {
12908
13210
  return { success: false, error: "Not in approval state" };
12909
13211
  }
@@ -13029,7 +13331,7 @@ async function handleResolveAction(h, args) {
13029
13331
 
13030
13332
  // src/commands/cdp-commands.ts
13031
13333
  import * as fs5 from "fs";
13032
- import * as path12 from "path";
13334
+ import * as path13 from "path";
13033
13335
  import * as os7 from "os";
13034
13336
  var KEY_TO_VK = {
13035
13337
  Backspace: 8,
@@ -13286,25 +13588,25 @@ function resolveSafePath(requestedPath) {
13286
13588
  const inputPath = rawPath || ".";
13287
13589
  const home = os7.homedir();
13288
13590
  if (inputPath.startsWith("~")) {
13289
- return path12.resolve(path12.join(home, inputPath.slice(1)));
13591
+ return path13.resolve(path13.join(home, inputPath.slice(1)));
13290
13592
  }
13291
13593
  if (process.platform === "win32") {
13292
13594
  const normalized = normalizeWindowsRequestedPath(inputPath);
13293
- if (path12.win32.isAbsolute(normalized)) {
13294
- return path12.win32.normalize(normalized);
13595
+ if (path13.win32.isAbsolute(normalized)) {
13596
+ return path13.win32.normalize(normalized);
13295
13597
  }
13296
- return path12.win32.resolve(normalized);
13598
+ return path13.win32.resolve(normalized);
13297
13599
  }
13298
- if (path12.isAbsolute(inputPath)) {
13299
- return path12.normalize(inputPath);
13600
+ if (path13.isAbsolute(inputPath)) {
13601
+ return path13.normalize(inputPath);
13300
13602
  }
13301
- return path12.resolve(inputPath);
13603
+ return path13.resolve(inputPath);
13302
13604
  }
13303
13605
  function listDirectoryEntriesSafe(dirPath) {
13304
13606
  const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
13305
13607
  const files = [];
13306
13608
  for (const entry of entries) {
13307
- const entryPath = path12.join(dirPath, entry.name);
13609
+ const entryPath = path13.join(dirPath, entry.name);
13308
13610
  try {
13309
13611
  if (entry.isDirectory()) {
13310
13612
  files.push({ name: entry.name, type: "directory" });
@@ -13358,7 +13660,7 @@ async function handleFileRead(h, args) {
13358
13660
  async function handleFileWrite(h, args) {
13359
13661
  try {
13360
13662
  const filePath = resolveSafePath(args?.path);
13361
- fs5.mkdirSync(path12.dirname(filePath), { recursive: true });
13663
+ fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
13362
13664
  fs5.writeFileSync(filePath, args?.content || "", "utf-8");
13363
13665
  return { success: true, path: filePath };
13364
13666
  } catch (e) {
@@ -14142,9 +14444,11 @@ var DaemonCommandHandler = class {
14142
14444
  }
14143
14445
  const sessionLookupFailed = !!targetSessionId && !session;
14144
14446
  const managerKey = this.extractIdeType(args, sessionLookupFailed);
14145
- let providerType;
14447
+ let providerType = args?.agentType || args?.providerType;
14146
14448
  if (!sessionLookupFailed) {
14147
- providerType = session?.providerType || args?.agentType || args?.providerType || this.inferProviderType(managerKey);
14449
+ providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
14450
+ } else if (!providerType) {
14451
+ providerType = this.inferProviderType(managerKey);
14148
14452
  }
14149
14453
  return { session, managerKey, providerType, sessionLookupFailed };
14150
14454
  }
@@ -14224,7 +14528,8 @@ var DaemonCommandHandler = class {
14224
14528
  "pty_resize",
14225
14529
  "invoke_provider_script"
14226
14530
  ]);
14227
- if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd)) {
14531
+ 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);
14532
+ if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
14228
14533
  const result2 = {
14229
14534
  success: false,
14230
14535
  error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
@@ -14478,16 +14783,16 @@ var DaemonCommandHandler = class {
14478
14783
  // src/commands/cli-manager.ts
14479
14784
  init_provider_cli_adapter();
14480
14785
  import * as os13 from "os";
14481
- import * as path16 from "path";
14786
+ import * as path17 from "path";
14482
14787
  import * as crypto4 from "crypto";
14483
- import { existsSync as existsSync11 } from "fs";
14788
+ import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
14484
14789
  import { execFileSync } from "child_process";
14485
14790
  import chalk from "chalk";
14486
14791
  init_config();
14487
14792
 
14488
14793
  // src/providers/cli-provider-instance.ts
14489
14794
  import * as os12 from "os";
14490
- import * as path15 from "path";
14795
+ import * as path16 from "path";
14491
14796
  import * as crypto3 from "crypto";
14492
14797
  import * as fs6 from "fs";
14493
14798
  import { createRequire } from "module";
@@ -14546,7 +14851,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
14546
14851
  var CachedDatabaseSync = null;
14547
14852
  function getDatabaseSync() {
14548
14853
  if (CachedDatabaseSync) return CachedDatabaseSync;
14549
- const requireFn = typeof __require === "function" ? __require : createRequire(path15.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
14854
+ const requireFn = typeof __require === "function" ? __require : createRequire(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
14550
14855
  const sqliteModule = requireFn(`node:${"sqlite"}`);
14551
14856
  CachedDatabaseSync = sqliteModule.DatabaseSync;
14552
14857
  if (!CachedDatabaseSync) {
@@ -14599,7 +14904,7 @@ var CliProviderInstance = class {
14599
14904
  this.providerSessionId = options?.providerSessionId;
14600
14905
  this.launchMode = options?.launchMode || "new";
14601
14906
  this.onProviderSessionResolved = options?.onProviderSessionResolved;
14602
- this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
14907
+ this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
14603
14908
  this.monitor = new StatusMonitor();
14604
14909
  this.historyWriter = new ChatHistoryWriter();
14605
14910
  }
@@ -15076,7 +15381,19 @@ var CliProviderInstance = class {
15076
15381
  }
15077
15382
  }
15078
15383
  pushEvent(event) {
15079
- this.events.push(event);
15384
+ const enrichedEvent = {
15385
+ ...event,
15386
+ instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
15387
+ targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
15388
+ providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
15389
+ workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
15390
+ providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
15391
+ };
15392
+ if (this.context?.emitProviderEvent) {
15393
+ this.context.emitProviderEvent(enrichedEvent);
15394
+ return;
15395
+ }
15396
+ this.events.push(enrichedEvent);
15080
15397
  }
15081
15398
  flushEvents() {
15082
15399
  const events = [...this.events];
@@ -15283,12 +15600,59 @@ ${effect.notification.body || ""}`.trim();
15283
15600
  );
15284
15601
  }
15285
15602
  }
15603
+ mergeRuntimeChatMessages(parsedMessages) {
15604
+ return this.mergeConversationMessages(parsedMessages);
15605
+ }
15286
15606
  mergeConversationMessages(parsedMessages) {
15287
15607
  if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
15288
- return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
15289
- const aTime = a.message.receivedAt || a.message.timestamp || 0;
15290
- const bTime = b.message.receivedAt || b.message.timestamp || 0;
15291
- if (aTime !== bTime) return aTime - bTime;
15608
+ const parsedEntries = parsedMessages.map((message, index) => ({
15609
+ message,
15610
+ index,
15611
+ source: "parsed"
15612
+ }));
15613
+ const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
15614
+ message: entry.message,
15615
+ index: parsedMessages.length + index,
15616
+ source: "runtime",
15617
+ runtimeKey: entry.key
15618
+ }));
15619
+ const getTime = (message) => {
15620
+ const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
15621
+ return Number.isFinite(value) && value > 0 ? value : 0;
15622
+ };
15623
+ const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
15624
+ const isRuntimeOverlay = (entry) => {
15625
+ if (entry.source !== "runtime") return false;
15626
+ const key = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
15627
+ if (key.startsWith("auto_approval:")) return true;
15628
+ return !isUserFacingChatMessage(entry.message);
15629
+ };
15630
+ const shouldKeepParsedBeforeUntimedRuntime = (message) => {
15631
+ const role = getRole(message);
15632
+ return role === "user" || role === "human";
15633
+ };
15634
+ const shouldKeepParsedAfterUntimedRuntime = (message) => {
15635
+ const role = getRole(message);
15636
+ if (role !== "assistant") return false;
15637
+ const kind = resolveChatMessageKind(message);
15638
+ return kind === "standard" || kind === "terminal";
15639
+ };
15640
+ return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
15641
+ const aTime = getTime(a.message);
15642
+ const bTime = getTime(b.message);
15643
+ if (aTime && bTime && aTime !== bTime) return aTime - bTime;
15644
+ if (a.source !== b.source && aTime !== bTime) {
15645
+ const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
15646
+ const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
15647
+ if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
15648
+ if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
15649
+ return a.source === "parsed" ? -1 : 1;
15650
+ }
15651
+ if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
15652
+ return a.source === "parsed" ? 1 : -1;
15653
+ }
15654
+ }
15655
+ }
15292
15656
  return a.index - b.index;
15293
15657
  }).map((entry) => entry.message));
15294
15658
  }
@@ -16617,17 +16981,17 @@ function shouldRestoreHostedRuntime(record, managerTag) {
16617
16981
  // src/commands/cli-manager.ts
16618
16982
  function isExplicitCommand(command) {
16619
16983
  const trimmed = command.trim();
16620
- return path16.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
16984
+ return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
16621
16985
  }
16622
16986
  function expandExecutable(command) {
16623
16987
  const trimmed = command.trim();
16624
- return trimmed.startsWith("~") ? path16.join(os13.homedir(), trimmed.slice(1)) : trimmed;
16988
+ return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
16625
16989
  }
16626
16990
  function commandExists(command) {
16627
16991
  const trimmed = command.trim();
16628
16992
  if (!trimmed) return false;
16629
16993
  if (isExplicitCommand(trimmed)) {
16630
- return existsSync11(expandExecutable(trimmed));
16994
+ return existsSync12(expandExecutable(trimmed));
16631
16995
  }
16632
16996
  try {
16633
16997
  execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -16645,6 +17009,35 @@ function colorize(color, text) {
16645
17009
  const fn = chalkApi?.[color];
16646
17010
  return typeof fn === "function" ? fn(text) : text;
16647
17011
  }
17012
+ var COORDINATOR_DELEGATED_ENV_UNSETS = {
17013
+ ADHDEV_INLINE_MESH: "",
17014
+ ADHDEV_MCP_TRANSPORT: "",
17015
+ ADHDEV_MESH_ID: "",
17016
+ HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
17017
+ };
17018
+ function hasCliArg(args, flag) {
17019
+ return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
17020
+ }
17021
+ function ensureEmptyDelegatedMcpConfig(workspace) {
17022
+ const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
17023
+ mkdirSync7(baseDir, { recursive: true });
17024
+ const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
17025
+ const filePath = path17.join(baseDir, `${workspaceHash}.json`);
17026
+ writeFileSync7(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
17027
+ return filePath;
17028
+ }
17029
+ function buildCoordinatorDelegatedCliLaunchOptions(input) {
17030
+ const cliType = String(input.cliType || "").trim();
17031
+ const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
17032
+ const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
17033
+ if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
17034
+ cliArgs.unshift("--ignore-user-config");
17035
+ }
17036
+ if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
17037
+ cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
17038
+ }
17039
+ return { cliArgs, env };
17040
+ }
16648
17041
  function isUuid(value) {
16649
17042
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
16650
17043
  }
@@ -16815,7 +17208,7 @@ var DaemonCliManager = class {
16815
17208
  attachExisting
16816
17209
  }) || void 0;
16817
17210
  }
16818
- createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
17211
+ createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
16819
17212
  const normalizedType = this.providerLoader.resolveAlias(cliType);
16820
17213
  const provider = this.providerLoader.getMeta(normalizedType);
16821
17214
  if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
@@ -16829,7 +17222,7 @@ var DaemonCliManager = class {
16829
17222
  providerSessionId,
16830
17223
  attachExisting
16831
17224
  );
16832
- return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
17225
+ return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
16833
17226
  }
16834
17227
  throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
16835
17228
  }
@@ -16902,7 +17295,7 @@ var DaemonCliManager = class {
16902
17295
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
16903
17296
  const trimmed = (workingDir || "").trim();
16904
17297
  if (!trimmed) throw new Error("working directory required");
16905
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path16.resolve(trimmed);
17298
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
16906
17299
  const normalizedType = this.providerLoader.resolveAlias(cliType);
16907
17300
  const rawProvider = this.providerLoader.getByAlias(cliType);
16908
17301
  const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
@@ -17032,6 +17425,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
17032
17425
  {
17033
17426
  providerSessionId: sessionBinding.providerSessionId,
17034
17427
  launchMode: sessionBinding.launchMode,
17428
+ extraEnv: options?.extraEnv,
17035
17429
  onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
17036
17430
  this.persistRecentActivity({
17037
17431
  kind: "cli",
@@ -17052,7 +17446,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
17052
17446
  resolvedCliArgs,
17053
17447
  key,
17054
17448
  sessionBinding.providerSessionId,
17055
- false
17449
+ false,
17450
+ options?.extraEnv
17056
17451
  );
17057
17452
  try {
17058
17453
  await adapter.spawn();
@@ -17276,12 +17671,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
17276
17671
  const dir = resolved.path;
17277
17672
  const launchSource = resolved.source;
17278
17673
  if (!cliType) throw new Error("cliType required");
17674
+ const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
17675
+ const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
17676
+ cliType,
17677
+ workspace: dir,
17678
+ cliArgs: args?.cliArgs,
17679
+ env: args?.env
17680
+ }) : null;
17279
17681
  const started = await this.startSession(
17280
17682
  cliType,
17281
17683
  dir,
17282
- args?.cliArgs,
17684
+ delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
17283
17685
  args?.initialModel,
17284
- { resumeSessionId: args?.resumeSessionId, settingsOverride: args?.settings }
17686
+ {
17687
+ resumeSessionId: args?.resumeSessionId,
17688
+ settingsOverride,
17689
+ extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
17690
+ }
17285
17691
  );
17286
17692
  return {
17287
17693
  success: true,
@@ -17403,11 +17809,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
17403
17809
  import { execSync as execSync4, spawn as spawn2 } from "child_process";
17404
17810
  import * as net from "net";
17405
17811
  import * as os15 from "os";
17406
- import * as path18 from "path";
17812
+ import * as path19 from "path";
17407
17813
 
17408
17814
  // src/providers/provider-loader.ts
17409
17815
  import * as fs7 from "fs";
17410
- import * as path17 from "path";
17816
+ import * as path18 from "path";
17411
17817
  import * as os14 from "os";
17412
17818
  import * as chokidar from "chokidar";
17413
17819
  init_logger();
@@ -17731,7 +18137,7 @@ var ProviderLoader = class _ProviderLoader {
17731
18137
  try {
17732
18138
  if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
17733
18139
  return ["ide", "extension", "cli", "acp"].some(
17734
- (category) => fs7.existsSync(path17.join(candidate, category))
18140
+ (category) => fs7.existsSync(path18.join(candidate, category))
17735
18141
  );
17736
18142
  } catch {
17737
18143
  return false;
@@ -17739,20 +18145,20 @@ var ProviderLoader = class _ProviderLoader {
17739
18145
  }
17740
18146
  static hasProviderRootMarker(candidate) {
17741
18147
  try {
17742
- return fs7.existsSync(path17.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
18148
+ return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
17743
18149
  } catch {
17744
18150
  return false;
17745
18151
  }
17746
18152
  }
17747
18153
  detectDefaultUserDir() {
17748
- const fallback = path17.join(os14.homedir(), ".adhdev", "providers");
18154
+ const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
17749
18155
  const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
17750
18156
  const visited = /* @__PURE__ */ new Set();
17751
18157
  for (const start of this.probeStarts) {
17752
- let current = path17.resolve(start);
18158
+ let current = path18.resolve(start);
17753
18159
  while (!visited.has(current)) {
17754
18160
  visited.add(current);
17755
- const siblingCandidate = path17.join(path17.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
18161
+ const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
17756
18162
  if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
17757
18163
  const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
17758
18164
  if (envOptIn || hasMarker) {
@@ -17774,7 +18180,7 @@ var ProviderLoader = class _ProviderLoader {
17774
18180
  return { path: siblingCandidate, source };
17775
18181
  }
17776
18182
  }
17777
- const parent = path17.dirname(current);
18183
+ const parent = path18.dirname(current);
17778
18184
  if (parent === current) break;
17779
18185
  current = parent;
17780
18186
  }
@@ -17784,11 +18190,11 @@ var ProviderLoader = class _ProviderLoader {
17784
18190
  constructor(options) {
17785
18191
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
17786
18192
  this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
17787
- this.defaultProvidersDir = path17.join(os14.homedir(), ".adhdev", "providers");
18193
+ this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
17788
18194
  const detected = this.detectDefaultUserDir();
17789
18195
  this.userDir = detected.path;
17790
18196
  this.userDirSource = detected.source;
17791
- this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
18197
+ this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
17792
18198
  this.disableUpstream = false;
17793
18199
  this.applySourceConfig({
17794
18200
  userDir: options?.userDir,
@@ -17847,7 +18253,7 @@ var ProviderLoader = class _ProviderLoader {
17847
18253
  this.userDir = detected.path;
17848
18254
  this.userDirSource = detected.source;
17849
18255
  }
17850
- this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
18256
+ this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
17851
18257
  this.disableUpstream = this.sourceMode === "no-upstream";
17852
18258
  if (this.explicitProviderDir) {
17853
18259
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
@@ -17861,7 +18267,7 @@ var ProviderLoader = class _ProviderLoader {
17861
18267
  * Canonical provider directory shape for a given root.
17862
18268
  */
17863
18269
  getProviderDir(root, category, type) {
17864
- return path17.join(root, category, type);
18270
+ return path18.join(root, category, type);
17865
18271
  }
17866
18272
  /**
17867
18273
  * Canonical user override directory for a provider.
@@ -17888,7 +18294,7 @@ var ProviderLoader = class _ProviderLoader {
17888
18294
  resolveProviderFile(type, ...segments) {
17889
18295
  const dir = this.findProviderDirInternal(type);
17890
18296
  if (!dir) return null;
17891
- return path17.join(dir, ...segments);
18297
+ return path18.join(dir, ...segments);
17892
18298
  }
17893
18299
  /**
17894
18300
  * Load all providers (3-tier priority)
@@ -17927,7 +18333,7 @@ var ProviderLoader = class _ProviderLoader {
17927
18333
  if (!fs7.existsSync(this.upstreamDir)) return false;
17928
18334
  try {
17929
18335
  return fs7.readdirSync(this.upstreamDir).some(
17930
- (d) => fs7.statSync(path17.join(this.upstreamDir, d)).isDirectory()
18336
+ (d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
17931
18337
  );
17932
18338
  } catch {
17933
18339
  return false;
@@ -18424,8 +18830,8 @@ var ProviderLoader = class _ProviderLoader {
18424
18830
  resolved._resolvedScriptDir = entry.scriptDir;
18425
18831
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
18426
18832
  if (providerDir) {
18427
- const fullDir = path17.join(providerDir, entry.scriptDir);
18428
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
18833
+ const fullDir = path18.join(providerDir, entry.scriptDir);
18834
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18429
18835
  }
18430
18836
  matched = true;
18431
18837
  }
@@ -18440,8 +18846,8 @@ var ProviderLoader = class _ProviderLoader {
18440
18846
  resolved._resolvedScriptDir = base.defaultScriptDir;
18441
18847
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
18442
18848
  if (providerDir) {
18443
- const fullDir = path17.join(providerDir, base.defaultScriptDir);
18444
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
18849
+ const fullDir = path18.join(providerDir, base.defaultScriptDir);
18850
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18445
18851
  }
18446
18852
  }
18447
18853
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -18458,8 +18864,8 @@ var ProviderLoader = class _ProviderLoader {
18458
18864
  resolved._resolvedScriptDir = dirOverride;
18459
18865
  resolved._resolvedScriptsSource = `versions:${range}`;
18460
18866
  if (providerDir) {
18461
- const fullDir = path17.join(providerDir, dirOverride);
18462
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
18867
+ const fullDir = path18.join(providerDir, dirOverride);
18868
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18463
18869
  }
18464
18870
  }
18465
18871
  } else if (override.scripts) {
@@ -18475,8 +18881,8 @@ var ProviderLoader = class _ProviderLoader {
18475
18881
  resolved._resolvedScriptDir = base.defaultScriptDir;
18476
18882
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
18477
18883
  if (providerDir) {
18478
- const fullDir = path17.join(providerDir, base.defaultScriptDir);
18479
- resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
18884
+ const fullDir = path18.join(providerDir, base.defaultScriptDir);
18885
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18480
18886
  }
18481
18887
  }
18482
18888
  }
@@ -18508,14 +18914,14 @@ var ProviderLoader = class _ProviderLoader {
18508
18914
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
18509
18915
  return null;
18510
18916
  }
18511
- const dir = path17.join(providerDir, scriptDir);
18917
+ const dir = path18.join(providerDir, scriptDir);
18512
18918
  if (!fs7.existsSync(dir)) {
18513
18919
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
18514
18920
  return null;
18515
18921
  }
18516
18922
  const cached = this.scriptsCache.get(dir);
18517
18923
  if (cached) return cached;
18518
- const scriptsJs = path17.join(dir, "scripts.js");
18924
+ const scriptsJs = path18.join(dir, "scripts.js");
18519
18925
  if (fs7.existsSync(scriptsJs)) {
18520
18926
  try {
18521
18927
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -18557,7 +18963,7 @@ var ProviderLoader = class _ProviderLoader {
18557
18963
  return;
18558
18964
  }
18559
18965
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
18560
- this.log(`File changed: ${path17.basename(filePath)}, reloading...`);
18966
+ this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
18561
18967
  this.reload();
18562
18968
  }
18563
18969
  };
@@ -18612,7 +19018,7 @@ var ProviderLoader = class _ProviderLoader {
18612
19018
  }
18613
19019
  const https = __require("https");
18614
19020
  const { execSync: execSync7 } = __require("child_process");
18615
- const metaPath = path17.join(this.upstreamDir, _ProviderLoader.META_FILE);
19021
+ const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
18616
19022
  let prevEtag = "";
18617
19023
  let prevTimestamp = 0;
18618
19024
  try {
@@ -18672,17 +19078,17 @@ var ProviderLoader = class _ProviderLoader {
18672
19078
  return { updated: false };
18673
19079
  }
18674
19080
  this.log("Downloading latest providers from GitHub...");
18675
- const tmpTar = path17.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
18676
- const tmpExtract = path17.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
19081
+ const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
19082
+ const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
18677
19083
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
18678
19084
  fs7.mkdirSync(tmpExtract, { recursive: true });
18679
19085
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
18680
19086
  const extracted = fs7.readdirSync(tmpExtract);
18681
19087
  const rootDir = extracted.find(
18682
- (d) => fs7.statSync(path17.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
19088
+ (d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
18683
19089
  );
18684
19090
  if (!rootDir) throw new Error("Unexpected tarball structure");
18685
- const sourceDir = path17.join(tmpExtract, rootDir);
19091
+ const sourceDir = path18.join(tmpExtract, rootDir);
18686
19092
  const backupDir = this.upstreamDir + ".bak";
18687
19093
  if (fs7.existsSync(this.upstreamDir)) {
18688
19094
  if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
@@ -18757,8 +19163,8 @@ var ProviderLoader = class _ProviderLoader {
18757
19163
  copyDirRecursive(src, dest) {
18758
19164
  fs7.mkdirSync(dest, { recursive: true });
18759
19165
  for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
18760
- const srcPath = path17.join(src, entry.name);
18761
- const destPath = path17.join(dest, entry.name);
19166
+ const srcPath = path18.join(src, entry.name);
19167
+ const destPath = path18.join(dest, entry.name);
18762
19168
  if (entry.isDirectory()) {
18763
19169
  this.copyDirRecursive(srcPath, destPath);
18764
19170
  } else {
@@ -18769,7 +19175,7 @@ var ProviderLoader = class _ProviderLoader {
18769
19175
  /** .meta.json save */
18770
19176
  writeMeta(metaPath, etag, timestamp) {
18771
19177
  try {
18772
- fs7.mkdirSync(path17.dirname(metaPath), { recursive: true });
19178
+ fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
18773
19179
  fs7.writeFileSync(metaPath, JSON.stringify({
18774
19180
  etag,
18775
19181
  timestamp,
@@ -18786,7 +19192,7 @@ var ProviderLoader = class _ProviderLoader {
18786
19192
  const scan = (d) => {
18787
19193
  try {
18788
19194
  for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
18789
- if (entry.isDirectory()) scan(path17.join(d, entry.name));
19195
+ if (entry.isDirectory()) scan(path18.join(d, entry.name));
18790
19196
  else if (entry.name === "provider.json") count++;
18791
19197
  }
18792
19198
  } catch {
@@ -19014,17 +19420,17 @@ var ProviderLoader = class _ProviderLoader {
19014
19420
  for (const root of searchRoots) {
19015
19421
  if (!fs7.existsSync(root)) continue;
19016
19422
  const candidate = this.getProviderDir(root, cat, type);
19017
- if (fs7.existsSync(path17.join(candidate, "provider.json"))) return candidate;
19018
- const catDir = path17.join(root, cat);
19423
+ if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
19424
+ const catDir = path18.join(root, cat);
19019
19425
  if (fs7.existsSync(catDir)) {
19020
19426
  try {
19021
19427
  for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
19022
19428
  if (!entry.isDirectory()) continue;
19023
- const jsonPath = path17.join(catDir, entry.name, "provider.json");
19429
+ const jsonPath = path18.join(catDir, entry.name, "provider.json");
19024
19430
  if (fs7.existsSync(jsonPath)) {
19025
19431
  try {
19026
19432
  const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
19027
- if (data.type === type) return path17.join(catDir, entry.name);
19433
+ if (data.type === type) return path18.join(catDir, entry.name);
19028
19434
  } catch {
19029
19435
  }
19030
19436
  }
@@ -19041,7 +19447,7 @@ var ProviderLoader = class _ProviderLoader {
19041
19447
  * (template substitution is NOT applied here — scripts.js handles that)
19042
19448
  */
19043
19449
  buildScriptWrappersFromDir(dir) {
19044
- const scriptsJs = path17.join(dir, "scripts.js");
19450
+ const scriptsJs = path18.join(dir, "scripts.js");
19045
19451
  if (fs7.existsSync(scriptsJs)) {
19046
19452
  try {
19047
19453
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -19055,7 +19461,7 @@ var ProviderLoader = class _ProviderLoader {
19055
19461
  for (const file of fs7.readdirSync(dir)) {
19056
19462
  if (!file.endsWith(".js")) continue;
19057
19463
  const scriptName = toCamel(file.replace(".js", ""));
19058
- const filePath = path17.join(dir, file);
19464
+ const filePath = path18.join(dir, file);
19059
19465
  result[scriptName] = (...args) => {
19060
19466
  try {
19061
19467
  let content = fs7.readFileSync(filePath, "utf-8");
@@ -19115,7 +19521,7 @@ var ProviderLoader = class _ProviderLoader {
19115
19521
  }
19116
19522
  const hasJson = entries.some((e) => e.name === "provider.json");
19117
19523
  if (hasJson) {
19118
- const jsonPath = path17.join(d, "provider.json");
19524
+ const jsonPath = path18.join(d, "provider.json");
19119
19525
  try {
19120
19526
  const raw = fs7.readFileSync(jsonPath, "utf-8");
19121
19527
  const mod = JSON.parse(raw);
@@ -19136,7 +19542,7 @@ var ProviderLoader = class _ProviderLoader {
19136
19542
  this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
19137
19543
  } else {
19138
19544
  const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
19139
- const scriptsPath = path17.join(d, "scripts.js");
19545
+ const scriptsPath = path18.join(d, "scripts.js");
19140
19546
  if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
19141
19547
  try {
19142
19548
  delete __require.cache[__require.resolve(scriptsPath)];
@@ -19162,7 +19568,7 @@ var ProviderLoader = class _ProviderLoader {
19162
19568
  if (!entry.isDirectory()) continue;
19163
19569
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
19164
19570
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
19165
- scan(path17.join(d, entry.name));
19571
+ scan(path18.join(d, entry.name));
19166
19572
  }
19167
19573
  }
19168
19574
  };
@@ -19487,8 +19893,8 @@ function detectCurrentWorkspace(ideId) {
19487
19893
  const appNameMap = getMacAppIdentifiers();
19488
19894
  const appName = appNameMap[ideId];
19489
19895
  if (appName) {
19490
- const storagePath = path18.join(
19491
- process.env.APPDATA || path18.join(os15.homedir(), "AppData", "Roaming"),
19896
+ const storagePath = path19.join(
19897
+ process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
19492
19898
  appName,
19493
19899
  "storage.json"
19494
19900
  );
@@ -19677,9 +20083,9 @@ init_logger();
19677
20083
 
19678
20084
  // src/logging/command-log.ts
19679
20085
  import * as fs8 from "fs";
19680
- import * as path19 from "path";
20086
+ import * as path20 from "path";
19681
20087
  import * as os16 from "os";
19682
- var LOG_DIR2 = process.platform === "win32" ? path19.join(process.env.LOCALAPPDATA || process.env.APPDATA || path19.join(os16.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path19.join(os16.homedir(), "Library", "Logs", "adhdev") : path19.join(os16.homedir(), ".local", "share", "adhdev", "logs");
20088
+ var LOG_DIR2 = process.platform === "win32" ? path20.join(process.env.LOCALAPPDATA || process.env.APPDATA || path20.join(os16.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path20.join(os16.homedir(), "Library", "Logs", "adhdev") : path20.join(os16.homedir(), ".local", "share", "adhdev", "logs");
19683
20089
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
19684
20090
  var MAX_DAYS = 7;
19685
20091
  try {
@@ -19717,13 +20123,13 @@ function getDateStr2() {
19717
20123
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
19718
20124
  }
19719
20125
  var currentDate2 = getDateStr2();
19720
- var currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20126
+ var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
19721
20127
  var writeCount2 = 0;
19722
20128
  function checkRotation() {
19723
20129
  const today = getDateStr2();
19724
20130
  if (today !== currentDate2) {
19725
20131
  currentDate2 = today;
19726
- currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20132
+ currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
19727
20133
  cleanOldFiles();
19728
20134
  }
19729
20135
  }
@@ -19737,7 +20143,7 @@ function cleanOldFiles() {
19737
20143
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
19738
20144
  if (dateMatch && dateMatch[1] < cutoffStr) {
19739
20145
  try {
19740
- fs8.unlinkSync(path19.join(LOG_DIR2, file));
20146
+ fs8.unlinkSync(path20.join(LOG_DIR2, file));
19741
20147
  } catch {
19742
20148
  }
19743
20149
  }
@@ -19821,13 +20227,65 @@ cleanOldFiles();
19821
20227
 
19822
20228
  // src/commands/router.ts
19823
20229
  init_logger();
20230
+ import * as yaml from "js-yaml";
19824
20231
 
19825
20232
  // src/commands/mesh-coordinator.ts
19826
- import { existsSync as existsSync14, realpathSync as realpathSync2 } from "fs";
20233
+ import { execFileSync as execFileSync2 } from "child_process";
20234
+ import { existsSync as existsSync15, readdirSync as readdirSync6, realpathSync as realpathSync2 } from "fs";
19827
20235
  import { createRequire as createRequire2 } from "module";
19828
- import { dirname as dirname3, join as join17, resolve as resolve13 } from "path";
20236
+ import * as os17 from "os";
20237
+ import { dirname as dirname4, isAbsolute as isAbsolute10, join as join18, resolve as resolve13 } from "path";
19829
20238
  var DEFAULT_SERVER_NAME = "adhdev-mesh";
19830
20239
  var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
20240
+ var HERMES_CLI_TYPE = "hermes-cli";
20241
+ var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
20242
+ function isHermesProvider(provider, cliType) {
20243
+ const type = cliType?.trim() || provider?.type?.trim() || "";
20244
+ return type === HERMES_CLI_TYPE;
20245
+ }
20246
+ function resolveHermesMeshCoordinatorSetup(options) {
20247
+ const mcpServer = resolveAdhdevMcpServerLaunch({
20248
+ meshId: options.meshId,
20249
+ nodeExecutable: options.nodeExecutable,
20250
+ adhdevMcpEntryPath: options.adhdevMcpEntryPath
20251
+ });
20252
+ if (!mcpServer) {
20253
+ return {
20254
+ kind: "unsupported",
20255
+ reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
20256
+ };
20257
+ }
20258
+ const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
20259
+ if (!configPath.trim()) {
20260
+ return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
20261
+ }
20262
+ return {
20263
+ kind: "auto_import",
20264
+ serverName: DEFAULT_SERVER_NAME,
20265
+ configPath,
20266
+ configFormat: "hermes_config_yaml",
20267
+ mcpServer
20268
+ };
20269
+ }
20270
+ function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
20271
+ return {
20272
+ kind: "manual",
20273
+ serverName: DEFAULT_SERVER_NAME,
20274
+ configFormat: "hermes_config_yaml",
20275
+ configPathCommand: HERMES_MCP_CONFIG_PATH,
20276
+ requiresRestart: true,
20277
+ 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.",
20278
+ template: renderMeshCoordinatorTemplate(
20279
+ "mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
20280
+ {
20281
+ meshId,
20282
+ workspace,
20283
+ serverName: DEFAULT_SERVER_NAME,
20284
+ adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
20285
+ }
20286
+ )
20287
+ };
20288
+ }
19831
20289
  function resolveMeshCoordinatorSetup(options) {
19832
20290
  const { provider, meshId, workspace } = options;
19833
20291
  const config = provider?.meshCoordinator;
@@ -19837,6 +20295,9 @@ function resolveMeshCoordinatorSetup(options) {
19837
20295
  reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
19838
20296
  };
19839
20297
  }
20298
+ if (isHermesProvider(provider, options.cliType)) {
20299
+ return resolveHermesMeshCoordinatorSetup(options);
20300
+ }
19840
20301
  const mcpConfig = config.mcpConfig;
19841
20302
  if (!mcpConfig || mcpConfig.mode === "none") {
19842
20303
  return {
@@ -19846,8 +20307,8 @@ function resolveMeshCoordinatorSetup(options) {
19846
20307
  }
19847
20308
  const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
19848
20309
  if (mcpConfig.mode === "auto_import") {
19849
- const path26 = mcpConfig.path?.trim();
19850
- if (!path26) {
20310
+ const path27 = mcpConfig.path?.trim();
20311
+ if (!path27) {
19851
20312
  return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
19852
20313
  }
19853
20314
  const mcpServer = resolveAdhdevMcpServerLaunch({
@@ -19858,13 +20319,13 @@ function resolveMeshCoordinatorSetup(options) {
19858
20319
  if (!mcpServer) {
19859
20320
  return {
19860
20321
  kind: "unsupported",
19861
- reason: "Could not resolve the ADHDev MCP server entrypoint without relying on a PATH bin shim"
20322
+ reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
19862
20323
  };
19863
20324
  }
19864
20325
  return {
19865
20326
  kind: "auto_import",
19866
20327
  serverName,
19867
- configPath: join17(workspace, path26),
20328
+ configPath: resolveMcpConfigPath(path27, workspace),
19868
20329
  configFormat: mcpConfig.format,
19869
20330
  mcpServer
19870
20331
  };
@@ -19898,14 +20359,85 @@ function resolveMeshCoordinatorSetup(options) {
19898
20359
  function renderMeshCoordinatorTemplate(template, values) {
19899
20360
  return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
19900
20361
  }
20362
+ function resolveMcpConfigPath(configPath, workspace) {
20363
+ const trimmed = configPath.trim();
20364
+ if (trimmed === "~") return os17.homedir();
20365
+ if (trimmed.startsWith("~/")) return join18(os17.homedir(), trimmed.slice(2));
20366
+ if (isAbsolute10(trimmed)) return trimmed;
20367
+ return join18(workspace, trimmed);
20368
+ }
19901
20369
  function resolveAdhdevMcpServerLaunch(options) {
19902
20370
  const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
19903
20371
  if (!entryPath) return null;
20372
+ const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
20373
+ if (!nodeExecutable) return null;
19904
20374
  return {
19905
- command: options.nodeExecutable?.trim() || process.execPath,
20375
+ command: nodeExecutable,
19906
20376
  args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
19907
20377
  };
19908
20378
  }
20379
+ function resolveMcpNodeExecutable(explicitExecutable) {
20380
+ const explicit = explicitExecutable?.trim();
20381
+ if (explicit) return explicit;
20382
+ const candidates = [];
20383
+ const addCandidate = (candidate) => {
20384
+ const trimmed = candidate?.trim();
20385
+ if (!trimmed) return;
20386
+ const normalized = normalizeExistingPath(trimmed) || trimmed;
20387
+ if (!candidates.includes(normalized)) candidates.push(normalized);
20388
+ };
20389
+ addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
20390
+ addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
20391
+ addCandidate(process.env.npm_node_execpath);
20392
+ addNodeCandidatesFromPath(process.env.PATH, addCandidate);
20393
+ addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
20394
+ addCandidate("/opt/homebrew/bin/node");
20395
+ addCandidate("/usr/local/bin/node");
20396
+ addCandidate("/usr/bin/node");
20397
+ addCandidate(process.execPath);
20398
+ for (const candidate of candidates) {
20399
+ if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
20400
+ }
20401
+ return null;
20402
+ }
20403
+ function addNodeCandidatesFromPath(pathValue, addCandidate) {
20404
+ for (const entry of (pathValue || "").split(":")) {
20405
+ const dir = entry.trim();
20406
+ if (!dir) continue;
20407
+ addCandidate(join18(dir, "node"));
20408
+ }
20409
+ }
20410
+ function addNodeCandidatesFromNvm(homeDir, addCandidate) {
20411
+ const versionsDir = join18(homeDir, ".nvm", "versions", "node");
20412
+ try {
20413
+ const versionDirs = readdirSync6(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
20414
+ for (const versionDir of versionDirs) {
20415
+ addCandidate(join18(versionsDir, versionDir, "bin", "node"));
20416
+ }
20417
+ } catch {
20418
+ }
20419
+ }
20420
+ function compareNodeVersionNamesDescending(a, b) {
20421
+ const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
20422
+ const left = parse(a);
20423
+ const right = parse(b);
20424
+ for (let i = 0; i < Math.max(left.length, right.length); i++) {
20425
+ const diff = (right[i] || 0) - (left[i] || 0);
20426
+ if (diff !== 0) return diff;
20427
+ }
20428
+ return b.localeCompare(a);
20429
+ }
20430
+ function nodeRuntimeSupportsWebSocket(nodeExecutable) {
20431
+ try {
20432
+ execFileSync2(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
20433
+ stdio: "ignore",
20434
+ timeout: 3e3
20435
+ });
20436
+ return true;
20437
+ } catch {
20438
+ return false;
20439
+ }
20440
+ }
19909
20441
  function resolveAdhdevMcpEntryPath(explicitPath) {
19910
20442
  const explicit = explicitPath?.trim();
19911
20443
  if (explicit) return normalizeExistingPath(explicit) || explicit;
@@ -19918,7 +20450,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19918
20450
  const addPackagedCandidates = (baseFile) => {
19919
20451
  if (!baseFile) return;
19920
20452
  const realBase = normalizeExistingPath(baseFile) || baseFile;
19921
- const dir = dirname3(realBase);
20453
+ const dir = dirname4(realBase);
19922
20454
  addCandidate(resolve13(dir, "../vendor/mcp-server/index.js"));
19923
20455
  addCandidate(resolve13(dir, "../../vendor/mcp-server/index.js"));
19924
20456
  addCandidate(resolve13(dir, "../../../vendor/mcp-server/index.js"));
@@ -19931,7 +20463,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19931
20463
  if (normalized) return normalized;
19932
20464
  }
19933
20465
  try {
19934
- const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join17(process.cwd(), "adhdev-daemon.js");
20466
+ const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join18(process.cwd(), "adhdev-daemon.js");
19935
20467
  const req = createRequire2(requireBase);
19936
20468
  const resolvedModule = req.resolve("@adhdev/mcp-server");
19937
20469
  return normalizeExistingPath(resolvedModule) || resolvedModule;
@@ -19941,16 +20473,110 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19941
20473
  }
19942
20474
  function normalizeExistingPath(filePath) {
19943
20475
  try {
19944
- if (!existsSync14(filePath)) return null;
20476
+ if (!existsSync15(filePath)) return null;
19945
20477
  return realpathSync2.native(filePath);
19946
20478
  } catch {
19947
20479
  return null;
19948
20480
  }
19949
20481
  }
19950
20482
 
20483
+ // src/mesh/mesh-events.ts
20484
+ init_mesh_config();
20485
+ init_logger();
20486
+ function readNonEmptyString(value) {
20487
+ return typeof value === "string" && value.trim() ? value.trim() : "";
20488
+ }
20489
+ function formatCompletionMetadata(event) {
20490
+ const parts = [
20491
+ readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
20492
+ readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
20493
+ readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
20494
+ ].filter(Boolean);
20495
+ return parts.length > 0 ? ` (${parts.join("; ")})` : "";
20496
+ }
20497
+ function buildMeshSystemMessage(args) {
20498
+ const metadata = formatCompletionMetadata(args.metadataEvent);
20499
+ if (args.event === "agent:generating_completed") {
20500
+ 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.`;
20501
+ }
20502
+ if (args.event === "agent:waiting_approval") {
20503
+ return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
20504
+ }
20505
+ return "";
20506
+ }
20507
+ function injectMeshSystemMessage(components, args) {
20508
+ const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
20509
+ const instState = inst.getState();
20510
+ if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
20511
+ if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
20512
+ return true;
20513
+ });
20514
+ if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
20515
+ const messageText = buildMeshSystemMessage({
20516
+ event: args.event,
20517
+ nodeLabel: args.nodeLabel,
20518
+ metadataEvent: args.metadataEvent
20519
+ });
20520
+ if (!messageText) return { success: false, error: "unsupported mesh event" };
20521
+ for (const coord of coordinatorInstances) {
20522
+ const coordState = coord.getState();
20523
+ LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
20524
+ coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
20525
+ }
20526
+ return { success: true, forwarded: coordinatorInstances.length };
20527
+ }
20528
+ function handleMeshForwardEvent(components, payload) {
20529
+ const eventName = readNonEmptyString(payload.event);
20530
+ if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
20531
+ return { success: false, error: "unsupported mesh event" };
20532
+ }
20533
+ const meshId = readNonEmptyString(payload.meshId);
20534
+ if (!meshId) return { success: false, error: "meshId required" };
20535
+ const nodeId = readNonEmptyString(payload.nodeId);
20536
+ const workspace = readNonEmptyString(payload.workspace);
20537
+ const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
20538
+ return injectMeshSystemMessage(components, {
20539
+ meshId,
20540
+ nodeLabel,
20541
+ event: eventName,
20542
+ metadataEvent: {
20543
+ targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
20544
+ providerType: readNonEmptyString(payload.providerType),
20545
+ providerSessionId: readNonEmptyString(payload.providerSessionId)
20546
+ }
20547
+ });
20548
+ }
20549
+ function setupMeshEventForwarding(components) {
20550
+ components.instanceManager.onEvent((event) => {
20551
+ if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
20552
+ const instanceId = readNonEmptyString(event.instanceId);
20553
+ if (!instanceId) return;
20554
+ const sourceInstance = components.instanceManager.getInstance(instanceId);
20555
+ if (!sourceInstance || sourceInstance.category !== "cli") return;
20556
+ const state = sourceInstance.getState();
20557
+ const workspace = readNonEmptyString(state.workspace);
20558
+ if (!workspace) return;
20559
+ const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
20560
+ const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
20561
+ const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
20562
+ const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
20563
+ if (!meshId) return;
20564
+ const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
20565
+ const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
20566
+ const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
20567
+ injectMeshSystemMessage(components, {
20568
+ meshId,
20569
+ sourceInstanceId: instanceId,
20570
+ nodeLabel,
20571
+ event: event.event,
20572
+ metadataEvent: event
20573
+ });
20574
+ });
20575
+ }
20576
+
19951
20577
  // src/status/snapshot.ts
19952
20578
  init_config();
19953
- import * as os17 from "os";
20579
+ import * as os18 from "os";
19954
20580
  init_terminal_screen();
19955
20581
  init_logger();
19956
20582
  var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
@@ -20005,8 +20631,8 @@ function buildAvailableProviders(providerLoader) {
20005
20631
  }
20006
20632
  function buildMachineInfo(profile = "full") {
20007
20633
  const base = {
20008
- hostname: os17.hostname(),
20009
- platform: os17.platform()
20634
+ hostname: os18.hostname(),
20635
+ platform: os18.platform()
20010
20636
  };
20011
20637
  if (profile === "live") {
20012
20638
  return base;
@@ -20015,23 +20641,23 @@ function buildMachineInfo(profile = "full") {
20015
20641
  const memSnap2 = getHostMemorySnapshot();
20016
20642
  return {
20017
20643
  ...base,
20018
- arch: os17.arch(),
20019
- cpus: os17.cpus().length,
20644
+ arch: os18.arch(),
20645
+ cpus: os18.cpus().length,
20020
20646
  totalMem: memSnap2.totalMem,
20021
- release: os17.release()
20647
+ release: os18.release()
20022
20648
  };
20023
20649
  }
20024
20650
  const memSnap = getHostMemorySnapshot();
20025
20651
  return {
20026
20652
  ...base,
20027
- arch: os17.arch(),
20028
- cpus: os17.cpus().length,
20653
+ arch: os18.arch(),
20654
+ cpus: os18.cpus().length,
20029
20655
  totalMem: memSnap.totalMem,
20030
20656
  freeMem: memSnap.freeMem,
20031
20657
  availableMem: memSnap.availableMem,
20032
- loadavg: os17.loadavg(),
20033
- uptime: os17.uptime(),
20034
- release: os17.release()
20658
+ loadavg: os18.loadavg(),
20659
+ uptime: os18.uptime(),
20660
+ release: os18.release()
20035
20661
  };
20036
20662
  }
20037
20663
  function parseMessageTime(value) {
@@ -20262,17 +20888,17 @@ function buildStatusSnapshot(options) {
20262
20888
  }
20263
20889
 
20264
20890
  // src/commands/upgrade-helper.ts
20265
- import { execFileSync as execFileSync2 } from "child_process";
20891
+ import { execFileSync as execFileSync3 } from "child_process";
20266
20892
  import { spawn as spawn3 } from "child_process";
20267
20893
  import * as fs9 from "fs";
20268
- import * as os18 from "os";
20269
- import * as path20 from "path";
20894
+ import * as os19 from "os";
20895
+ import * as path21 from "path";
20270
20896
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
20271
20897
  function getUpgradeLogPath() {
20272
- const home = os18.homedir();
20273
- const dir = path20.join(home, ".adhdev");
20898
+ const home = os19.homedir();
20899
+ const dir = path21.join(home, ".adhdev");
20274
20900
  fs9.mkdirSync(dir, { recursive: true });
20275
- return path20.join(dir, "daemon-upgrade.log");
20901
+ return path21.join(dir, "daemon-upgrade.log");
20276
20902
  }
20277
20903
  function appendUpgradeLog(message) {
20278
20904
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -20283,14 +20909,14 @@ function appendUpgradeLog(message) {
20283
20909
  }
20284
20910
  }
20285
20911
  function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
20286
- const binDir = path20.dirname(nodeExecutable);
20912
+ const binDir = path21.dirname(nodeExecutable);
20287
20913
  if (platform10 === "win32") {
20288
- const npmCliPath = path20.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
20914
+ const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
20289
20915
  if (fs9.existsSync(npmCliPath)) {
20290
20916
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
20291
20917
  }
20292
20918
  for (const candidate of ["npm.exe", "npm"]) {
20293
- const candidatePath = path20.join(binDir, candidate);
20919
+ const candidatePath = path21.join(binDir, candidate);
20294
20920
  if (fs9.existsSync(candidatePath)) {
20295
20921
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
20296
20922
  }
@@ -20298,7 +20924,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
20298
20924
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
20299
20925
  }
20300
20926
  for (const candidate of ["npm"]) {
20301
- const candidatePath = path20.join(binDir, candidate);
20927
+ const candidatePath = path21.join(binDir, candidate);
20302
20928
  if (fs9.existsSync(candidatePath)) {
20303
20929
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
20304
20930
  }
@@ -20315,13 +20941,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20315
20941
  let currentDir = resolvedPath;
20316
20942
  try {
20317
20943
  if (fs9.statSync(resolvedPath).isFile()) {
20318
- currentDir = path20.dirname(resolvedPath);
20944
+ currentDir = path21.dirname(resolvedPath);
20319
20945
  }
20320
20946
  } catch {
20321
- currentDir = path20.dirname(resolvedPath);
20947
+ currentDir = path21.dirname(resolvedPath);
20322
20948
  }
20323
20949
  while (true) {
20324
- const packageJsonPath = path20.join(currentDir, "package.json");
20950
+ const packageJsonPath = path21.join(currentDir, "package.json");
20325
20951
  try {
20326
20952
  if (fs9.existsSync(packageJsonPath)) {
20327
20953
  const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
@@ -20332,7 +20958,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20332
20958
  }
20333
20959
  } catch {
20334
20960
  }
20335
- const parentDir = path20.dirname(currentDir);
20961
+ const parentDir = path21.dirname(currentDir);
20336
20962
  if (parentDir === currentDir) {
20337
20963
  return null;
20338
20964
  }
@@ -20340,13 +20966,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20340
20966
  }
20341
20967
  }
20342
20968
  function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
20343
- const nodeModulesDir = packageName.startsWith("@") ? path20.dirname(path20.dirname(packageRoot)) : path20.dirname(packageRoot);
20344
- if (path20.basename(nodeModulesDir) !== "node_modules") {
20969
+ const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
20970
+ if (path21.basename(nodeModulesDir) !== "node_modules") {
20345
20971
  return null;
20346
20972
  }
20347
- const maybeLibDir = path20.dirname(nodeModulesDir);
20348
- if (path20.basename(maybeLibDir) === "lib") {
20349
- return path20.dirname(maybeLibDir);
20973
+ const maybeLibDir = path21.dirname(nodeModulesDir);
20974
+ if (path21.basename(maybeLibDir) === "lib") {
20975
+ return path21.dirname(maybeLibDir);
20350
20976
  }
20351
20977
  return maybeLibDir;
20352
20978
  }
@@ -20382,7 +21008,7 @@ function getNpmExecOptions(platform10 = process.platform) {
20382
21008
  }
20383
21009
  function execNpmCommandSync(args, options = {}, surface) {
20384
21010
  const execOptions = surface?.execOptions || getNpmExecOptions();
20385
- return execFileSync2(
21011
+ return execFileSync3(
20386
21012
  surface?.npmExecutable || "npm",
20387
21013
  [...surface?.npmArgsPrefix || [], ...args],
20388
21014
  {
@@ -20395,7 +21021,7 @@ function execNpmCommandSync(args, options = {}, surface) {
20395
21021
  function killPid(pid) {
20396
21022
  try {
20397
21023
  if (process.platform === "win32") {
20398
- execFileSync2("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
21024
+ execFileSync3("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
20399
21025
  } else {
20400
21026
  process.kill(pid, "SIGTERM");
20401
21027
  }
@@ -20407,7 +21033,7 @@ function killPid(pid) {
20407
21033
  function getWindowsProcessCommandLine(pid) {
20408
21034
  const pidFilter = `ProcessId=${pid}`;
20409
21035
  try {
20410
- const psOut = execFileSync2("powershell.exe", [
21036
+ const psOut = execFileSync3("powershell.exe", [
20411
21037
  "-NoProfile",
20412
21038
  "-NonInteractive",
20413
21039
  "-ExecutionPolicy",
@@ -20419,7 +21045,7 @@ function getWindowsProcessCommandLine(pid) {
20419
21045
  } catch {
20420
21046
  }
20421
21047
  try {
20422
- const wmicOut = execFileSync2("wmic", [
21048
+ const wmicOut = execFileSync3("wmic", [
20423
21049
  "process",
20424
21050
  "where",
20425
21051
  pidFilter,
@@ -20435,7 +21061,7 @@ function getProcessCommandLine(pid) {
20435
21061
  if (!Number.isFinite(pid) || pid <= 0) return null;
20436
21062
  if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
20437
21063
  try {
20438
- const text = execFileSync2("ps", ["-o", "command=", "-p", String(pid)], {
21064
+ const text = execFileSync3("ps", ["-o", "command=", "-p", String(pid)], {
20439
21065
  encoding: "utf8",
20440
21066
  timeout: 3e3,
20441
21067
  stdio: ["ignore", "pipe", "ignore"]
@@ -20461,7 +21087,7 @@ async function waitForPidExit(pid, timeoutMs) {
20461
21087
  }
20462
21088
  }
20463
21089
  function stopSessionHostProcesses(appName) {
20464
- const pidFile = path20.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
21090
+ const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
20465
21091
  try {
20466
21092
  if (fs9.existsSync(pidFile)) {
20467
21093
  const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
@@ -20478,7 +21104,7 @@ function stopSessionHostProcesses(appName) {
20478
21104
  }
20479
21105
  }
20480
21106
  function removeDaemonPidFile() {
20481
- const pidFile = path20.join(os18.homedir(), ".adhdev", "daemon.pid");
21107
+ const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
20482
21108
  try {
20483
21109
  fs9.unlinkSync(pidFile);
20484
21110
  } catch {
@@ -20489,7 +21115,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
20489
21115
  const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
20490
21116
  if (!npmRoot) return;
20491
21117
  const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
20492
- const binDir = process.platform === "win32" ? npmPrefix : path20.join(npmPrefix, "bin");
21118
+ const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
20493
21119
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
20494
21120
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
20495
21121
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -20497,25 +21123,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
20497
21123
  }
20498
21124
  if (pkgName.startsWith("@")) {
20499
21125
  const [scope, name] = pkgName.split("/");
20500
- const scopeDir = path20.join(npmRoot, scope);
21126
+ const scopeDir = path21.join(npmRoot, scope);
20501
21127
  if (!fs9.existsSync(scopeDir)) return;
20502
21128
  for (const entry of fs9.readdirSync(scopeDir)) {
20503
21129
  if (!entry.startsWith(`.${name}-`)) continue;
20504
- fs9.rmSync(path20.join(scopeDir, entry), { recursive: true, force: true });
20505
- appendUpgradeLog(`Removed stale scoped staging dir: ${path20.join(scopeDir, entry)}`);
21130
+ fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
21131
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
20506
21132
  }
20507
21133
  } else {
20508
21134
  for (const entry of fs9.readdirSync(npmRoot)) {
20509
21135
  if (!entry.startsWith(`.${pkgName}-`)) continue;
20510
- fs9.rmSync(path20.join(npmRoot, entry), { recursive: true, force: true });
20511
- appendUpgradeLog(`Removed stale staging dir: ${path20.join(npmRoot, entry)}`);
21136
+ fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
21137
+ appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
20512
21138
  }
20513
21139
  }
20514
21140
  if (fs9.existsSync(binDir)) {
20515
21141
  for (const entry of fs9.readdirSync(binDir)) {
20516
21142
  if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
20517
- fs9.rmSync(path20.join(binDir, entry), { recursive: true, force: true });
20518
- appendUpgradeLog(`Removed stale bin staging entry: ${path20.join(binDir, entry)}`);
21143
+ fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
21144
+ appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
20519
21145
  }
20520
21146
  }
20521
21147
  }
@@ -20551,7 +21177,7 @@ async function runDaemonUpgradeHelper(payload) {
20551
21177
  cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
20552
21178
  const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
20553
21179
  appendUpgradeLog(`Installing ${spec}`);
20554
- const installOutput = execFileSync2(
21180
+ const installOutput = execFileSync3(
20555
21181
  installCommand.command,
20556
21182
  installCommand.args,
20557
21183
  {
@@ -20616,6 +21242,56 @@ function normalizeReleaseChannel(value) {
20616
21242
  function resolveUpgradeChannel(args) {
20617
21243
  return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
20618
21244
  }
21245
+ function readProviderPriorityFromPolicy(policy) {
21246
+ const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
21247
+ const raw = record.providerPriority;
21248
+ if (!Array.isArray(raw)) return [];
21249
+ const seen = /* @__PURE__ */ new Set();
21250
+ return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
21251
+ if (seen.has(type)) return false;
21252
+ seen.add(type);
21253
+ return true;
21254
+ });
21255
+ }
21256
+ async function resolveProviderTypeFromPriority(args) {
21257
+ if (!args.providerPriority.length) {
21258
+ return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
21259
+ }
21260
+ const failed = [];
21261
+ for (const requestedType of args.providerPriority) {
21262
+ const normalizedType = args.providerLoader.resolveAlias(requestedType);
21263
+ if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
21264
+ failed.push(`${requestedType}: disabled`);
21265
+ continue;
21266
+ }
21267
+ const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
21268
+ args.providerLoader.setCliDetectionResults([{
21269
+ id: normalizedType,
21270
+ installed: !!detected,
21271
+ path: detected?.path
21272
+ }], false);
21273
+ args.onStatusChange?.();
21274
+ if (detected) return { providerType: normalizedType };
21275
+ failed.push(`${requestedType}: not detected`);
21276
+ }
21277
+ return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
21278
+ }
21279
+ function loadYamlModule() {
21280
+ return yaml;
21281
+ }
21282
+ function getMcpServersKey(format) {
21283
+ return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
21284
+ }
21285
+ function parseMeshCoordinatorMcpConfig(text, format) {
21286
+ if (!text.trim()) return {};
21287
+ if (format === "claude_mcp_json") return JSON.parse(text);
21288
+ const parsed = loadYamlModule().load(text);
21289
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
21290
+ }
21291
+ function serializeMeshCoordinatorMcpConfig(config, format) {
21292
+ if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
21293
+ return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
21294
+ }
20619
21295
  var CHAT_COMMANDS = [
20620
21296
  "send_chat",
20621
21297
  "new_chat",
@@ -20714,6 +21390,154 @@ var DaemonCommandRouter = class {
20714
21390
  constructor(deps) {
20715
21391
  this.deps = deps;
20716
21392
  }
21393
+ getCachedInlineMesh(meshId, inlineMesh) {
21394
+ if (inlineMesh && typeof inlineMesh === "object") {
21395
+ this.inlineMeshCache.set(meshId, inlineMesh);
21396
+ return inlineMesh;
21397
+ }
21398
+ return this.inlineMeshCache.get(meshId);
21399
+ }
21400
+ async getMeshForCommand(meshId, inlineMesh) {
21401
+ try {
21402
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21403
+ const mesh = getMesh3(meshId);
21404
+ if (mesh) return { mesh, inline: false };
21405
+ } catch {
21406
+ }
21407
+ const cached = this.getCachedInlineMesh(meshId, inlineMesh);
21408
+ return cached ? { mesh: cached, inline: true } : null;
21409
+ }
21410
+ updateInlineMeshNode(meshId, mesh, node) {
21411
+ if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
21412
+ const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
21413
+ if (idx >= 0) mesh.nodes[idx] = node;
21414
+ else mesh.nodes.push(node);
21415
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21416
+ this.inlineMeshCache.set(meshId, mesh);
21417
+ }
21418
+ removeInlineMeshNode(meshId, mesh, nodeId) {
21419
+ if (!mesh || !Array.isArray(mesh.nodes)) return false;
21420
+ const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
21421
+ if (idx === -1) return false;
21422
+ mesh.nodes.splice(idx, 1);
21423
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21424
+ this.inlineMeshCache.set(meshId, mesh);
21425
+ return true;
21426
+ }
21427
+ normalizeMeshSessionCleanupMode(value) {
21428
+ return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
21429
+ }
21430
+ sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
21431
+ const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
21432
+ if (!sessionId) return false;
21433
+ if (sessionIds?.size) return sessionIds.has(sessionId);
21434
+ const workspace = typeof node?.workspace === "string" ? node.workspace : "";
21435
+ if (workspace && record?.workspace === workspace) return true;
21436
+ if (record?.meta?.meshNodeId === nodeId) return true;
21437
+ return false;
21438
+ }
21439
+ isCompletedHostedSession(record) {
21440
+ return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
21441
+ }
21442
+ async cleanupMeshSessions(args) {
21443
+ if (args.mode === "preserve") {
21444
+ return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
21445
+ }
21446
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
21447
+ const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
21448
+ const sessions = await this.deps.sessionHostControl.listSessions();
21449
+ const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
21450
+ const hasExplicitSessionIds = !!requestedSessionIds?.size;
21451
+ const stoppedSessionIds = [];
21452
+ const deletedSessionIds = [];
21453
+ const skippedSessionIds = [];
21454
+ const skippedLiveSessionIds = [];
21455
+ const deleteUnsupportedSessionIds = [];
21456
+ const recordsRemainSessionIds = [];
21457
+ const errors = [];
21458
+ const matchedBySurfaceKind = {
21459
+ live_runtime: 0,
21460
+ recovery_snapshot: 0,
21461
+ inactive_record: 0
21462
+ };
21463
+ for (const record of matched) {
21464
+ const surfaceKind = getSessionHostSurfaceKind(record);
21465
+ matchedBySurfaceKind[surfaceKind] += 1;
21466
+ }
21467
+ for (const record of matched) {
21468
+ const sessionId = String(record.sessionId);
21469
+ const completed = this.isCompletedHostedSession(record);
21470
+ const surfaceKind = getSessionHostSurfaceKind(record);
21471
+ const liveRuntime = surfaceKind === "live_runtime";
21472
+ if (!hasExplicitSessionIds && liveRuntime) {
21473
+ skippedSessionIds.push(sessionId);
21474
+ skippedLiveSessionIds.push(sessionId);
21475
+ continue;
21476
+ }
21477
+ try {
21478
+ if (args.mode === "stop") {
21479
+ if (!completed) {
21480
+ if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
21481
+ stoppedSessionIds.push(sessionId);
21482
+ } else {
21483
+ skippedSessionIds.push(sessionId);
21484
+ }
21485
+ continue;
21486
+ }
21487
+ if (args.mode === "delete_stopped") {
21488
+ if (completed) {
21489
+ if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
21490
+ deletedSessionIds.push(sessionId);
21491
+ } else {
21492
+ skippedSessionIds.push(sessionId);
21493
+ }
21494
+ continue;
21495
+ }
21496
+ if (args.mode === "stop_and_delete") {
21497
+ if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
21498
+ deletedSessionIds.push(sessionId);
21499
+ continue;
21500
+ }
21501
+ } catch (e) {
21502
+ const message = e?.message || String(e);
21503
+ if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
21504
+ deleteUnsupportedSessionIds.push(sessionId);
21505
+ recordsRemainSessionIds.push(sessionId);
21506
+ if (args.mode === "stop_and_delete" && !completed) {
21507
+ try {
21508
+ await this.deps.sessionHostControl.stopSession(sessionId);
21509
+ stoppedSessionIds.push(sessionId);
21510
+ } catch (stopError) {
21511
+ errors.push({ sessionId, error: stopError?.message || String(stopError) });
21512
+ continue;
21513
+ }
21514
+ }
21515
+ skippedSessionIds.push(sessionId);
21516
+ continue;
21517
+ }
21518
+ errors.push({ sessionId, error: message });
21519
+ }
21520
+ }
21521
+ const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
21522
+ return {
21523
+ success: errors.length === 0,
21524
+ mode: args.mode,
21525
+ dryRun: args.dryRun === true,
21526
+ matchedCount: matched.length,
21527
+ matchedBySurfaceKind,
21528
+ stoppedSessionIds,
21529
+ deletedSessionIds,
21530
+ skippedSessionIds,
21531
+ skippedLiveSessionIds,
21532
+ ...deleteUnsupported ? {
21533
+ deleteUnsupported: true,
21534
+ effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
21535
+ deleteUnsupportedSessionIds,
21536
+ recordsRemainSessionIds
21537
+ } : {},
21538
+ ...errors.length ? { errors } : {}
21539
+ };
21540
+ }
20717
21541
  async traceSessionHostAction(action, args, run, summarizeResult) {
20718
21542
  const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
20719
21543
  const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
@@ -20833,6 +21657,9 @@ var DaemonCommandRouter = class {
20833
21657
  async executeDaemonCommand(cmd, args) {
20834
21658
  switch (cmd) {
20835
21659
  // ─── CLI / ACP commands ───
21660
+ case "mesh_forward_event": {
21661
+ return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
21662
+ }
20836
21663
  case "launch_cli":
20837
21664
  case "stop_cli":
20838
21665
  case "set_cli_view_mode":
@@ -21377,7 +22204,26 @@ var DaemonCommandRouter = class {
21377
22204
  if (!name) return { success: false, error: "name required" };
21378
22205
  try {
21379
22206
  const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21380
- const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
22207
+ const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
22208
+ return { success: true, mesh };
22209
+ } catch (e) {
22210
+ return { success: false, error: e.message };
22211
+ }
22212
+ }
22213
+ case "update_mesh": {
22214
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22215
+ if (!meshId) return { success: false, error: "meshId required" };
22216
+ try {
22217
+ const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22218
+ const patch = {};
22219
+ if (typeof args?.name === "string") patch.name = args.name;
22220
+ if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
22221
+ if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
22222
+ if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
22223
+ if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
22224
+ const mesh = updateMesh2(meshId, patch);
22225
+ if (!mesh) return { success: false, error: "Mesh not found" };
22226
+ this.inlineMeshCache.set(meshId, mesh);
21381
22227
  return { success: true, mesh };
21382
22228
  } catch (e) {
21383
22229
  return { success: false, error: e.message };
@@ -21401,21 +22247,164 @@ var DaemonCommandRouter = class {
21401
22247
  if (!workspace) return { success: false, error: "workspace required" };
21402
22248
  try {
21403
22249
  const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21404
- const node = addNode3(meshId, { workspace });
22250
+ const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
22251
+ const readOnly = args?.readOnly === true;
22252
+ const policy = {
22253
+ ...readOnly ? { readOnly: true } : {},
22254
+ ...providerPriority.length ? { providerPriority } : {}
22255
+ };
22256
+ const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
21405
22257
  if (!node) return { success: false, error: "Mesh not found" };
21406
22258
  return { success: true, node };
21407
22259
  } catch (e) {
21408
22260
  return { success: false, error: e.message };
21409
22261
  }
21410
22262
  }
22263
+ case "update_mesh_node": {
22264
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22265
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
22266
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
22267
+ try {
22268
+ const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22269
+ const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
22270
+ if (Array.isArray(args?.providerPriority)) {
22271
+ const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
22272
+ delete policy.provider_priority;
22273
+ if (providerPriority.length) {
22274
+ policy.providerPriority = providerPriority;
22275
+ } else {
22276
+ delete policy.providerPriority;
22277
+ }
22278
+ }
22279
+ const node = updateNode2(meshId, nodeId, { policy });
22280
+ if (!node) return { success: false, error: "Mesh node not found" };
22281
+ return { success: true, node };
22282
+ } catch (e) {
22283
+ return { success: false, error: e.message };
22284
+ }
22285
+ }
22286
+ case "cleanup_mesh_sessions": {
22287
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22288
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
22289
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
22290
+ try {
22291
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22292
+ const mesh = meshRecord?.mesh;
22293
+ if (!mesh) return { success: false, error: "Mesh not found" };
22294
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
22295
+ if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
22296
+ const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
22297
+ const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
22298
+ const result = await this.cleanupMeshSessions({
22299
+ meshId,
22300
+ nodeId,
22301
+ node,
22302
+ mode,
22303
+ sessionIds,
22304
+ dryRun: args?.dryRun === true
22305
+ });
22306
+ return result;
22307
+ } catch (e) {
22308
+ return { success: false, error: e.message };
22309
+ }
22310
+ }
21411
22311
  case "remove_mesh_node": {
21412
22312
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21413
22313
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
21414
22314
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
21415
22315
  try {
21416
- const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21417
- const removed = removeNode3(meshId, nodeId);
21418
- return { success: true, removed };
22316
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22317
+ const mesh = meshRecord?.mesh;
22318
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
22319
+ const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
22320
+ args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
22321
+ );
22322
+ let sessionCleanup;
22323
+ if (node && sessionCleanupMode !== "preserve") {
22324
+ sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
22325
+ if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
22326
+ }
22327
+ if (node?.isLocalWorktree && node.workspace) {
22328
+ try {
22329
+ const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
22330
+ const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
22331
+ if (repoRoot) {
22332
+ const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22333
+ await removeWorktree2(repoRoot, node.workspace);
22334
+ }
22335
+ } catch (e) {
22336
+ LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
22337
+ }
22338
+ }
22339
+ let removed = false;
22340
+ if (meshRecord?.inline) {
22341
+ removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
22342
+ } else {
22343
+ const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22344
+ removed = removeNode3(meshId, nodeId);
22345
+ }
22346
+ return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
22347
+ } catch (e) {
22348
+ return { success: false, error: e.message };
22349
+ }
22350
+ }
22351
+ case "clone_mesh_node": {
22352
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22353
+ const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
22354
+ const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
22355
+ const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
22356
+ if (!meshId) return { success: false, error: "meshId required" };
22357
+ if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
22358
+ if (!branch) return { success: false, error: "branch required" };
22359
+ try {
22360
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22361
+ const mesh = meshRecord?.mesh;
22362
+ if (!mesh) return { success: false, error: "Mesh not found" };
22363
+ const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
22364
+ if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
22365
+ const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
22366
+ const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22367
+ const result = await createWorktree2({
22368
+ repoRoot,
22369
+ branch,
22370
+ baseBranch,
22371
+ meshName: mesh.name
22372
+ });
22373
+ let node;
22374
+ if (meshRecord.inline) {
22375
+ const { randomUUID: randomUUID8 } = await import("crypto");
22376
+ node = {
22377
+ id: `node_${randomUUID8().replace(/-/g, "")}`,
22378
+ workspace: result.worktreePath,
22379
+ repoRoot: result.worktreePath,
22380
+ daemonId: sourceNode.daemonId,
22381
+ userOverrides: { ...sourceNode.userOverrides || {} },
22382
+ policy: { ...sourceNode.policy || {} },
22383
+ isLocalWorktree: true,
22384
+ worktreeBranch: result.branch,
22385
+ clonedFromNodeId: sourceNodeId
22386
+ };
22387
+ this.updateInlineMeshNode(meshId, mesh, node);
22388
+ } else {
22389
+ const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22390
+ node = addNode3(meshId, {
22391
+ workspace: result.worktreePath,
22392
+ repoRoot: result.worktreePath,
22393
+ daemonId: sourceNode.daemonId,
22394
+ userOverrides: { ...sourceNode.userOverrides || {} },
22395
+ isLocalWorktree: true,
22396
+ worktreeBranch: result.branch,
22397
+ clonedFromNodeId: sourceNodeId,
22398
+ policy: { ...sourceNode.policy || {} }
22399
+ });
22400
+ if (!node) return { success: false, error: "Failed to register worktree node" };
22401
+ }
22402
+ return {
22403
+ success: true,
22404
+ node,
22405
+ worktreePath: result.worktreePath,
22406
+ branch: result.branch
22407
+ };
21419
22408
  } catch (e) {
21420
22409
  return { success: false, error: e.message };
21421
22410
  }
@@ -21423,7 +22412,7 @@ var DaemonCommandRouter = class {
21423
22412
  // ─── Mesh Coordinator Launch ───
21424
22413
  case "launch_mesh_coordinator": {
21425
22414
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21426
- const cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "claude-cli";
22415
+ let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
21427
22416
  if (!meshId) return { success: false, error: "meshId required" };
21428
22417
  try {
21429
22418
  const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
@@ -21451,9 +22440,29 @@ var DaemonCommandRouter = class {
21451
22440
  }
21452
22441
  const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
21453
22442
  if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
22443
+ if (!cliType) {
22444
+ const resolved = await resolveProviderTypeFromPriority({
22445
+ nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
22446
+ providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
22447
+ providerLoader: this.deps.providerLoader,
22448
+ onStatusChange: this.deps.onStatusChange
22449
+ });
22450
+ if (!resolved.providerType) {
22451
+ return {
22452
+ success: false,
22453
+ code: "mesh_coordinator_provider_priority_unusable",
22454
+ error: resolved.error || "No usable provider found from node providerPriority",
22455
+ meshId,
22456
+ cliType,
22457
+ workspace
22458
+ };
22459
+ }
22460
+ cliType = resolved.providerType;
22461
+ }
21454
22462
  const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
21455
22463
  const coordinatorSetup = resolveMeshCoordinatorSetup({
21456
22464
  provider: providerMeta,
22465
+ cliType,
21457
22466
  meshId,
21458
22467
  workspace
21459
22468
  });
@@ -21478,7 +22487,8 @@ var DaemonCommandRouter = class {
21478
22487
  meshCoordinatorSetup: coordinatorSetup
21479
22488
  };
21480
22489
  }
21481
- if (coordinatorSetup.configFormat !== "claude_mcp_json") {
22490
+ const configFormat = coordinatorSetup.configFormat;
22491
+ if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
21482
22492
  return {
21483
22493
  success: false,
21484
22494
  code: "mesh_coordinator_unsupported",
@@ -21488,17 +22498,34 @@ var DaemonCommandRouter = class {
21488
22498
  workspace
21489
22499
  };
21490
22500
  }
21491
- const { existsSync: existsSync22, readFileSync: readFileSync15, writeFileSync: writeFileSync12, copyFileSync: copyFileSync3 } = await import("fs");
21492
- const mcpConfigPath = coordinatorSetup.configPath;
21493
- const hadExistingMcpConfig = existsSync22(mcpConfigPath);
21494
- let existingMcpConfig = {};
21495
- if (hadExistingMcpConfig) {
21496
- try {
21497
- existingMcpConfig = JSON.parse(readFileSync15(mcpConfigPath, "utf-8"));
21498
- copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
21499
- } catch {
21500
- }
22501
+ let systemPrompt = "";
22502
+ try {
22503
+ systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
22504
+ } catch (error) {
22505
+ const message = error?.message || String(error);
22506
+ LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
22507
+ return {
22508
+ success: false,
22509
+ code: "mesh_coordinator_prompt_failed",
22510
+ error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
22511
+ meshId,
22512
+ cliType,
22513
+ workspace
22514
+ };
21501
22515
  }
22516
+ const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
22517
+ const { dirname: dirname9 } = await import("path");
22518
+ const mcpConfigPath = coordinatorSetup.configPath;
22519
+ const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
22520
+ const returnManualFallback = (message) => ({
22521
+ success: false,
22522
+ code: "mesh_coordinator_manual_mcp_setup_required",
22523
+ error: message,
22524
+ meshId,
22525
+ cliType,
22526
+ workspace,
22527
+ meshCoordinatorSetup: hermesManualFallback
22528
+ });
21502
22529
  const mcpServerEntry = {
21503
22530
  command: coordinatorSetup.mcpServer.command,
21504
22531
  args: coordinatorSetup.mcpServer.args
@@ -21509,24 +22536,55 @@ var DaemonCommandRouter = class {
21509
22536
  ADHDEV_MCP_TRANSPORT: "ipc"
21510
22537
  };
21511
22538
  }
22539
+ try {
22540
+ mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
22541
+ } catch (error) {
22542
+ const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
22543
+ LOG.error("MeshCoordinator", message);
22544
+ if (hermesManualFallback) return returnManualFallback(message);
22545
+ return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
22546
+ }
22547
+ const hadExistingMcpConfig = existsSync23(mcpConfigPath);
22548
+ let existingMcpConfig = {};
22549
+ if (hadExistingMcpConfig) {
22550
+ try {
22551
+ existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
22552
+ copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
22553
+ } catch (error) {
22554
+ LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
22555
+ return {
22556
+ success: false,
22557
+ code: "mesh_coordinator_config_parse_failed",
22558
+ error: `Failed to parse existing MCP config at ${mcpConfigPath}`
22559
+ };
22560
+ }
22561
+ }
22562
+ const mcpServersKey = getMcpServersKey(configFormat);
22563
+ const existingServers = existingMcpConfig[mcpServersKey];
21512
22564
  const mcpConfig = {
21513
22565
  ...existingMcpConfig,
21514
- mcpServers: {
21515
- ...existingMcpConfig.mcpServers || {},
22566
+ [mcpServersKey]: {
22567
+ ...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
21516
22568
  [coordinatorSetup.serverName]: mcpServerEntry
21517
22569
  }
21518
22570
  };
21519
- writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
21520
- LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
21521
- let systemPrompt = "";
21522
22571
  try {
21523
- systemPrompt = buildCoordinatorSystemPrompt2({ mesh });
21524
- } catch {
21525
- 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).`;
22572
+ writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
22573
+ } catch (error) {
22574
+ const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
22575
+ LOG.error("MeshCoordinator", message);
22576
+ if (hermesManualFallback) return returnManualFallback(message);
22577
+ return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
21526
22578
  }
22579
+ LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
21527
22580
  const cliArgs = [];
22581
+ const launchEnv = {};
21528
22582
  if (systemPrompt) {
21529
- cliArgs.push("--append-system-prompt", systemPrompt);
22583
+ if (configFormat === "hermes_config_yaml") {
22584
+ launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
22585
+ } else {
22586
+ cliArgs.push("--append-system-prompt", systemPrompt);
22587
+ }
21530
22588
  }
21531
22589
  if (cliType === "claude-cli") {
21532
22590
  cliArgs.push("--mcp-config", coordinatorSetup.configPath);
@@ -21535,6 +22593,7 @@ var DaemonCommandRouter = class {
21535
22593
  cliType,
21536
22594
  dir: workspace,
21537
22595
  cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
22596
+ env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
21538
22597
  settings: {
21539
22598
  meshCoordinatorFor: meshId
21540
22599
  }
@@ -21714,6 +22773,12 @@ var DaemonStatusReporter = class {
21714
22773
  if (providerType) {
21715
22774
  payload.providerType = providerType;
21716
22775
  }
22776
+ if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
22777
+ payload.providerSessionId = event.providerSessionId.trim();
22778
+ }
22779
+ if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
22780
+ payload.workspaceName = event.workspaceName.trim();
22781
+ }
21717
22782
  if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
21718
22783
  payload.duration = event.duration;
21719
22784
  }
@@ -22961,7 +24026,10 @@ var ProviderInstanceManager = class {
22961
24026
  this.instances.get(id).dispose();
22962
24027
  }
22963
24028
  this.instances.set(id, instance);
22964
- await instance.init(context);
24029
+ await instance.init({
24030
+ ...context,
24031
+ emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
24032
+ });
22965
24033
  }
22966
24034
  /**
22967
24035
  * Instance remove
@@ -23123,6 +24191,17 @@ var ProviderInstanceManager = class {
23123
24191
  onEvent(listener) {
23124
24192
  this.eventListeners.push(listener);
23125
24193
  }
24194
+ emitProviderEvent(providerType, instanceId, event) {
24195
+ const payload = {
24196
+ ...event,
24197
+ providerType,
24198
+ instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
24199
+ targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
24200
+ };
24201
+ for (const listener of this.eventListeners) {
24202
+ listener(payload);
24203
+ }
24204
+ }
23126
24205
  emitPendingEvents(providerType, state, extra = {}) {
23127
24206
  for (const event of state.pendingEvents) {
23128
24207
  for (const listener of this.eventListeners) {
@@ -23195,11 +24274,11 @@ var ProviderInstanceManager = class {
23195
24274
 
23196
24275
  // src/providers/version-archive.ts
23197
24276
  import * as fs11 from "fs";
23198
- import * as path21 from "path";
23199
- import * as os19 from "os";
24277
+ import * as path22 from "path";
24278
+ import * as os20 from "os";
23200
24279
  import { execSync as execSync5 } from "child_process";
23201
24280
  import { platform as platform8 } from "os";
23202
- var ARCHIVE_PATH = path21.join(os19.homedir(), ".adhdev", "version-history.json");
24281
+ var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
23203
24282
  var MAX_ENTRIES_PER_PROVIDER = 20;
23204
24283
  var VersionArchive = class {
23205
24284
  history = {};
@@ -23246,7 +24325,7 @@ var VersionArchive = class {
23246
24325
  }
23247
24326
  save() {
23248
24327
  try {
23249
- fs11.mkdirSync(path21.dirname(ARCHIVE_PATH), { recursive: true });
24328
+ fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
23250
24329
  fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
23251
24330
  } catch {
23252
24331
  }
@@ -23302,8 +24381,8 @@ function getVersion(binary, versionCommand) {
23302
24381
  function checkPathExists2(paths) {
23303
24382
  for (const p of paths) {
23304
24383
  if (p.includes("*")) {
23305
- const home = os19.homedir();
23306
- const resolved = p.replace(/\*/g, home.split(path21.sep).pop() || "");
24384
+ const home = os20.homedir();
24385
+ const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
23307
24386
  if (fs11.existsSync(resolved)) return resolved;
23308
24387
  } else {
23309
24388
  if (fs11.existsSync(p)) return p;
@@ -23313,7 +24392,7 @@ function checkPathExists2(paths) {
23313
24392
  }
23314
24393
  function getMacAppVersion(appPath) {
23315
24394
  if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
23316
- const plistPath = path21.join(appPath, "Contents", "Info.plist");
24395
+ const plistPath = path22.join(appPath, "Contents", "Info.plist");
23317
24396
  if (!fs11.existsSync(plistPath)) return null;
23318
24397
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
23319
24398
  return raw || null;
@@ -23339,7 +24418,7 @@ async function detectAllVersions(loader, archive) {
23339
24418
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
23340
24419
  let resolvedBin = cliBin;
23341
24420
  if (!resolvedBin && appPath && currentOs === "darwin") {
23342
- const bundled = path21.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
24421
+ const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
23343
24422
  if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
23344
24423
  }
23345
24424
  info.installed = !!(appPath || resolvedBin);
@@ -23380,7 +24459,7 @@ async function detectAllVersions(loader, archive) {
23380
24459
  // src/daemon/dev-server.ts
23381
24460
  import * as http2 from "http";
23382
24461
  import * as fs15 from "fs";
23383
- import * as path25 from "path";
24462
+ import * as path26 from "path";
23384
24463
  init_config();
23385
24464
 
23386
24465
  // src/daemon/scaffold-template.ts
@@ -23732,7 +24811,7 @@ init_logger();
23732
24811
  // src/daemon/dev-cdp-handlers.ts
23733
24812
  init_logger();
23734
24813
  import * as fs12 from "fs";
23735
- import * as path22 from "path";
24814
+ import * as path23 from "path";
23736
24815
  async function handleCdpEvaluate(ctx, req, res) {
23737
24816
  const body = await ctx.readBody(req);
23738
24817
  const { expression, timeout, ideType } = body;
@@ -23910,17 +24989,17 @@ async function handleScriptHints(ctx, type, _req, res) {
23910
24989
  return;
23911
24990
  }
23912
24991
  let scriptsPath = "";
23913
- const directScripts = path22.join(dir, "scripts.js");
24992
+ const directScripts = path23.join(dir, "scripts.js");
23914
24993
  if (fs12.existsSync(directScripts)) {
23915
24994
  scriptsPath = directScripts;
23916
24995
  } else {
23917
- const scriptsDir = path22.join(dir, "scripts");
24996
+ const scriptsDir = path23.join(dir, "scripts");
23918
24997
  if (fs12.existsSync(scriptsDir)) {
23919
24998
  const versions = fs12.readdirSync(scriptsDir).filter((d) => {
23920
- return fs12.statSync(path22.join(scriptsDir, d)).isDirectory();
24999
+ return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
23921
25000
  }).sort().reverse();
23922
25001
  for (const ver of versions) {
23923
- const p = path22.join(scriptsDir, ver, "scripts.js");
25002
+ const p = path23.join(scriptsDir, ver, "scripts.js");
23924
25003
  if (fs12.existsSync(p)) {
23925
25004
  scriptsPath = p;
23926
25005
  break;
@@ -24749,7 +25828,7 @@ async function handleDomContext(ctx, type, req, res) {
24749
25828
 
24750
25829
  // src/daemon/dev-cli-debug.ts
24751
25830
  import * as fs13 from "fs";
24752
- import * as path23 from "path";
25831
+ import * as path24 from "path";
24753
25832
  function slugifyFixtureName(value) {
24754
25833
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
24755
25834
  return normalized || `fixture-${Date.now()}`;
@@ -24759,11 +25838,11 @@ function getCliFixtureDir(ctx, type) {
24759
25838
  if (!providerDir) {
24760
25839
  throw new Error(`Provider directory not found for '${type}'`);
24761
25840
  }
24762
- return path23.join(providerDir, "fixtures");
25841
+ return path24.join(providerDir, "fixtures");
24763
25842
  }
24764
25843
  function readCliFixture(ctx, type, name) {
24765
25844
  const fixtureDir = getCliFixtureDir(ctx, type);
24766
- const filePath = path23.join(fixtureDir, `${name}.json`);
25845
+ const filePath = path24.join(fixtureDir, `${name}.json`);
24767
25846
  if (!fs13.existsSync(filePath)) {
24768
25847
  throw new Error(`Fixture not found: ${filePath}`);
24769
25848
  }
@@ -24931,7 +26010,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
24931
26010
  if (!adapter) return null;
24932
26011
  return { target, instance, adapter };
24933
26012
  }
24934
- function sleep(ms) {
26013
+ function sleep2(ms) {
24935
26014
  return new Promise((resolve16) => setTimeout(resolve16, ms));
24936
26015
  }
24937
26016
  async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
@@ -24948,7 +26027,7 @@ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
24948
26027
  return bundle;
24949
26028
  }
24950
26029
  }
24951
- await sleep(100);
26030
+ await sleep2(100);
24952
26031
  }
24953
26032
  return getCliTargetBundle(ctx, type, instanceId);
24954
26033
  }
@@ -25004,7 +26083,7 @@ async function runCliExerciseInternal(ctx, body) {
25004
26083
  const message = String(lastLaunchError.message || "");
25005
26084
  const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
25006
26085
  if (!retryable || attempt === 2) break;
25007
- await sleep(1e3);
26086
+ await sleep2(1e3);
25008
26087
  }
25009
26088
  }
25010
26089
  if (!launched) {
@@ -25067,16 +26146,16 @@ async function runCliExerciseInternal(ctx, body) {
25067
26146
  const modal = debug?.activeModal || trace?.activeModal || null;
25068
26147
  noteStatus(status);
25069
26148
  if (resolveActiveModalIfNeeded(status, modal)) {
25070
- await sleep(150);
26149
+ await sleep2(150);
25071
26150
  continue;
25072
26151
  }
25073
26152
  const startupParseGate = !!debug?.startupParseGate;
25074
26153
  if (status === "idle" && !startupParseGate) break;
25075
- await sleep(150);
26154
+ await sleep2(150);
25076
26155
  }
25077
26156
  ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
25078
26157
  while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
25079
- await sleep(150);
26158
+ await sleep2(150);
25080
26159
  bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
25081
26160
  if (!bundle) {
25082
26161
  throw new Error("CLI instance disappeared during exercise");
@@ -25530,7 +26609,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
25530
26609
  },
25531
26610
  notes: typeof body?.notes === "string" ? body.notes : void 0
25532
26611
  };
25533
- const filePath = path23.join(fixtureDir, `${name}.json`);
26612
+ const filePath = path24.join(fixtureDir, `${name}.json`);
25534
26613
  fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
25535
26614
  ctx.json(res, 200, {
25536
26615
  saved: true,
@@ -25554,7 +26633,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
25554
26633
  return;
25555
26634
  }
25556
26635
  const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
25557
- const fullPath = path23.join(fixtureDir, file);
26636
+ const fullPath = path24.join(fixtureDir, file);
25558
26637
  try {
25559
26638
  const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
25560
26639
  return {
@@ -25690,8 +26769,8 @@ async function handleCliRaw(ctx, req, res) {
25690
26769
 
25691
26770
  // src/daemon/dev-auto-implement.ts
25692
26771
  import * as fs14 from "fs";
25693
- import * as path24 from "path";
25694
- import * as os20 from "os";
26772
+ import * as path25 from "path";
26773
+ import * as os21 from "os";
25695
26774
  function getAutoImplPid(ctx) {
25696
26775
  const pid = ctx.autoImplProcess?.pid;
25697
26776
  return typeof pid === "number" && pid > 0 ? pid : null;
@@ -25740,22 +26819,22 @@ function getLatestScriptVersionDir(scriptsDir) {
25740
26819
  if (!fs14.existsSync(scriptsDir)) return null;
25741
26820
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
25742
26821
  try {
25743
- return fs14.statSync(path24.join(scriptsDir, d)).isDirectory();
26822
+ return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
25744
26823
  } catch {
25745
26824
  return false;
25746
26825
  }
25747
26826
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
25748
26827
  if (versions.length === 0) return null;
25749
- return path24.join(scriptsDir, versions[0]);
26828
+ return path25.join(scriptsDir, versions[0]);
25750
26829
  }
25751
26830
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
25752
- const canonicalUserDir = path24.resolve(ctx.providerLoader.getUserProviderDir(category, type));
25753
- const desiredDir = requestedDir ? path24.resolve(requestedDir) : canonicalUserDir;
25754
- const upstreamRoot = path24.resolve(ctx.providerLoader.getUpstreamDir());
25755
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path24.sep}`)) {
26831
+ const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
26832
+ const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
26833
+ const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
26834
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
25756
26835
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
25757
26836
  }
25758
- if (path24.basename(desiredDir) !== type) {
26837
+ if (path25.basename(desiredDir) !== type) {
25759
26838
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
25760
26839
  }
25761
26840
  const sourceDir = ctx.findProviderDir(type);
@@ -25763,11 +26842,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
25763
26842
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
25764
26843
  }
25765
26844
  if (!fs14.existsSync(desiredDir)) {
25766
- fs14.mkdirSync(path24.dirname(desiredDir), { recursive: true });
26845
+ fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
25767
26846
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
25768
26847
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
25769
26848
  }
25770
- const providerJson = path24.join(desiredDir, "provider.json");
26849
+ const providerJson = path25.join(desiredDir, "provider.json");
25771
26850
  if (!fs14.existsSync(providerJson)) {
25772
26851
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
25773
26852
  }
@@ -25778,13 +26857,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
25778
26857
  const refDir = ctx.findProviderDir(referenceType);
25779
26858
  if (!refDir || !fs14.existsSync(refDir)) return {};
25780
26859
  const referenceScripts = {};
25781
- const scriptsDir = path24.join(refDir, "scripts");
26860
+ const scriptsDir = path25.join(refDir, "scripts");
25782
26861
  const latestDir = getLatestScriptVersionDir(scriptsDir);
25783
26862
  if (!latestDir) return referenceScripts;
25784
26863
  for (const file of fs14.readdirSync(latestDir)) {
25785
26864
  if (!file.endsWith(".js")) continue;
25786
26865
  try {
25787
- referenceScripts[file] = fs14.readFileSync(path24.join(latestDir, file), "utf-8");
26866
+ referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
25788
26867
  } catch {
25789
26868
  }
25790
26869
  }
@@ -25892,9 +26971,9 @@ async function handleAutoImplement(ctx, type, req, res) {
25892
26971
  });
25893
26972
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
25894
26973
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
25895
- const tmpDir = path24.join(os20.tmpdir(), "adhdev-autoimpl");
26974
+ const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
25896
26975
  if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
25897
- const promptFile = path24.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
26976
+ const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
25898
26977
  fs14.writeFileSync(promptFile, prompt, "utf-8");
25899
26978
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
25900
26979
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -26047,7 +27126,7 @@ async function handleAutoImplement(ctx, type, req, res) {
26047
27126
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
26048
27127
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
26049
27128
  let shellCmd;
26050
- const isWin = os20.platform() === "win32";
27129
+ const isWin = os21.platform() === "win32";
26051
27130
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
26052
27131
  const promptMode = autoImpl?.promptMode ?? "stdin";
26053
27132
  const extraArgs = autoImpl?.extraArgs ?? [];
@@ -26086,7 +27165,7 @@ async function handleAutoImplement(ctx, type, req, res) {
26086
27165
  try {
26087
27166
  const pty = __require("node-pty");
26088
27167
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
26089
- const isWin2 = os20.platform() === "win32";
27168
+ const isWin2 = os21.platform() === "win32";
26090
27169
  child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
26091
27170
  name: "xterm-256color",
26092
27171
  cols: 120,
@@ -26326,7 +27405,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26326
27405
  setMode: "set_mode.js"
26327
27406
  };
26328
27407
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26329
- const scriptsDir = path24.join(providerDir, "scripts");
27408
+ const scriptsDir = path25.join(providerDir, "scripts");
26330
27409
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
26331
27410
  if (latestScriptsDir) {
26332
27411
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26337,7 +27416,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26337
27416
  for (const file of fs14.readdirSync(latestScriptsDir)) {
26338
27417
  if (file.endsWith(".js") && targetFileNames.has(file)) {
26339
27418
  try {
26340
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27419
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26341
27420
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26342
27421
  lines.push("```javascript");
26343
27422
  lines.push(content);
@@ -26354,7 +27433,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26354
27433
  lines.push("");
26355
27434
  for (const file of refFiles) {
26356
27435
  try {
26357
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27436
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26358
27437
  lines.push(`### \`${file}\` \u{1F512}`);
26359
27438
  lines.push("```javascript");
26360
27439
  lines.push(content);
@@ -26395,10 +27474,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26395
27474
  lines.push("");
26396
27475
  }
26397
27476
  }
26398
- const docsDir = path24.join(providerDir, "../../docs");
27477
+ const docsDir = path25.join(providerDir, "../../docs");
26399
27478
  const loadGuide = (name) => {
26400
27479
  try {
26401
- const p = path24.join(docsDir, name);
27480
+ const p = path25.join(docsDir, name);
26402
27481
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
26403
27482
  } catch {
26404
27483
  }
@@ -26635,7 +27714,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26635
27714
  parseApproval: "parse_approval.js"
26636
27715
  };
26637
27716
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26638
- const scriptsDir = path24.join(providerDir, "scripts");
27717
+ const scriptsDir = path25.join(providerDir, "scripts");
26639
27718
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
26640
27719
  if (latestScriptsDir) {
26641
27720
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26647,7 +27726,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26647
27726
  if (!file.endsWith(".js")) continue;
26648
27727
  if (!targetFileNames.has(file)) continue;
26649
27728
  try {
26650
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27729
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26651
27730
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26652
27731
  lines.push("```javascript");
26653
27732
  lines.push(content);
@@ -26663,7 +27742,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26663
27742
  lines.push("");
26664
27743
  for (const file of refFiles) {
26665
27744
  try {
26666
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27745
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26667
27746
  lines.push(`### \`${file}\` \u{1F512}`);
26668
27747
  lines.push("```javascript");
26669
27748
  lines.push(content);
@@ -26696,10 +27775,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26696
27775
  lines.push("");
26697
27776
  }
26698
27777
  }
26699
- const docsDir = path24.join(providerDir, "../../docs");
27778
+ const docsDir = path25.join(providerDir, "../../docs");
26700
27779
  const loadGuide = (name) => {
26701
27780
  try {
26702
- const p = path24.join(docsDir, name);
27781
+ const p = path25.join(docsDir, name);
26703
27782
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
26704
27783
  } catch {
26705
27784
  }
@@ -27146,8 +28225,8 @@ var DevServer = class _DevServer {
27146
28225
  }
27147
28226
  getEndpointList() {
27148
28227
  return this.routes.map((r) => {
27149
- const path26 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
27150
- return `${r.method.padEnd(5)} ${path26}`;
28228
+ const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
28229
+ return `${r.method.padEnd(5)} ${path27}`;
27151
28230
  });
27152
28231
  }
27153
28232
  async start(port = DEV_SERVER_PORT) {
@@ -27435,12 +28514,12 @@ var DevServer = class _DevServer {
27435
28514
  // ─── DevConsole SPA ───
27436
28515
  getConsoleDistDir() {
27437
28516
  const candidates = [
27438
- path25.resolve(__dirname, "../../web-devconsole/dist"),
27439
- path25.resolve(__dirname, "../../../web-devconsole/dist"),
27440
- path25.join(process.cwd(), "packages/web-devconsole/dist")
28517
+ path26.resolve(__dirname, "../../web-devconsole/dist"),
28518
+ path26.resolve(__dirname, "../../../web-devconsole/dist"),
28519
+ path26.join(process.cwd(), "packages/web-devconsole/dist")
27441
28520
  ];
27442
28521
  for (const dir of candidates) {
27443
- if (fs15.existsSync(path25.join(dir, "index.html"))) return dir;
28522
+ if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
27444
28523
  }
27445
28524
  return null;
27446
28525
  }
@@ -27450,7 +28529,7 @@ var DevServer = class _DevServer {
27450
28529
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
27451
28530
  return;
27452
28531
  }
27453
- const htmlPath = path25.join(distDir, "index.html");
28532
+ const htmlPath = path26.join(distDir, "index.html");
27454
28533
  try {
27455
28534
  const html = fs15.readFileSync(htmlPath, "utf-8");
27456
28535
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -27475,15 +28554,15 @@ var DevServer = class _DevServer {
27475
28554
  this.json(res, 404, { error: "Not found" });
27476
28555
  return;
27477
28556
  }
27478
- const safePath = path25.normalize(pathname).replace(/^\.\.\//, "");
27479
- const filePath = path25.join(distDir, safePath);
28557
+ const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
28558
+ const filePath = path26.join(distDir, safePath);
27480
28559
  if (!filePath.startsWith(distDir)) {
27481
28560
  this.json(res, 403, { error: "Forbidden" });
27482
28561
  return;
27483
28562
  }
27484
28563
  try {
27485
28564
  const content = fs15.readFileSync(filePath);
27486
- const ext = path25.extname(filePath);
28565
+ const ext = path26.extname(filePath);
27487
28566
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
27488
28567
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
27489
28568
  res.end(content);
@@ -27596,9 +28675,9 @@ var DevServer = class _DevServer {
27596
28675
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
27597
28676
  if (entry.isDirectory()) {
27598
28677
  files.push({ path: rel, size: 0, type: "dir" });
27599
- scan(path25.join(d, entry.name), rel);
28678
+ scan(path26.join(d, entry.name), rel);
27600
28679
  } else {
27601
- const stat2 = fs15.statSync(path25.join(d, entry.name));
28680
+ const stat2 = fs15.statSync(path26.join(d, entry.name));
27602
28681
  files.push({ path: rel, size: stat2.size, type: "file" });
27603
28682
  }
27604
28683
  }
@@ -27621,7 +28700,7 @@ var DevServer = class _DevServer {
27621
28700
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
27622
28701
  return;
27623
28702
  }
27624
- const fullPath = path25.resolve(dir, path25.normalize(filePath));
28703
+ const fullPath = path26.resolve(dir, path26.normalize(filePath));
27625
28704
  if (!fullPath.startsWith(dir)) {
27626
28705
  this.json(res, 403, { error: "Forbidden" });
27627
28706
  return;
@@ -27646,14 +28725,14 @@ var DevServer = class _DevServer {
27646
28725
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
27647
28726
  return;
27648
28727
  }
27649
- const fullPath = path25.resolve(dir, path25.normalize(filePath));
28728
+ const fullPath = path26.resolve(dir, path26.normalize(filePath));
27650
28729
  if (!fullPath.startsWith(dir)) {
27651
28730
  this.json(res, 403, { error: "Forbidden" });
27652
28731
  return;
27653
28732
  }
27654
28733
  try {
27655
28734
  if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
27656
- fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
28735
+ fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
27657
28736
  fs15.writeFileSync(fullPath, content, "utf-8");
27658
28737
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
27659
28738
  this.providerLoader.reload();
@@ -27670,7 +28749,7 @@ var DevServer = class _DevServer {
27670
28749
  return;
27671
28750
  }
27672
28751
  for (const name of ["scripts.js", "provider.json"]) {
27673
- const p = path25.join(dir, name);
28752
+ const p = path26.join(dir, name);
27674
28753
  if (fs15.existsSync(p)) {
27675
28754
  const source = fs15.readFileSync(p, "utf-8");
27676
28755
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -27691,8 +28770,8 @@ var DevServer = class _DevServer {
27691
28770
  this.json(res, 404, { error: `Provider not found: ${type}` });
27692
28771
  return;
27693
28772
  }
27694
- const target = fs15.existsSync(path25.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
27695
- const targetPath = path25.join(dir, target);
28773
+ const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
28774
+ const targetPath = path26.join(dir, target);
27696
28775
  try {
27697
28776
  if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
27698
28777
  fs15.writeFileSync(targetPath, source, "utf-8");
@@ -27839,7 +28918,7 @@ var DevServer = class _DevServer {
27839
28918
  }
27840
28919
  let targetDir;
27841
28920
  targetDir = this.providerLoader.getUserProviderDir(category, type);
27842
- const jsonPath = path25.join(targetDir, "provider.json");
28921
+ const jsonPath = path26.join(targetDir, "provider.json");
27843
28922
  if (fs15.existsSync(jsonPath)) {
27844
28923
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
27845
28924
  return;
@@ -27851,8 +28930,8 @@ var DevServer = class _DevServer {
27851
28930
  const createdFiles = ["provider.json"];
27852
28931
  if (result.files) {
27853
28932
  for (const [relPath, content] of Object.entries(result.files)) {
27854
- const fullPath = path25.join(targetDir, relPath);
27855
- fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
28933
+ const fullPath = path26.join(targetDir, relPath);
28934
+ fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
27856
28935
  fs15.writeFileSync(fullPath, content, "utf-8");
27857
28936
  createdFiles.push(relPath);
27858
28937
  }
@@ -27905,22 +28984,22 @@ var DevServer = class _DevServer {
27905
28984
  if (!fs15.existsSync(scriptsDir)) return null;
27906
28985
  const versions = fs15.readdirSync(scriptsDir).filter((d) => {
27907
28986
  try {
27908
- return fs15.statSync(path25.join(scriptsDir, d)).isDirectory();
28987
+ return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
27909
28988
  } catch {
27910
28989
  return false;
27911
28990
  }
27912
28991
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
27913
28992
  if (versions.length === 0) return null;
27914
- return path25.join(scriptsDir, versions[0]);
28993
+ return path26.join(scriptsDir, versions[0]);
27915
28994
  }
27916
28995
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
27917
- const canonicalUserDir = path25.resolve(this.providerLoader.getUserProviderDir(category, type));
27918
- const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
27919
- const upstreamRoot = path25.resolve(this.providerLoader.getUpstreamDir());
27920
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
28996
+ const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
28997
+ const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
28998
+ const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
28999
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
27921
29000
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
27922
29001
  }
27923
- if (path25.basename(desiredDir) !== type) {
29002
+ if (path26.basename(desiredDir) !== type) {
27924
29003
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
27925
29004
  }
27926
29005
  const sourceDir = this.findProviderDir(type);
@@ -27928,11 +29007,11 @@ var DevServer = class _DevServer {
27928
29007
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
27929
29008
  }
27930
29009
  if (!fs15.existsSync(desiredDir)) {
27931
- fs15.mkdirSync(path25.dirname(desiredDir), { recursive: true });
29010
+ fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
27932
29011
  fs15.cpSync(sourceDir, desiredDir, { recursive: true });
27933
29012
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
27934
29013
  }
27935
- const providerJson = path25.join(desiredDir, "provider.json");
29014
+ const providerJson = path26.join(desiredDir, "provider.json");
27936
29015
  if (!fs15.existsSync(providerJson)) {
27937
29016
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
27938
29017
  }
@@ -27968,7 +29047,7 @@ var DevServer = class _DevServer {
27968
29047
  setMode: "set_mode.js"
27969
29048
  };
27970
29049
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
27971
- const scriptsDir = path25.join(providerDir, "scripts");
29050
+ const scriptsDir = path26.join(providerDir, "scripts");
27972
29051
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
27973
29052
  if (latestScriptsDir) {
27974
29053
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -27979,7 +29058,7 @@ var DevServer = class _DevServer {
27979
29058
  for (const file of fs15.readdirSync(latestScriptsDir)) {
27980
29059
  if (file.endsWith(".js") && targetFileNames.has(file)) {
27981
29060
  try {
27982
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29061
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
27983
29062
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
27984
29063
  lines.push("```javascript");
27985
29064
  lines.push(content);
@@ -27996,7 +29075,7 @@ var DevServer = class _DevServer {
27996
29075
  lines.push("");
27997
29076
  for (const file of refFiles) {
27998
29077
  try {
27999
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29078
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28000
29079
  lines.push(`### \`${file}\` \u{1F512}`);
28001
29080
  lines.push("```javascript");
28002
29081
  lines.push(content);
@@ -28037,10 +29116,10 @@ var DevServer = class _DevServer {
28037
29116
  lines.push("");
28038
29117
  }
28039
29118
  }
28040
- const docsDir = path25.join(providerDir, "../../docs");
29119
+ const docsDir = path26.join(providerDir, "../../docs");
28041
29120
  const loadGuide = (name) => {
28042
29121
  try {
28043
- const p = path25.join(docsDir, name);
29122
+ const p = path26.join(docsDir, name);
28044
29123
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
28045
29124
  } catch {
28046
29125
  }
@@ -28214,7 +29293,7 @@ var DevServer = class _DevServer {
28214
29293
  parseApproval: "parse_approval.js"
28215
29294
  };
28216
29295
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
28217
- const scriptsDir = path25.join(providerDir, "scripts");
29296
+ const scriptsDir = path26.join(providerDir, "scripts");
28218
29297
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
28219
29298
  if (latestScriptsDir) {
28220
29299
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -28226,7 +29305,7 @@ var DevServer = class _DevServer {
28226
29305
  if (!file.endsWith(".js")) continue;
28227
29306
  if (!targetFileNames.has(file)) continue;
28228
29307
  try {
28229
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29308
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28230
29309
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
28231
29310
  lines.push("```javascript");
28232
29311
  lines.push(content);
@@ -28242,7 +29321,7 @@ var DevServer = class _DevServer {
28242
29321
  lines.push("");
28243
29322
  for (const file of refFiles) {
28244
29323
  try {
28245
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29324
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28246
29325
  lines.push(`### \`${file}\` \u{1F512}`);
28247
29326
  lines.push("```javascript");
28248
29327
  lines.push(content);
@@ -28275,10 +29354,10 @@ var DevServer = class _DevServer {
28275
29354
  lines.push("");
28276
29355
  }
28277
29356
  }
28278
- const docsDir = path25.join(providerDir, "../../docs");
29357
+ const docsDir = path26.join(providerDir, "../../docs");
28279
29358
  const loadGuide = (name) => {
28280
29359
  try {
28281
- const p = path25.join(docsDir, name);
29360
+ const p = path26.join(docsDir, name);
28282
29361
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
28283
29362
  } catch {
28284
29363
  }
@@ -28969,29 +30048,58 @@ import {
28969
30048
  } from "@adhdev/session-host-core";
28970
30049
  var STARTUP_TIMEOUT_MS = DEFAULT_SESSION_HOST_READY_TIMEOUT_MS;
28971
30050
  var STARTUP_POLL_MS = 200;
28972
- async function canConnect(endpoint) {
30051
+ var SessionHostCompatibilityError = class extends Error {
30052
+ constructor(message) {
30053
+ super(message);
30054
+ this.name = "SessionHostCompatibilityError";
30055
+ }
30056
+ };
30057
+ function getMissingRequestTypes(diagnostics, requiredRequestTypes) {
30058
+ const supported = new Set(diagnostics?.supportedRequestTypes || []);
30059
+ return requiredRequestTypes.filter((requestType) => !supported.has(requestType));
30060
+ }
30061
+ async function assertRequiredRequestTypes(client, requiredRequestTypes) {
30062
+ if (requiredRequestTypes.length === 0) return;
30063
+ const response = await client.request({
30064
+ type: "get_host_diagnostics",
30065
+ payload: { includeSessions: false }
30066
+ });
30067
+ const missing = getMissingRequestTypes(response.success ? response.result : void 0, requiredRequestTypes);
30068
+ if (missing.length > 0) {
30069
+ const detail = response.success ? "" : ` (${response.error || "capability probe failed"})`;
30070
+ throw new SessionHostCompatibilityError(
30071
+ `Session host does not support required request types: ${missing.join(", ")}${detail}`
30072
+ );
30073
+ }
30074
+ }
30075
+ async function canConnect(endpoint, requiredRequestTypes = []) {
28973
30076
  const client = new SessionHostClient2({ endpoint });
28974
30077
  try {
28975
30078
  await client.connect();
28976
- await client.close();
30079
+ await assertRequiredRequestTypes(client, requiredRequestTypes);
28977
30080
  return true;
28978
- } catch {
30081
+ } catch (error) {
30082
+ if (error instanceof SessionHostCompatibilityError) throw error;
28979
30083
  return false;
30084
+ } finally {
30085
+ await client.close().catch(() => {
30086
+ });
28980
30087
  }
28981
30088
  }
28982
- async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
30089
+ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS, requiredRequestTypes = []) {
28983
30090
  const deadline = Date.now() + timeoutMs;
28984
30091
  while (Date.now() < deadline) {
28985
- if (await canConnect(endpoint)) return;
30092
+ if (await canConnect(endpoint, requiredRequestTypes)) return;
28986
30093
  await new Promise((resolve16) => setTimeout(resolve16, STARTUP_POLL_MS));
28987
30094
  }
28988
30095
  throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
28989
30096
  }
28990
30097
  async function ensureSessionHostReady(options) {
28991
30098
  const endpoint = getDefaultSessionHostEndpoint(options.appName || "adhdev");
28992
- if (await canConnect(endpoint)) return endpoint;
30099
+ const requiredRequestTypes = options.requiredRequestTypes || [];
30100
+ if (await canConnect(endpoint, requiredRequestTypes)) return endpoint;
28993
30101
  options.spawnHost();
28994
- await waitForReady(endpoint, options.timeoutMs);
30102
+ await waitForReady(endpoint, options.timeoutMs, requiredRequestTypes);
28995
30103
  return endpoint;
28996
30104
  }
28997
30105
  async function listHostedCliRuntimes(endpoint) {
@@ -29283,48 +30391,6 @@ var SessionRegistry = class {
29283
30391
  // src/boot/daemon-lifecycle.ts
29284
30392
  init_logger();
29285
30393
  init_config();
29286
-
29287
- // src/mesh/mesh-events.ts
29288
- init_mesh_config();
29289
- init_logger();
29290
- function setupMeshEventForwarding(components) {
29291
- components.instanceManager.onEvent((event) => {
29292
- if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
29293
- const instanceId = event.instanceId;
29294
- if (!instanceId) return;
29295
- const sourceInstance = components.instanceManager.getInstance(instanceId);
29296
- if (!sourceInstance || sourceInstance.category !== "cli") return;
29297
- const state = sourceInstance.getState();
29298
- const workspace = state.workspace;
29299
- if (!workspace) return;
29300
- const mesh = getMeshByRepo(workspace);
29301
- if (!mesh) return;
29302
- const allInstances = components.instanceManager.getByCategory("cli");
29303
- const coordinatorInstances = allInstances.filter((inst) => {
29304
- const instState = inst.getState();
29305
- if (instState.settings?.meshCoordinatorFor !== mesh.id) return false;
29306
- if (instState.instanceId === instanceId) return false;
29307
- return true;
29308
- });
29309
- if (coordinatorInstances.length === 0) return;
29310
- const targetNode = mesh.nodes.find((n) => n.workspace === workspace);
29311
- const nodeLabel = targetNode ? `Node '${targetNode.id}'` : `Agent at ${workspace}`;
29312
- let messageText = "";
29313
- if (event.event === "agent:generating_completed") {
29314
- messageText = `[System] ${nodeLabel} has completed its task and is now idle. You may use mesh_read_chat to review its progress.`;
29315
- } else if (event.event === "agent:waiting_approval") {
29316
- messageText = `[System] ${nodeLabel} is waiting for approval to proceed. You may use mesh_read_chat and mesh_approve to handle it.`;
29317
- }
29318
- if (!messageText) return;
29319
- for (const coord of coordinatorInstances) {
29320
- const coordState = coord.getState();
29321
- LOG.info("MeshEvents", `Forwarding event from ${workspace} to coordinator ${coordState.instanceId}`);
29322
- coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
29323
- }
29324
- });
29325
- }
29326
-
29327
- // src/boot/daemon-lifecycle.ts
29328
30394
  async function initDaemonComponents(config) {
29329
30395
  installGlobalInterceptor();
29330
30396
  const appConfig = loadConfig();
@@ -29630,12 +30696,14 @@ export {
29630
30696
  createGitWorkspaceMonitor,
29631
30697
  createInteractionId,
29632
30698
  createMesh,
30699
+ createWorktree,
29633
30700
  deleteMesh,
29634
30701
  detectAllVersions,
29635
30702
  detectCLIs,
29636
30703
  detectIDEs,
29637
30704
  ensureSessionHostReady,
29638
30705
  execNpmCommandSync,
30706
+ filterUserFacingChatMessages,
29639
30707
  findCdpManager,
29640
30708
  flattenMessageParts,
29641
30709
  forwardAgentStreamsToIdeInstance,
@@ -29677,11 +30745,13 @@ export {
29677
30745
  isSessionHostLiveRuntime,
29678
30746
  isSessionHostRecoverySnapshot,
29679
30747
  isSetupComplete,
30748
+ isUserFacingChatMessage,
29680
30749
  killIdeProcess,
29681
30750
  launchIDE,
29682
30751
  launchWithCdp,
29683
30752
  listHostedCliRuntimes,
29684
30753
  listMeshes,
30754
+ listWorktrees,
29685
30755
  loadConfig,
29686
30756
  loadState,
29687
30757
  logCommand,
@@ -29701,6 +30771,7 @@ export {
29701
30771
  normalizeSessionModalFields,
29702
30772
  parsePorcelainV2Status,
29703
30773
  parseProviderSourceConfigUpdate,
30774
+ parseWorktreeListOutput,
29704
30775
  partitionSessionHostDiagnosticsSessions,
29705
30776
  partitionSessionHostRecords,
29706
30777
  prepareSessionChatTailUpdate,
@@ -29710,6 +30781,7 @@ export {
29710
30781
  recordDebugTrace,
29711
30782
  registerExtensionProviders,
29712
30783
  removeNode,
30784
+ removeWorktree,
29713
30785
  resetConfig,
29714
30786
  resetDebugRuntimeConfig,
29715
30787
  resetState,
@@ -29719,6 +30791,7 @@ export {
29719
30791
  resolveGitRepository,
29720
30792
  resolveSessionHostAppName,
29721
30793
  resolveSessionHostAppNameResolution,
30794
+ resolveWorktreePath,
29722
30795
  runAsyncBatch,
29723
30796
  runGit,
29724
30797
  saveConfig,