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

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 (54) 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 +3 -3
  11. package/dist/index.js +1690 -447
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +1703 -478
  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 +40 -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/chat/subscription-updates.ts +3 -1
  27. package/src/cli-adapters/provider-cli-adapter.ts +28 -7
  28. package/src/cli-adapters/provider-cli-runtime.ts +3 -2
  29. package/src/commands/chat-commands.ts +126 -11
  30. package/src/commands/cli-manager.ts +78 -5
  31. package/src/commands/handler.ts +13 -4
  32. package/src/commands/mesh-coordinator.ts +148 -5
  33. package/src/commands/router.d.ts +1 -0
  34. package/src/commands/router.ts +553 -34
  35. package/src/config/mesh-config.ts +23 -2
  36. package/src/git/git-commands.ts +5 -1
  37. package/src/git/git-types.ts +1 -0
  38. package/src/git/git-worktree.ts +214 -0
  39. package/src/git/index.ts +14 -0
  40. package/src/index.ts +16 -1
  41. package/src/mesh/coordinator-prompt.ts +29 -14
  42. package/src/mesh/mesh-events.ts +109 -43
  43. package/src/providers/chat-message-normalization.ts +241 -0
  44. package/src/providers/cli-provider-instance.d.ts +2 -0
  45. package/src/providers/cli-provider-instance.ts +93 -8
  46. package/src/providers/provider-instance-manager.ts +20 -1
  47. package/src/providers/provider-instance.ts +2 -0
  48. package/src/providers/read-chat-contract.ts +8 -0
  49. package/src/repo-mesh-types.ts +30 -0
  50. package/src/session-host/runtime-support.ts +55 -7
  51. package/src/shared-types.ts +4 -0
  52. package/src/status/builders.ts +17 -12
  53. package/src/status/reporter.ts +6 -0
  54. 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
  }
@@ -7641,6 +7815,20 @@ var StatusMonitor = class {
7641
7815
 
7642
7816
  // src/providers/chat-message-normalization.ts
7643
7817
  var BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
7818
+ var CHAT_MESSAGE_VISIBILITIES = ["user", "debug", "internal", "hidden"];
7819
+ var CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES = ["visible", "chat", "user", "debug", "internal", "hidden"];
7820
+ var CHAT_MESSAGE_AUDIENCES = ["chat", "debug", "trace", "internal"];
7821
+ var CHAT_MESSAGE_SOURCES = [
7822
+ "assistant_text",
7823
+ "tool_call",
7824
+ "terminal_command",
7825
+ "runtime_activity",
7826
+ "runtime_status",
7827
+ "provider_chrome",
7828
+ "control"
7829
+ ];
7830
+ var CHAT_MESSAGE_ACTIVITY_SOURCES = ["tool_call", "terminal_command", "runtime_activity"];
7831
+ var CHAT_MESSAGE_INTERNAL_SOURCES = ["runtime_status", "provider_chrome", "control"];
7644
7832
  var KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
7645
7833
  var CHAT_MESSAGE_KIND_ALIASES = {
7646
7834
  text: "standard",
@@ -7782,6 +7970,169 @@ function normalizeChatMessage(message) {
7782
7970
  function normalizeChatMessages(messages) {
7783
7971
  return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
7784
7972
  }
7973
+ function readMessageMeta(message) {
7974
+ const meta = message?.meta;
7975
+ return meta && typeof meta === "object" && !Array.isArray(meta) ? meta : null;
7976
+ }
7977
+ function readStringField(value) {
7978
+ return typeof value === "string" ? value.trim().toLowerCase() : "";
7979
+ }
7980
+ function readRecordField(message, meta, key) {
7981
+ const record = message;
7982
+ return record[key] ?? meta?.[key];
7983
+ }
7984
+ function readVisibilityField(message, meta) {
7985
+ return readStringField(readRecordField(message, meta, "visibility"));
7986
+ }
7987
+ function readTranscriptVisibilityField(message, meta) {
7988
+ const record = message;
7989
+ return readStringField(record.transcriptVisibility ?? meta?.transcriptVisibility ?? record.visibility ?? meta?.visibility);
7990
+ }
7991
+ var EXPLICIT_HIDDEN_VISIBILITIES = /* @__PURE__ */ new Set(["hidden", "debug", "internal"]);
7992
+ var EXPLICIT_VISIBLE_VISIBILITIES = /* @__PURE__ */ new Set(["visible", "user", "chat"]);
7993
+ var HIDDEN_AUDIENCES = /* @__PURE__ */ new Set(["debug", "trace", "internal"]);
7994
+ var ACTIVITY_SOURCE_SET = new Set(CHAT_MESSAGE_ACTIVITY_SOURCES);
7995
+ var INTERNAL_SOURCE_SET = new Set(CHAT_MESSAGE_INTERNAL_SOURCES);
7996
+ function hasBooleanMarker(message, meta, keys) {
7997
+ const record = message;
7998
+ return keys.some((key) => record[key] === true || meta?.[key] === true);
7999
+ }
8000
+ function isActivityKind(kind) {
8001
+ return kind === "thought" || kind === "tool" || kind === "terminal";
8002
+ }
8003
+ function isOrdinaryVisibleTurn(message, role, kind) {
8004
+ if (role === "user" || role === "human") return kind === "standard" || kind === "";
8005
+ if (role === "assistant") return kind === "standard" || kind === "";
8006
+ return false;
8007
+ }
8008
+ function classifyChatMessageVisibility(message) {
8009
+ if (!message) {
8010
+ return {
8011
+ surface: "internal",
8012
+ isUserFacing: false,
8013
+ isActivityFacing: false,
8014
+ isInternal: true,
8015
+ explicitUserFacing: false,
8016
+ explicitHidden: true,
8017
+ role: "",
8018
+ kind: "standard",
8019
+ visibility: "",
8020
+ transcriptVisibility: "",
8021
+ audience: "",
8022
+ source: ""
8023
+ };
8024
+ }
8025
+ const meta = readMessageMeta(message);
8026
+ const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
8027
+ const kind = resolveChatMessageKind(message);
8028
+ const visibility = readVisibilityField(message, meta);
8029
+ const transcriptVisibility = readTranscriptVisibilityField(message, meta);
8030
+ const audience = readStringField(readRecordField(message, meta, "audience"));
8031
+ const source = readStringField(readRecordField(message, meta, "source"));
8032
+ const explicitHidden = EXPLICIT_HIDDEN_VISIBILITIES.has(visibility) || EXPLICIT_HIDDEN_VISIBILITIES.has(transcriptVisibility) || HIDDEN_AUDIENCES.has(audience) || hasBooleanMarker(message, meta, ["internal", "isInternal", "debug", "statusOnly", "controlOnly"]);
8033
+ const explicitUserFacing = EXPLICIT_VISIBLE_VISIBILITIES.has(visibility) || EXPLICIT_VISIBLE_VISIBILITIES.has(transcriptVisibility) || audience === "chat" || hasBooleanMarker(message, meta, ["userFacing"]);
8034
+ if (explicitHidden) {
8035
+ const activityLike = isActivityKind(kind) || ACTIVITY_SOURCE_SET.has(source);
8036
+ return {
8037
+ surface: activityLike ? "activity" : "internal",
8038
+ isUserFacing: false,
8039
+ isActivityFacing: activityLike,
8040
+ isInternal: !activityLike,
8041
+ explicitUserFacing,
8042
+ explicitHidden,
8043
+ role,
8044
+ kind,
8045
+ visibility,
8046
+ transcriptVisibility,
8047
+ audience,
8048
+ source
8049
+ };
8050
+ }
8051
+ if (explicitUserFacing) {
8052
+ return {
8053
+ surface: "chat",
8054
+ isUserFacing: true,
8055
+ isActivityFacing: false,
8056
+ isInternal: false,
8057
+ explicitUserFacing,
8058
+ explicitHidden,
8059
+ role,
8060
+ kind,
8061
+ visibility,
8062
+ transcriptVisibility,
8063
+ audience,
8064
+ source
8065
+ };
8066
+ }
8067
+ if (INTERNAL_SOURCE_SET.has(source) || role === "system" || kind === "system") {
8068
+ return {
8069
+ surface: "internal",
8070
+ isUserFacing: false,
8071
+ isActivityFacing: false,
8072
+ isInternal: true,
8073
+ explicitUserFacing,
8074
+ explicitHidden,
8075
+ role,
8076
+ kind,
8077
+ visibility,
8078
+ transcriptVisibility,
8079
+ audience,
8080
+ source
8081
+ };
8082
+ }
8083
+ if (ACTIVITY_SOURCE_SET.has(source) || isActivityKind(kind)) {
8084
+ return {
8085
+ surface: "activity",
8086
+ isUserFacing: false,
8087
+ isActivityFacing: true,
8088
+ isInternal: false,
8089
+ explicitUserFacing,
8090
+ explicitHidden,
8091
+ role,
8092
+ kind,
8093
+ visibility,
8094
+ transcriptVisibility,
8095
+ audience,
8096
+ source
8097
+ };
8098
+ }
8099
+ const isUserFacing = isOrdinaryVisibleTurn(message, role, kind);
8100
+ return {
8101
+ surface: isUserFacing ? "chat" : "internal",
8102
+ isUserFacing,
8103
+ isActivityFacing: false,
8104
+ isInternal: !isUserFacing,
8105
+ explicitUserFacing,
8106
+ explicitHidden,
8107
+ role,
8108
+ kind,
8109
+ visibility,
8110
+ transcriptVisibility,
8111
+ audience,
8112
+ source
8113
+ };
8114
+ }
8115
+ function isUserFacingChatMessage(message) {
8116
+ return classifyChatMessageVisibility(message).isUserFacing;
8117
+ }
8118
+ function isActivityChatMessage(message) {
8119
+ return classifyChatMessageVisibility(message).isActivityFacing;
8120
+ }
8121
+ function isInternalChatMessage(message) {
8122
+ return classifyChatMessageVisibility(message).isInternal;
8123
+ }
8124
+ function filterUserFacingChatMessages(messages) {
8125
+ return (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
8126
+ }
8127
+ function filterActivityChatMessages(messages) {
8128
+ return (Array.isArray(messages) ? messages : []).filter((message) => isActivityChatMessage(message));
8129
+ }
8130
+ function filterInternalChatMessages(messages) {
8131
+ return (Array.isArray(messages) ? messages : []).filter((message) => isInternalChatMessage(message));
8132
+ }
8133
+ function filterChatMessagesByVisibility(messages, surface) {
8134
+ return (Array.isArray(messages) ? messages : []).filter((message) => classifyChatMessageVisibility(message).surface === surface);
8135
+ }
7785
8136
 
7786
8137
  // src/providers/control-effects.ts
7787
8138
  function extractProviderControlValues(controls, data) {
@@ -7978,9 +8329,9 @@ ${cleanBody}`;
7978
8329
 
7979
8330
  // src/config/chat-history.ts
7980
8331
  import * as fs3 from "fs";
7981
- import * as path10 from "path";
8332
+ import * as path11 from "path";
7982
8333
  import * as os5 from "os";
7983
- var HISTORY_DIR = path10.join(os5.homedir(), ".adhdev", "history");
8334
+ var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
7984
8335
  var RETAIN_DAYS = 30;
7985
8336
  var SAVED_HISTORY_INDEX_VERSION = 1;
7986
8337
  var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
@@ -8143,7 +8494,7 @@ function extractSavedHistorySessionIdFromFile(file) {
8143
8494
  function buildSavedHistoryFileSignatureMap(dir, files) {
8144
8495
  return new Map(files.map((file) => {
8145
8496
  try {
8146
- const stat2 = fs3.statSync(path10.join(dir, file));
8497
+ const stat2 = fs3.statSync(path11.join(dir, file));
8147
8498
  return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
8148
8499
  } catch {
8149
8500
  return [file, `${file}:missing`];
@@ -8154,7 +8505,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
8154
8505
  return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
8155
8506
  }
8156
8507
  function getSavedHistoryIndexFilePath(dir) {
8157
- return path10.join(dir, SAVED_HISTORY_INDEX_FILE);
8508
+ return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
8158
8509
  }
8159
8510
  function getSavedHistoryIndexLockPath(dir) {
8160
8511
  return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
@@ -8256,7 +8607,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
8256
8607
  }
8257
8608
  for (const file of Array.from(currentEntries.keys())) {
8258
8609
  if (incomingFiles.has(file)) continue;
8259
- if (!fs3.existsSync(path10.join(dir, file))) {
8610
+ if (!fs3.existsSync(path11.join(dir, file))) {
8260
8611
  currentEntries.delete(file);
8261
8612
  }
8262
8613
  }
@@ -8282,7 +8633,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
8282
8633
  const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
8283
8634
  const files = listHistoryFiles(dir);
8284
8635
  for (const file of files) {
8285
- const stat2 = fs3.statSync(path10.join(dir, file));
8636
+ const stat2 = fs3.statSync(path11.join(dir, file));
8286
8637
  if (stat2.mtimeMs > indexStat.mtimeMs) return true;
8287
8638
  }
8288
8639
  return false;
@@ -8292,14 +8643,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
8292
8643
  }
8293
8644
  function buildSavedHistoryFileSignature(dir, file) {
8294
8645
  try {
8295
- const stat2 = fs3.statSync(path10.join(dir, file));
8646
+ const stat2 = fs3.statSync(path11.join(dir, file));
8296
8647
  return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
8297
8648
  } catch {
8298
8649
  return `${file}:missing`;
8299
8650
  }
8300
8651
  }
8301
8652
  function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
8302
- const filePath = path10.join(dir, file);
8653
+ const filePath = path11.join(dir, file);
8303
8654
  const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
8304
8655
  const currentEntry = entries.get(file) || null;
8305
8656
  const nextSummary = updater(currentEntry?.summary || null);
@@ -8372,7 +8723,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
8372
8723
  function computeSavedHistoryFileSummary(dir, file) {
8373
8724
  const historySessionId = extractSavedHistorySessionIdFromFile(file);
8374
8725
  if (!historySessionId) return null;
8375
- const filePath = path10.join(dir, file);
8726
+ const filePath = path11.join(dir, file);
8376
8727
  const content = fs3.readFileSync(filePath, "utf-8");
8377
8728
  const lines = content.split("\n").filter(Boolean);
8378
8729
  let messageCount = 0;
@@ -8459,7 +8810,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
8459
8810
  const summaryBySessionId = /* @__PURE__ */ new Map();
8460
8811
  const nextPersistedEntries = /* @__PURE__ */ new Map();
8461
8812
  for (const file of files.slice().sort()) {
8462
- const filePath = path10.join(dir, file);
8813
+ const filePath = path11.join(dir, file);
8463
8814
  const signature = fileSignatures.get(file) || `${file}:missing`;
8464
8815
  const cached = savedHistoryFileSummaryCache.get(filePath);
8465
8816
  const persisted = persistedEntries.get(file);
@@ -8579,12 +8930,12 @@ var ChatHistoryWriter = class {
8579
8930
  });
8580
8931
  }
8581
8932
  if (newMessages.length === 0) return;
8582
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8933
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8583
8934
  fs3.mkdirSync(dir, { recursive: true });
8584
8935
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8585
8936
  const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
8586
8937
  const fileName = `${filePrefix}${date}.jsonl`;
8587
- const filePath = path10.join(dir, fileName);
8938
+ const filePath = path11.join(dir, fileName);
8588
8939
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
8589
8940
  fs3.appendFileSync(filePath, lines, "utf-8");
8590
8941
  updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
@@ -8675,11 +9026,11 @@ var ChatHistoryWriter = class {
8675
9026
  const ws = String(workspace || "").trim();
8676
9027
  if (!id || !ws) return;
8677
9028
  try {
8678
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
9029
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8679
9030
  fs3.mkdirSync(dir, { recursive: true });
8680
9031
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8681
9032
  const fileName = `${this.sanitize(id)}_${date}.jsonl`;
8682
- const filePath = path10.join(dir, fileName);
9033
+ const filePath = path11.join(dir, fileName);
8683
9034
  const record = {
8684
9035
  ts: (/* @__PURE__ */ new Date()).toISOString(),
8685
9036
  receivedAt: Date.now(),
@@ -8725,14 +9076,14 @@ var ChatHistoryWriter = class {
8725
9076
  this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
8726
9077
  this.lastSeenCounts.delete(fromDedupKey);
8727
9078
  }
8728
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
9079
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8729
9080
  if (!fs3.existsSync(dir)) return;
8730
9081
  const fromPrefix = `${this.sanitize(fromId)}_`;
8731
9082
  const toPrefix = `${this.sanitize(toId)}_`;
8732
9083
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
8733
9084
  for (const file of files) {
8734
- const sourcePath = path10.join(dir, file);
8735
- const targetPath = path10.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
9085
+ const sourcePath = path11.join(dir, file);
9086
+ const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
8736
9087
  const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
8737
9088
  const rewritten = sourceLines.map((line) => {
8738
9089
  try {
@@ -8766,13 +9117,13 @@ var ChatHistoryWriter = class {
8766
9117
  const sessionId = String(historySessionId || "").trim();
8767
9118
  if (!sessionId) return;
8768
9119
  try {
8769
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
9120
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8770
9121
  if (!fs3.existsSync(dir)) return;
8771
9122
  const prefix = `${this.sanitize(sessionId)}_`;
8772
9123
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
8773
9124
  const seen = /* @__PURE__ */ new Set();
8774
9125
  for (const file of files) {
8775
- const filePath = path10.join(dir, file);
9126
+ const filePath = path11.join(dir, file);
8776
9127
  const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8777
9128
  const next = [];
8778
9129
  for (const line of lines) {
@@ -8826,11 +9177,11 @@ var ChatHistoryWriter = class {
8826
9177
  const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
8827
9178
  const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
8828
9179
  for (const dir of agentDirs) {
8829
- const dirPath = path10.join(HISTORY_DIR, dir.name);
9180
+ const dirPath = path11.join(HISTORY_DIR, dir.name);
8830
9181
  const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
8831
9182
  let removedAny = false;
8832
9183
  for (const file of files) {
8833
- const filePath = path10.join(dirPath, file);
9184
+ const filePath = path11.join(dirPath, file);
8834
9185
  const stat2 = fs3.statSync(filePath);
8835
9186
  if (stat2.mtimeMs < cutoff) {
8836
9187
  fs3.unlinkSync(filePath);
@@ -8880,13 +9231,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
8880
9231
  function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
8881
9232
  try {
8882
9233
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
8883
- const dir = path10.join(HISTORY_DIR, sanitized);
9234
+ const dir = path11.join(HISTORY_DIR, sanitized);
8884
9235
  if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
8885
9236
  const files = listHistoryFiles(dir, historySessionId);
8886
9237
  const allMessages = [];
8887
9238
  const seen = /* @__PURE__ */ new Set();
8888
9239
  for (const file of files) {
8889
- const filePath = path10.join(dir, file);
9240
+ const filePath = path11.join(dir, file);
8890
9241
  const content = fs3.readFileSync(filePath, "utf-8");
8891
9242
  const lines = content.trim().split("\n").filter(Boolean);
8892
9243
  for (let i = 0; i < lines.length; i++) {
@@ -8910,7 +9261,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
8910
9261
  function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
8911
9262
  try {
8912
9263
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
8913
- const dir = path10.join(HISTORY_DIR, sanitized);
9264
+ const dir = path11.join(HISTORY_DIR, sanitized);
8914
9265
  if (!fs3.existsSync(dir)) {
8915
9266
  savedHistorySessionCache.delete(sanitized);
8916
9267
  return { sessions: [], hasMore: false };
@@ -8971,11 +9322,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
8971
9322
  }
8972
9323
  function readExistingSessionStartRecord(agentType, historySessionId) {
8973
9324
  try {
8974
- const dir = path10.join(HISTORY_DIR, agentType);
9325
+ const dir = path11.join(HISTORY_DIR, agentType);
8975
9326
  if (!fs3.existsSync(dir)) return null;
8976
9327
  const files = listHistoryFiles(dir, historySessionId).sort();
8977
9328
  for (const file of files) {
8978
- const lines = fs3.readFileSync(path10.join(dir, file), "utf-8").split("\n").filter(Boolean);
9329
+ const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
8979
9330
  for (const line of lines) {
8980
9331
  try {
8981
9332
  const parsed = JSON.parse(line);
@@ -8995,16 +9346,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
8995
9346
  function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
8996
9347
  if (records.length === 0) return false;
8997
9348
  try {
8998
- const dir = path10.join(HISTORY_DIR, agentType);
9349
+ const dir = path11.join(HISTORY_DIR, agentType);
8999
9350
  fs3.mkdirSync(dir, { recursive: true });
9000
9351
  const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
9001
9352
  for (const file of fs3.readdirSync(dir)) {
9002
9353
  if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
9003
- fs3.unlinkSync(path10.join(dir, file));
9354
+ fs3.unlinkSync(path11.join(dir, file));
9004
9355
  }
9005
9356
  }
9006
9357
  const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
9007
- const filePath = path10.join(dir, `${prefix}${targetDate}.jsonl`);
9358
+ const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
9008
9359
  fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
9009
9360
  `, "utf-8");
9010
9361
  invalidatePersistedSavedHistoryIndex(agentType, dir);
@@ -9754,6 +10105,14 @@ function validateMessage(message, source, index) {
9754
10105
  if (typeof message.senderName === "string") normalized.senderName = message.senderName;
9755
10106
  if (typeof message._type === "string") normalized._type = message._type;
9756
10107
  if (typeof message._sub === "string") normalized._sub = message._sub;
10108
+ if (typeof message.visibility === "string") normalized.visibility = message.visibility;
10109
+ if (typeof message.transcriptVisibility === "string") normalized.transcriptVisibility = message.transcriptVisibility;
10110
+ if (typeof message.audience === "string") normalized.audience = message.audience;
10111
+ if (typeof message.source === "string") normalized.source = message.source;
10112
+ if (typeof message.userFacing === "boolean") normalized.userFacing = message.userFacing;
10113
+ if (typeof message.internal === "boolean") normalized.internal = message.internal;
10114
+ if (typeof message.isInternal === "boolean") normalized.isInternal = message.isInternal;
10115
+ if (typeof message.debug === "boolean") normalized.debug = message.debug;
9757
10116
  return normalized;
9758
10117
  }
9759
10118
  function validateModal(activeModal, status, source) {
@@ -10999,6 +11358,14 @@ function getActiveChatOptions(profile) {
10999
11358
  if (profile === "full") return {};
11000
11359
  return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
11001
11360
  }
11361
+ function resolveSessionStatus(activeChat, providerStatus) {
11362
+ const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
11363
+ const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
11364
+ if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
11365
+ if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
11366
+ if (topLevelStatus !== "idle") return topLevelStatus;
11367
+ return chatStatus;
11368
+ }
11002
11369
  function shouldIncludeSessionControls(profile) {
11003
11370
  return profile !== "live";
11004
11371
  }
@@ -11077,9 +11444,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
11077
11444
  providerName: state.name,
11078
11445
  kind: "workspace",
11079
11446
  transport: "cdp-page",
11080
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11081
- activeModal: activeChat?.activeModal || null
11082
- }),
11447
+ status: resolveSessionStatus(activeChat, state.status),
11083
11448
  title,
11084
11449
  workspace,
11085
11450
  ...git && { git },
@@ -11114,9 +11479,7 @@ function buildExtensionAgentSession(parent, ext, options) {
11114
11479
  providerSessionId: ext.providerSessionId,
11115
11480
  kind: "agent",
11116
11481
  transport: "cdp-webview",
11117
- status: normalizeManagedStatus(activeChat?.status || ext.status, {
11118
- activeModal: activeChat?.activeModal || null
11119
- }),
11482
+ status: resolveSessionStatus(activeChat, ext.status),
11120
11483
  title: activeChat?.title || ext.name,
11121
11484
  workspace,
11122
11485
  ...git && { git },
@@ -11166,9 +11529,7 @@ function buildCliSession(state, options) {
11166
11529
  providerSessionId: state.providerSessionId,
11167
11530
  kind: "agent",
11168
11531
  transport: "pty",
11169
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11170
- activeModal: activeChat?.activeModal || null
11171
- }),
11532
+ status: resolveSessionStatus(activeChat, state.status),
11172
11533
  title: activeChat?.title || state.name,
11173
11534
  workspace,
11174
11535
  ...git && { git },
@@ -11216,9 +11577,7 @@ function buildAcpSession(state, options) {
11216
11577
  providerName: state.name,
11217
11578
  kind: "agent",
11218
11579
  transport: "acp",
11219
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11220
- activeModal: activeChat?.activeModal || null
11221
- }),
11580
+ status: resolveSessionStatus(activeChat, state.status),
11222
11581
  title: activeChat?.title || state.name,
11223
11582
  workspace,
11224
11583
  ...git && { git },
@@ -11341,7 +11700,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
11341
11700
  // src/commands/chat-commands.ts
11342
11701
  import * as fs4 from "fs";
11343
11702
  import * as os6 from "os";
11344
- import * as path11 from "path";
11703
+ import * as path12 from "path";
11345
11704
  import { randomUUID as randomUUID5 } from "crypto";
11346
11705
 
11347
11706
  // src/providers/provider-input-support.ts
@@ -11544,6 +11903,7 @@ function buildSessionModalDeliverySignature(payload) {
11544
11903
  // src/commands/chat-commands.ts
11545
11904
  var RECENT_SEND_WINDOW_MS = 1200;
11546
11905
  var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
11906
+ var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
11547
11907
  var recentSendByTarget = /* @__PURE__ */ new Map();
11548
11908
  function getCurrentProviderType(h, fallback = "") {
11549
11909
  return h.currentSession?.providerType || h.currentProviderType || fallback;
@@ -11596,6 +11956,16 @@ function buildSendInputSignature(input) {
11596
11956
  function getSendChatInputEnvelope(args) {
11597
11957
  return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
11598
11958
  }
11959
+ function sleep(ms) {
11960
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
11961
+ }
11962
+ async function waitOnceForFreshHermesCliStart(adapter, log) {
11963
+ if (adapter.cliType !== "hermes-cli") return;
11964
+ const status = typeof adapter.getStatus === "function" ? adapter.getStatus()?.status : void 0;
11965
+ if (status !== "starting") return;
11966
+ log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
11967
+ await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
11968
+ }
11599
11969
  function getHistorySessionId(h, args) {
11600
11970
  const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
11601
11971
  if (explicit) return explicit;
@@ -11650,7 +12020,7 @@ function normalizeReadChatTailLimit(args) {
11650
12020
  }
11651
12021
  function normalizeReadChatMessages(payload) {
11652
12022
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
11653
- return messages;
12023
+ return normalizeChatMessages(messages);
11654
12024
  }
11655
12025
  function deriveHistoryDedupKey(message) {
11656
12026
  const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
@@ -11704,6 +12074,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
11704
12074
  return raw;
11705
12075
  }
11706
12076
  }
12077
+ function isGeneratingLikeStatus(status) {
12078
+ return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
12079
+ }
12080
+ function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
12081
+ if (!isGeneratingLikeStatus(parsedStatus)) return false;
12082
+ if (hasNonEmptyModalButtons(activeModal)) return false;
12083
+ const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
12084
+ if (adapterRawStatus !== "idle") return false;
12085
+ if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
12086
+ return true;
12087
+ }
12088
+ function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
12089
+ if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
12090
+ return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
12091
+ }
12092
+ function finalizeStreamingMessagesWhenIdle(messages, status) {
12093
+ if (status !== "idle") return messages;
12094
+ return messages.map((message) => {
12095
+ const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
12096
+ const hasStreamingMeta = meta?.streaming === true;
12097
+ if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
12098
+ return {
12099
+ ...message,
12100
+ ...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
12101
+ ...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
12102
+ };
12103
+ });
12104
+ }
11707
12105
  function buildReadChatCommandResult(payload, args) {
11708
12106
  let validatedPayload;
11709
12107
  const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
@@ -11716,13 +12114,22 @@ function buildReadChatCommandResult(payload, args) {
11716
12114
  return { success: false, error: error?.message || String(error) };
11717
12115
  }
11718
12116
  const messages = normalizeReadChatMessages(validatedPayload);
11719
- const sync = buildFullTail(messages, normalizeReadChatTailLimit(args));
12117
+ const visibleMessages = filterUserFacingChatMessages(messages);
12118
+ const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
12119
+ const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
12120
+ const returnedDebugReadChat = debugReadChat ? {
12121
+ ...debugReadChat,
12122
+ fullMsgCount: typeof debugReadChat.fullMsgCount === "number" ? debugReadChat.fullMsgCount : messages.length,
12123
+ visibleMsgCount: visibleMessages.length,
12124
+ hiddenMsgCount,
12125
+ returnedMsgCount: sync.messages.length
12126
+ } : void 0;
11720
12127
  return {
11721
12128
  success: true,
11722
12129
  ...validatedPayload,
11723
12130
  messages: sync.messages,
11724
12131
  totalMessages: sync.totalMessages,
11725
- ...debugReadChat ? { debugReadChat } : {}
12132
+ ...returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}
11726
12133
  };
11727
12134
  }
11728
12135
  var DEFAULT_DEBUG_SANITIZE_OPTIONS = {
@@ -11852,7 +12259,7 @@ function buildDebugBundleText(bundle) {
11852
12259
  }
11853
12260
  function getChatDebugBundleDir() {
11854
12261
  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");
12262
+ return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
11856
12263
  }
11857
12264
  function safeBundleIdSegment(value, fallback) {
11858
12265
  const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
@@ -11868,6 +12275,14 @@ function buildChatDebugBundleSummary(bundle) {
11868
12275
  const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
11869
12276
  const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
11870
12277
  const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
12278
+ const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
12279
+ const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
12280
+ const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
12281
+ const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
12282
+ const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
12283
+ const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
12284
+ const cliStatus = typeof cli?.status === "string" ? cli.status : "";
12285
+ const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
11871
12286
  return {
11872
12287
  createdAt: bundle.createdAt,
11873
12288
  targetSessionId: target.targetSessionId,
@@ -11876,8 +12291,22 @@ function buildChatDebugBundleSummary(bundle) {
11876
12291
  readChatSuccess: readChat.success,
11877
12292
  readChatStatus: readChat.status,
11878
12293
  readChatTotalMessages: readChat.totalMessages,
12294
+ readChatReturnedMessages,
11879
12295
  cliStatus: cli?.status,
12296
+ cliParsedStatus: cliParsedStatus || void 0,
11880
12297
  cliMessageCount: cli?.messageCount,
12298
+ cliParsedMessageCount,
12299
+ cliPartialResponseChars: cliPartialResponse.length,
12300
+ parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
12301
+ parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
12302
+ readChatDebug: Object.keys(debugReadChat).length ? {
12303
+ adapterStatus: debugReadChat.adapterStatus,
12304
+ parsedStatus: debugReadChat.parsedStatus,
12305
+ returnedStatus: debugReadChat.returnedStatus,
12306
+ parsedMsgCount: debugReadChat.parsedMsgCount,
12307
+ returnedMsgCount: debugReadChat.returnedMsgCount,
12308
+ shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
12309
+ } : void 0,
11881
12310
  hasFrontendSnapshot: !!frontend
11882
12311
  };
11883
12312
  }
@@ -11885,7 +12314,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
11885
12314
  const bundleId = createChatDebugBundleId(targetSessionId);
11886
12315
  const dir = getChatDebugBundleDir();
11887
12316
  fs4.mkdirSync(dir, { recursive: true });
11888
- const savedPath = path11.join(dir, `${bundleId}.json`);
12317
+ const savedPath = path12.join(dir, `${bundleId}.json`);
11889
12318
  const json = `${JSON.stringify(bundle, null, 2)}
11890
12319
  `;
11891
12320
  fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
@@ -12115,7 +12544,7 @@ async function handleChatHistory(h, args) {
12115
12544
  }
12116
12545
  }
12117
12546
  async function handleReadChat(h, args) {
12118
- const provider = h.getProvider(args?.agentType);
12547
+ const provider = h.getProvider(args?.agentType || args?.providerType);
12119
12548
  const transport = getTargetTransport(h, provider);
12120
12549
  const historySessionId = getHistorySessionId(h, args);
12121
12550
  const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
@@ -12142,10 +12571,13 @@ async function handleReadChat(h, args) {
12142
12571
  const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
12143
12572
  const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
12144
12573
  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}`);
12574
+ const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
12575
+ const runtimeMessageMerger = getTargetInstance(h, args);
12576
+ const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
12577
+ const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
12578
+ 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
12579
  return buildReadChatCommandResult({
12148
- messages: parsedRecord.messages,
12580
+ messages: returnedMessages,
12149
12581
  status: returnedStatus,
12150
12582
  activeModal,
12151
12583
  debugReadChat: {
@@ -12156,7 +12588,7 @@ async function handleReadChat(h, args) {
12156
12588
  returnedStatus: String(returnedStatus || ""),
12157
12589
  shouldPreferAdapterMessages: false,
12158
12590
  parsedMsgCount: parsedRecord.messages.length,
12159
- returnedMsgCount: parsedRecord.messages.length
12591
+ returnedMsgCount: returnedMessages.length
12160
12592
  },
12161
12593
  ...title ? { title } : {},
12162
12594
  ...providerSessionId ? { providerSessionId } : {},
@@ -12402,6 +12834,7 @@ async function handleSendChat(h, args) {
12402
12834
  try {
12403
12835
  assertTextOnlyInput(provider, input);
12404
12836
  if (!text) return { success: false, error: "text required for PTY send" };
12837
+ await waitOnceForFreshHermesCliStart(adapter, _log);
12405
12838
  await adapter.sendMessage(text);
12406
12839
  return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
12407
12840
  } catch (e) {
@@ -12901,9 +13334,17 @@ async function handleResolveAction(h, args) {
12901
13334
  const targetState = targetInstance?.getState?.();
12902
13335
  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
13336
  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"}`);
13337
+ const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
13338
+ try {
13339
+ return parseMaybeJson(adapter.getScriptParsedStatus());
13340
+ } catch {
13341
+ return null;
13342
+ }
13343
+ })() : null;
13344
+ 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;
13345
+ const effectiveModal = statusModal || surfacedModal || parsedModal;
13346
+ const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
13347
+ 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
13348
  if (!effectiveModal) {
12908
13349
  return { success: false, error: "Not in approval state" };
12909
13350
  }
@@ -13029,7 +13470,7 @@ async function handleResolveAction(h, args) {
13029
13470
 
13030
13471
  // src/commands/cdp-commands.ts
13031
13472
  import * as fs5 from "fs";
13032
- import * as path12 from "path";
13473
+ import * as path13 from "path";
13033
13474
  import * as os7 from "os";
13034
13475
  var KEY_TO_VK = {
13035
13476
  Backspace: 8,
@@ -13286,25 +13727,25 @@ function resolveSafePath(requestedPath) {
13286
13727
  const inputPath = rawPath || ".";
13287
13728
  const home = os7.homedir();
13288
13729
  if (inputPath.startsWith("~")) {
13289
- return path12.resolve(path12.join(home, inputPath.slice(1)));
13730
+ return path13.resolve(path13.join(home, inputPath.slice(1)));
13290
13731
  }
13291
13732
  if (process.platform === "win32") {
13292
13733
  const normalized = normalizeWindowsRequestedPath(inputPath);
13293
- if (path12.win32.isAbsolute(normalized)) {
13294
- return path12.win32.normalize(normalized);
13734
+ if (path13.win32.isAbsolute(normalized)) {
13735
+ return path13.win32.normalize(normalized);
13295
13736
  }
13296
- return path12.win32.resolve(normalized);
13737
+ return path13.win32.resolve(normalized);
13297
13738
  }
13298
- if (path12.isAbsolute(inputPath)) {
13299
- return path12.normalize(inputPath);
13739
+ if (path13.isAbsolute(inputPath)) {
13740
+ return path13.normalize(inputPath);
13300
13741
  }
13301
- return path12.resolve(inputPath);
13742
+ return path13.resolve(inputPath);
13302
13743
  }
13303
13744
  function listDirectoryEntriesSafe(dirPath) {
13304
13745
  const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
13305
13746
  const files = [];
13306
13747
  for (const entry of entries) {
13307
- const entryPath = path12.join(dirPath, entry.name);
13748
+ const entryPath = path13.join(dirPath, entry.name);
13308
13749
  try {
13309
13750
  if (entry.isDirectory()) {
13310
13751
  files.push({ name: entry.name, type: "directory" });
@@ -13358,7 +13799,7 @@ async function handleFileRead(h, args) {
13358
13799
  async function handleFileWrite(h, args) {
13359
13800
  try {
13360
13801
  const filePath = resolveSafePath(args?.path);
13361
- fs5.mkdirSync(path12.dirname(filePath), { recursive: true });
13802
+ fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
13362
13803
  fs5.writeFileSync(filePath, args?.content || "", "utf-8");
13363
13804
  return { success: true, path: filePath };
13364
13805
  } catch (e) {
@@ -14142,9 +14583,11 @@ var DaemonCommandHandler = class {
14142
14583
  }
14143
14584
  const sessionLookupFailed = !!targetSessionId && !session;
14144
14585
  const managerKey = this.extractIdeType(args, sessionLookupFailed);
14145
- let providerType;
14586
+ let providerType = args?.agentType || args?.providerType;
14146
14587
  if (!sessionLookupFailed) {
14147
- providerType = session?.providerType || args?.agentType || args?.providerType || this.inferProviderType(managerKey);
14588
+ providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
14589
+ } else if (!providerType) {
14590
+ providerType = this.inferProviderType(managerKey);
14148
14591
  }
14149
14592
  return { session, managerKey, providerType, sessionLookupFailed };
14150
14593
  }
@@ -14224,7 +14667,8 @@ var DaemonCommandHandler = class {
14224
14667
  "pty_resize",
14225
14668
  "invoke_provider_script"
14226
14669
  ]);
14227
- if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd)) {
14670
+ 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);
14671
+ if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
14228
14672
  const result2 = {
14229
14673
  success: false,
14230
14674
  error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
@@ -14478,16 +14922,16 @@ var DaemonCommandHandler = class {
14478
14922
  // src/commands/cli-manager.ts
14479
14923
  init_provider_cli_adapter();
14480
14924
  import * as os13 from "os";
14481
- import * as path16 from "path";
14925
+ import * as path17 from "path";
14482
14926
  import * as crypto4 from "crypto";
14483
- import { existsSync as existsSync11 } from "fs";
14927
+ import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
14484
14928
  import { execFileSync } from "child_process";
14485
14929
  import chalk from "chalk";
14486
14930
  init_config();
14487
14931
 
14488
14932
  // src/providers/cli-provider-instance.ts
14489
14933
  import * as os12 from "os";
14490
- import * as path15 from "path";
14934
+ import * as path16 from "path";
14491
14935
  import * as crypto3 from "crypto";
14492
14936
  import * as fs6 from "fs";
14493
14937
  import { createRequire } from "module";
@@ -14546,7 +14990,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
14546
14990
  var CachedDatabaseSync = null;
14547
14991
  function getDatabaseSync() {
14548
14992
  if (CachedDatabaseSync) return CachedDatabaseSync;
14549
- const requireFn = typeof __require === "function" ? __require : createRequire(path15.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
14993
+ const requireFn = typeof __require === "function" ? __require : createRequire(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
14550
14994
  const sqliteModule = requireFn(`node:${"sqlite"}`);
14551
14995
  CachedDatabaseSync = sqliteModule.DatabaseSync;
14552
14996
  if (!CachedDatabaseSync) {
@@ -14599,7 +15043,7 @@ var CliProviderInstance = class {
14599
15043
  this.providerSessionId = options?.providerSessionId;
14600
15044
  this.launchMode = options?.launchMode || "new";
14601
15045
  this.onProviderSessionResolved = options?.onProviderSessionResolved;
14602
- this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
15046
+ this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
14603
15047
  this.monitor = new StatusMonitor();
14604
15048
  this.historyWriter = new ChatHistoryWriter();
14605
15049
  }
@@ -15076,7 +15520,19 @@ var CliProviderInstance = class {
15076
15520
  }
15077
15521
  }
15078
15522
  pushEvent(event) {
15079
- this.events.push(event);
15523
+ const enrichedEvent = {
15524
+ ...event,
15525
+ instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
15526
+ targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
15527
+ providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
15528
+ workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
15529
+ providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
15530
+ };
15531
+ if (this.context?.emitProviderEvent) {
15532
+ this.context.emitProviderEvent(enrichedEvent);
15533
+ return;
15534
+ }
15535
+ this.events.push(enrichedEvent);
15080
15536
  }
15081
15537
  flushEvents() {
15082
15538
  const events = [...this.events];
@@ -15283,12 +15739,59 @@ ${effect.notification.body || ""}`.trim();
15283
15739
  );
15284
15740
  }
15285
15741
  }
15742
+ mergeRuntimeChatMessages(parsedMessages) {
15743
+ return this.mergeConversationMessages(parsedMessages);
15744
+ }
15286
15745
  mergeConversationMessages(parsedMessages) {
15287
15746
  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;
15747
+ const parsedEntries = parsedMessages.map((message, index) => ({
15748
+ message,
15749
+ index,
15750
+ source: "parsed"
15751
+ }));
15752
+ const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
15753
+ message: entry.message,
15754
+ index: parsedMessages.length + index,
15755
+ source: "runtime",
15756
+ runtimeKey: entry.key
15757
+ }));
15758
+ const getTime = (message) => {
15759
+ const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
15760
+ return Number.isFinite(value) && value > 0 ? value : 0;
15761
+ };
15762
+ const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
15763
+ const isRuntimeOverlay = (entry) => {
15764
+ if (entry.source !== "runtime") return false;
15765
+ const key = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
15766
+ if (key.startsWith("auto_approval:")) return true;
15767
+ return !isUserFacingChatMessage(entry.message);
15768
+ };
15769
+ const shouldKeepParsedBeforeUntimedRuntime = (message) => {
15770
+ const role = getRole(message);
15771
+ return role === "user" || role === "human";
15772
+ };
15773
+ const shouldKeepParsedAfterUntimedRuntime = (message) => {
15774
+ const role = getRole(message);
15775
+ if (role !== "assistant") return false;
15776
+ const kind = resolveChatMessageKind(message);
15777
+ return kind === "standard" || kind === "terminal";
15778
+ };
15779
+ return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
15780
+ const aTime = getTime(a.message);
15781
+ const bTime = getTime(b.message);
15782
+ if (aTime && bTime && aTime !== bTime) return aTime - bTime;
15783
+ if (a.source !== b.source && aTime !== bTime) {
15784
+ const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
15785
+ const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
15786
+ if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
15787
+ if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
15788
+ return a.source === "parsed" ? -1 : 1;
15789
+ }
15790
+ if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
15791
+ return a.source === "parsed" ? 1 : -1;
15792
+ }
15793
+ }
15794
+ }
15292
15795
  return a.index - b.index;
15293
15796
  }).map((entry) => entry.message));
15294
15797
  }
@@ -16617,17 +17120,17 @@ function shouldRestoreHostedRuntime(record, managerTag) {
16617
17120
  // src/commands/cli-manager.ts
16618
17121
  function isExplicitCommand(command) {
16619
17122
  const trimmed = command.trim();
16620
- return path16.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
17123
+ return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
16621
17124
  }
16622
17125
  function expandExecutable(command) {
16623
17126
  const trimmed = command.trim();
16624
- return trimmed.startsWith("~") ? path16.join(os13.homedir(), trimmed.slice(1)) : trimmed;
17127
+ return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
16625
17128
  }
16626
17129
  function commandExists(command) {
16627
17130
  const trimmed = command.trim();
16628
17131
  if (!trimmed) return false;
16629
17132
  if (isExplicitCommand(trimmed)) {
16630
- return existsSync11(expandExecutable(trimmed));
17133
+ return existsSync12(expandExecutable(trimmed));
16631
17134
  }
16632
17135
  try {
16633
17136
  execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -16645,6 +17148,35 @@ function colorize(color, text) {
16645
17148
  const fn = chalkApi?.[color];
16646
17149
  return typeof fn === "function" ? fn(text) : text;
16647
17150
  }
17151
+ var COORDINATOR_DELEGATED_ENV_UNSETS = {
17152
+ ADHDEV_INLINE_MESH: "",
17153
+ ADHDEV_MCP_TRANSPORT: "",
17154
+ ADHDEV_MESH_ID: "",
17155
+ HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
17156
+ };
17157
+ function hasCliArg(args, flag) {
17158
+ return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
17159
+ }
17160
+ function ensureEmptyDelegatedMcpConfig(workspace) {
17161
+ const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
17162
+ mkdirSync7(baseDir, { recursive: true });
17163
+ const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
17164
+ const filePath = path17.join(baseDir, `${workspaceHash}.json`);
17165
+ writeFileSync7(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
17166
+ return filePath;
17167
+ }
17168
+ function buildCoordinatorDelegatedCliLaunchOptions(input) {
17169
+ const cliType = String(input.cliType || "").trim();
17170
+ const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
17171
+ const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
17172
+ if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
17173
+ cliArgs.unshift("--ignore-user-config");
17174
+ }
17175
+ if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
17176
+ cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
17177
+ }
17178
+ return { cliArgs, env };
17179
+ }
16648
17180
  function isUuid(value) {
16649
17181
  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
17182
  }
@@ -16815,7 +17347,7 @@ var DaemonCliManager = class {
16815
17347
  attachExisting
16816
17348
  }) || void 0;
16817
17349
  }
16818
- createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
17350
+ createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
16819
17351
  const normalizedType = this.providerLoader.resolveAlias(cliType);
16820
17352
  const provider = this.providerLoader.getMeta(normalizedType);
16821
17353
  if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
@@ -16829,7 +17361,7 @@ var DaemonCliManager = class {
16829
17361
  providerSessionId,
16830
17362
  attachExisting
16831
17363
  );
16832
- return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
17364
+ return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
16833
17365
  }
16834
17366
  throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
16835
17367
  }
@@ -16902,7 +17434,7 @@ var DaemonCliManager = class {
16902
17434
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
16903
17435
  const trimmed = (workingDir || "").trim();
16904
17436
  if (!trimmed) throw new Error("working directory required");
16905
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path16.resolve(trimmed);
17437
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
16906
17438
  const normalizedType = this.providerLoader.resolveAlias(cliType);
16907
17439
  const rawProvider = this.providerLoader.getByAlias(cliType);
16908
17440
  const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
@@ -17032,6 +17564,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
17032
17564
  {
17033
17565
  providerSessionId: sessionBinding.providerSessionId,
17034
17566
  launchMode: sessionBinding.launchMode,
17567
+ extraEnv: options?.extraEnv,
17035
17568
  onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
17036
17569
  this.persistRecentActivity({
17037
17570
  kind: "cli",
@@ -17052,7 +17585,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
17052
17585
  resolvedCliArgs,
17053
17586
  key,
17054
17587
  sessionBinding.providerSessionId,
17055
- false
17588
+ false,
17589
+ options?.extraEnv
17056
17590
  );
17057
17591
  try {
17058
17592
  await adapter.spawn();
@@ -17276,12 +17810,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
17276
17810
  const dir = resolved.path;
17277
17811
  const launchSource = resolved.source;
17278
17812
  if (!cliType) throw new Error("cliType required");
17813
+ const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
17814
+ const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
17815
+ cliType,
17816
+ workspace: dir,
17817
+ cliArgs: args?.cliArgs,
17818
+ env: args?.env
17819
+ }) : null;
17279
17820
  const started = await this.startSession(
17280
17821
  cliType,
17281
17822
  dir,
17282
- args?.cliArgs,
17823
+ delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
17283
17824
  args?.initialModel,
17284
- { resumeSessionId: args?.resumeSessionId, settingsOverride: args?.settings }
17825
+ {
17826
+ resumeSessionId: args?.resumeSessionId,
17827
+ settingsOverride,
17828
+ extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
17829
+ }
17285
17830
  );
17286
17831
  return {
17287
17832
  success: true,
@@ -17403,11 +17948,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
17403
17948
  import { execSync as execSync4, spawn as spawn2 } from "child_process";
17404
17949
  import * as net from "net";
17405
17950
  import * as os15 from "os";
17406
- import * as path18 from "path";
17951
+ import * as path19 from "path";
17407
17952
 
17408
17953
  // src/providers/provider-loader.ts
17409
17954
  import * as fs7 from "fs";
17410
- import * as path17 from "path";
17955
+ import * as path18 from "path";
17411
17956
  import * as os14 from "os";
17412
17957
  import * as chokidar from "chokidar";
17413
17958
  init_logger();
@@ -17731,7 +18276,7 @@ var ProviderLoader = class _ProviderLoader {
17731
18276
  try {
17732
18277
  if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
17733
18278
  return ["ide", "extension", "cli", "acp"].some(
17734
- (category) => fs7.existsSync(path17.join(candidate, category))
18279
+ (category) => fs7.existsSync(path18.join(candidate, category))
17735
18280
  );
17736
18281
  } catch {
17737
18282
  return false;
@@ -17739,20 +18284,20 @@ var ProviderLoader = class _ProviderLoader {
17739
18284
  }
17740
18285
  static hasProviderRootMarker(candidate) {
17741
18286
  try {
17742
- return fs7.existsSync(path17.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
18287
+ return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
17743
18288
  } catch {
17744
18289
  return false;
17745
18290
  }
17746
18291
  }
17747
18292
  detectDefaultUserDir() {
17748
- const fallback = path17.join(os14.homedir(), ".adhdev", "providers");
18293
+ const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
17749
18294
  const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
17750
18295
  const visited = /* @__PURE__ */ new Set();
17751
18296
  for (const start of this.probeStarts) {
17752
- let current = path17.resolve(start);
18297
+ let current = path18.resolve(start);
17753
18298
  while (!visited.has(current)) {
17754
18299
  visited.add(current);
17755
- const siblingCandidate = path17.join(path17.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
18300
+ const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
17756
18301
  if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
17757
18302
  const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
17758
18303
  if (envOptIn || hasMarker) {
@@ -17774,7 +18319,7 @@ var ProviderLoader = class _ProviderLoader {
17774
18319
  return { path: siblingCandidate, source };
17775
18320
  }
17776
18321
  }
17777
- const parent = path17.dirname(current);
18322
+ const parent = path18.dirname(current);
17778
18323
  if (parent === current) break;
17779
18324
  current = parent;
17780
18325
  }
@@ -17784,11 +18329,11 @@ var ProviderLoader = class _ProviderLoader {
17784
18329
  constructor(options) {
17785
18330
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
17786
18331
  this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
17787
- this.defaultProvidersDir = path17.join(os14.homedir(), ".adhdev", "providers");
18332
+ this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
17788
18333
  const detected = this.detectDefaultUserDir();
17789
18334
  this.userDir = detected.path;
17790
18335
  this.userDirSource = detected.source;
17791
- this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
18336
+ this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
17792
18337
  this.disableUpstream = false;
17793
18338
  this.applySourceConfig({
17794
18339
  userDir: options?.userDir,
@@ -17847,7 +18392,7 @@ var ProviderLoader = class _ProviderLoader {
17847
18392
  this.userDir = detected.path;
17848
18393
  this.userDirSource = detected.source;
17849
18394
  }
17850
- this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
18395
+ this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
17851
18396
  this.disableUpstream = this.sourceMode === "no-upstream";
17852
18397
  if (this.explicitProviderDir) {
17853
18398
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
@@ -17861,7 +18406,7 @@ var ProviderLoader = class _ProviderLoader {
17861
18406
  * Canonical provider directory shape for a given root.
17862
18407
  */
17863
18408
  getProviderDir(root, category, type) {
17864
- return path17.join(root, category, type);
18409
+ return path18.join(root, category, type);
17865
18410
  }
17866
18411
  /**
17867
18412
  * Canonical user override directory for a provider.
@@ -17888,7 +18433,7 @@ var ProviderLoader = class _ProviderLoader {
17888
18433
  resolveProviderFile(type, ...segments) {
17889
18434
  const dir = this.findProviderDirInternal(type);
17890
18435
  if (!dir) return null;
17891
- return path17.join(dir, ...segments);
18436
+ return path18.join(dir, ...segments);
17892
18437
  }
17893
18438
  /**
17894
18439
  * Load all providers (3-tier priority)
@@ -17927,7 +18472,7 @@ var ProviderLoader = class _ProviderLoader {
17927
18472
  if (!fs7.existsSync(this.upstreamDir)) return false;
17928
18473
  try {
17929
18474
  return fs7.readdirSync(this.upstreamDir).some(
17930
- (d) => fs7.statSync(path17.join(this.upstreamDir, d)).isDirectory()
18475
+ (d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
17931
18476
  );
17932
18477
  } catch {
17933
18478
  return false;
@@ -18424,8 +18969,8 @@ var ProviderLoader = class _ProviderLoader {
18424
18969
  resolved._resolvedScriptDir = entry.scriptDir;
18425
18970
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
18426
18971
  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;
18972
+ const fullDir = path18.join(providerDir, entry.scriptDir);
18973
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18429
18974
  }
18430
18975
  matched = true;
18431
18976
  }
@@ -18440,8 +18985,8 @@ var ProviderLoader = class _ProviderLoader {
18440
18985
  resolved._resolvedScriptDir = base.defaultScriptDir;
18441
18986
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
18442
18987
  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;
18988
+ const fullDir = path18.join(providerDir, base.defaultScriptDir);
18989
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18445
18990
  }
18446
18991
  }
18447
18992
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -18458,8 +19003,8 @@ var ProviderLoader = class _ProviderLoader {
18458
19003
  resolved._resolvedScriptDir = dirOverride;
18459
19004
  resolved._resolvedScriptsSource = `versions:${range}`;
18460
19005
  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;
19006
+ const fullDir = path18.join(providerDir, dirOverride);
19007
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18463
19008
  }
18464
19009
  }
18465
19010
  } else if (override.scripts) {
@@ -18475,8 +19020,8 @@ var ProviderLoader = class _ProviderLoader {
18475
19020
  resolved._resolvedScriptDir = base.defaultScriptDir;
18476
19021
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
18477
19022
  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;
19023
+ const fullDir = path18.join(providerDir, base.defaultScriptDir);
19024
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18480
19025
  }
18481
19026
  }
18482
19027
  }
@@ -18508,14 +19053,14 @@ var ProviderLoader = class _ProviderLoader {
18508
19053
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
18509
19054
  return null;
18510
19055
  }
18511
- const dir = path17.join(providerDir, scriptDir);
19056
+ const dir = path18.join(providerDir, scriptDir);
18512
19057
  if (!fs7.existsSync(dir)) {
18513
19058
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
18514
19059
  return null;
18515
19060
  }
18516
19061
  const cached = this.scriptsCache.get(dir);
18517
19062
  if (cached) return cached;
18518
- const scriptsJs = path17.join(dir, "scripts.js");
19063
+ const scriptsJs = path18.join(dir, "scripts.js");
18519
19064
  if (fs7.existsSync(scriptsJs)) {
18520
19065
  try {
18521
19066
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -18557,7 +19102,7 @@ var ProviderLoader = class _ProviderLoader {
18557
19102
  return;
18558
19103
  }
18559
19104
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
18560
- this.log(`File changed: ${path17.basename(filePath)}, reloading...`);
19105
+ this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
18561
19106
  this.reload();
18562
19107
  }
18563
19108
  };
@@ -18612,7 +19157,7 @@ var ProviderLoader = class _ProviderLoader {
18612
19157
  }
18613
19158
  const https = __require("https");
18614
19159
  const { execSync: execSync7 } = __require("child_process");
18615
- const metaPath = path17.join(this.upstreamDir, _ProviderLoader.META_FILE);
19160
+ const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
18616
19161
  let prevEtag = "";
18617
19162
  let prevTimestamp = 0;
18618
19163
  try {
@@ -18672,17 +19217,17 @@ var ProviderLoader = class _ProviderLoader {
18672
19217
  return { updated: false };
18673
19218
  }
18674
19219
  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()}`);
19220
+ const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
19221
+ const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
18677
19222
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
18678
19223
  fs7.mkdirSync(tmpExtract, { recursive: true });
18679
19224
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
18680
19225
  const extracted = fs7.readdirSync(tmpExtract);
18681
19226
  const rootDir = extracted.find(
18682
- (d) => fs7.statSync(path17.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
19227
+ (d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
18683
19228
  );
18684
19229
  if (!rootDir) throw new Error("Unexpected tarball structure");
18685
- const sourceDir = path17.join(tmpExtract, rootDir);
19230
+ const sourceDir = path18.join(tmpExtract, rootDir);
18686
19231
  const backupDir = this.upstreamDir + ".bak";
18687
19232
  if (fs7.existsSync(this.upstreamDir)) {
18688
19233
  if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
@@ -18757,8 +19302,8 @@ var ProviderLoader = class _ProviderLoader {
18757
19302
  copyDirRecursive(src, dest) {
18758
19303
  fs7.mkdirSync(dest, { recursive: true });
18759
19304
  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);
19305
+ const srcPath = path18.join(src, entry.name);
19306
+ const destPath = path18.join(dest, entry.name);
18762
19307
  if (entry.isDirectory()) {
18763
19308
  this.copyDirRecursive(srcPath, destPath);
18764
19309
  } else {
@@ -18769,7 +19314,7 @@ var ProviderLoader = class _ProviderLoader {
18769
19314
  /** .meta.json save */
18770
19315
  writeMeta(metaPath, etag, timestamp) {
18771
19316
  try {
18772
- fs7.mkdirSync(path17.dirname(metaPath), { recursive: true });
19317
+ fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
18773
19318
  fs7.writeFileSync(metaPath, JSON.stringify({
18774
19319
  etag,
18775
19320
  timestamp,
@@ -18786,7 +19331,7 @@ var ProviderLoader = class _ProviderLoader {
18786
19331
  const scan = (d) => {
18787
19332
  try {
18788
19333
  for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
18789
- if (entry.isDirectory()) scan(path17.join(d, entry.name));
19334
+ if (entry.isDirectory()) scan(path18.join(d, entry.name));
18790
19335
  else if (entry.name === "provider.json") count++;
18791
19336
  }
18792
19337
  } catch {
@@ -19014,17 +19559,17 @@ var ProviderLoader = class _ProviderLoader {
19014
19559
  for (const root of searchRoots) {
19015
19560
  if (!fs7.existsSync(root)) continue;
19016
19561
  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);
19562
+ if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
19563
+ const catDir = path18.join(root, cat);
19019
19564
  if (fs7.existsSync(catDir)) {
19020
19565
  try {
19021
19566
  for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
19022
19567
  if (!entry.isDirectory()) continue;
19023
- const jsonPath = path17.join(catDir, entry.name, "provider.json");
19568
+ const jsonPath = path18.join(catDir, entry.name, "provider.json");
19024
19569
  if (fs7.existsSync(jsonPath)) {
19025
19570
  try {
19026
19571
  const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
19027
- if (data.type === type) return path17.join(catDir, entry.name);
19572
+ if (data.type === type) return path18.join(catDir, entry.name);
19028
19573
  } catch {
19029
19574
  }
19030
19575
  }
@@ -19041,7 +19586,7 @@ var ProviderLoader = class _ProviderLoader {
19041
19586
  * (template substitution is NOT applied here — scripts.js handles that)
19042
19587
  */
19043
19588
  buildScriptWrappersFromDir(dir) {
19044
- const scriptsJs = path17.join(dir, "scripts.js");
19589
+ const scriptsJs = path18.join(dir, "scripts.js");
19045
19590
  if (fs7.existsSync(scriptsJs)) {
19046
19591
  try {
19047
19592
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -19055,7 +19600,7 @@ var ProviderLoader = class _ProviderLoader {
19055
19600
  for (const file of fs7.readdirSync(dir)) {
19056
19601
  if (!file.endsWith(".js")) continue;
19057
19602
  const scriptName = toCamel(file.replace(".js", ""));
19058
- const filePath = path17.join(dir, file);
19603
+ const filePath = path18.join(dir, file);
19059
19604
  result[scriptName] = (...args) => {
19060
19605
  try {
19061
19606
  let content = fs7.readFileSync(filePath, "utf-8");
@@ -19115,7 +19660,7 @@ var ProviderLoader = class _ProviderLoader {
19115
19660
  }
19116
19661
  const hasJson = entries.some((e) => e.name === "provider.json");
19117
19662
  if (hasJson) {
19118
- const jsonPath = path17.join(d, "provider.json");
19663
+ const jsonPath = path18.join(d, "provider.json");
19119
19664
  try {
19120
19665
  const raw = fs7.readFileSync(jsonPath, "utf-8");
19121
19666
  const mod = JSON.parse(raw);
@@ -19136,7 +19681,7 @@ var ProviderLoader = class _ProviderLoader {
19136
19681
  this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
19137
19682
  } else {
19138
19683
  const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
19139
- const scriptsPath = path17.join(d, "scripts.js");
19684
+ const scriptsPath = path18.join(d, "scripts.js");
19140
19685
  if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
19141
19686
  try {
19142
19687
  delete __require.cache[__require.resolve(scriptsPath)];
@@ -19162,7 +19707,7 @@ var ProviderLoader = class _ProviderLoader {
19162
19707
  if (!entry.isDirectory()) continue;
19163
19708
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
19164
19709
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
19165
- scan(path17.join(d, entry.name));
19710
+ scan(path18.join(d, entry.name));
19166
19711
  }
19167
19712
  }
19168
19713
  };
@@ -19487,8 +20032,8 @@ function detectCurrentWorkspace(ideId) {
19487
20032
  const appNameMap = getMacAppIdentifiers();
19488
20033
  const appName = appNameMap[ideId];
19489
20034
  if (appName) {
19490
- const storagePath = path18.join(
19491
- process.env.APPDATA || path18.join(os15.homedir(), "AppData", "Roaming"),
20035
+ const storagePath = path19.join(
20036
+ process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
19492
20037
  appName,
19493
20038
  "storage.json"
19494
20039
  );
@@ -19677,9 +20222,9 @@ init_logger();
19677
20222
 
19678
20223
  // src/logging/command-log.ts
19679
20224
  import * as fs8 from "fs";
19680
- import * as path19 from "path";
20225
+ import * as path20 from "path";
19681
20226
  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");
20227
+ 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
20228
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
19684
20229
  var MAX_DAYS = 7;
19685
20230
  try {
@@ -19717,13 +20262,13 @@ function getDateStr2() {
19717
20262
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
19718
20263
  }
19719
20264
  var currentDate2 = getDateStr2();
19720
- var currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20265
+ var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
19721
20266
  var writeCount2 = 0;
19722
20267
  function checkRotation() {
19723
20268
  const today = getDateStr2();
19724
20269
  if (today !== currentDate2) {
19725
20270
  currentDate2 = today;
19726
- currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20271
+ currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
19727
20272
  cleanOldFiles();
19728
20273
  }
19729
20274
  }
@@ -19737,7 +20282,7 @@ function cleanOldFiles() {
19737
20282
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
19738
20283
  if (dateMatch && dateMatch[1] < cutoffStr) {
19739
20284
  try {
19740
- fs8.unlinkSync(path19.join(LOG_DIR2, file));
20285
+ fs8.unlinkSync(path20.join(LOG_DIR2, file));
19741
20286
  } catch {
19742
20287
  }
19743
20288
  }
@@ -19821,13 +20366,65 @@ cleanOldFiles();
19821
20366
 
19822
20367
  // src/commands/router.ts
19823
20368
  init_logger();
20369
+ import * as yaml from "js-yaml";
19824
20370
 
19825
20371
  // src/commands/mesh-coordinator.ts
19826
- import { existsSync as existsSync14, realpathSync as realpathSync2 } from "fs";
20372
+ import { execFileSync as execFileSync2 } from "child_process";
20373
+ import { existsSync as existsSync15, readdirSync as readdirSync6, realpathSync as realpathSync2 } from "fs";
19827
20374
  import { createRequire as createRequire2 } from "module";
19828
- import { dirname as dirname3, join as join17, resolve as resolve13 } from "path";
20375
+ import * as os17 from "os";
20376
+ import { dirname as dirname4, isAbsolute as isAbsolute10, join as join18, resolve as resolve13 } from "path";
19829
20377
  var DEFAULT_SERVER_NAME = "adhdev-mesh";
19830
20378
  var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
20379
+ var HERMES_CLI_TYPE = "hermes-cli";
20380
+ var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
20381
+ function isHermesProvider(provider, cliType) {
20382
+ const type = cliType?.trim() || provider?.type?.trim() || "";
20383
+ return type === HERMES_CLI_TYPE;
20384
+ }
20385
+ function resolveHermesMeshCoordinatorSetup(options) {
20386
+ const mcpServer = resolveAdhdevMcpServerLaunch({
20387
+ meshId: options.meshId,
20388
+ nodeExecutable: options.nodeExecutable,
20389
+ adhdevMcpEntryPath: options.adhdevMcpEntryPath
20390
+ });
20391
+ if (!mcpServer) {
20392
+ return {
20393
+ kind: "unsupported",
20394
+ reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
20395
+ };
20396
+ }
20397
+ const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
20398
+ if (!configPath.trim()) {
20399
+ return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
20400
+ }
20401
+ return {
20402
+ kind: "auto_import",
20403
+ serverName: DEFAULT_SERVER_NAME,
20404
+ configPath,
20405
+ configFormat: "hermes_config_yaml",
20406
+ mcpServer
20407
+ };
20408
+ }
20409
+ function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
20410
+ return {
20411
+ kind: "manual",
20412
+ serverName: DEFAULT_SERVER_NAME,
20413
+ configFormat: "hermes_config_yaml",
20414
+ configPathCommand: HERMES_MCP_CONFIG_PATH,
20415
+ requiresRestart: true,
20416
+ 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.",
20417
+ template: renderMeshCoordinatorTemplate(
20418
+ "mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
20419
+ {
20420
+ meshId,
20421
+ workspace,
20422
+ serverName: DEFAULT_SERVER_NAME,
20423
+ adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
20424
+ }
20425
+ )
20426
+ };
20427
+ }
19831
20428
  function resolveMeshCoordinatorSetup(options) {
19832
20429
  const { provider, meshId, workspace } = options;
19833
20430
  const config = provider?.meshCoordinator;
@@ -19837,6 +20434,9 @@ function resolveMeshCoordinatorSetup(options) {
19837
20434
  reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
19838
20435
  };
19839
20436
  }
20437
+ if (isHermesProvider(provider, options.cliType)) {
20438
+ return resolveHermesMeshCoordinatorSetup(options);
20439
+ }
19840
20440
  const mcpConfig = config.mcpConfig;
19841
20441
  if (!mcpConfig || mcpConfig.mode === "none") {
19842
20442
  return {
@@ -19846,8 +20446,8 @@ function resolveMeshCoordinatorSetup(options) {
19846
20446
  }
19847
20447
  const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
19848
20448
  if (mcpConfig.mode === "auto_import") {
19849
- const path26 = mcpConfig.path?.trim();
19850
- if (!path26) {
20449
+ const path27 = mcpConfig.path?.trim();
20450
+ if (!path27) {
19851
20451
  return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
19852
20452
  }
19853
20453
  const mcpServer = resolveAdhdevMcpServerLaunch({
@@ -19858,13 +20458,13 @@ function resolveMeshCoordinatorSetup(options) {
19858
20458
  if (!mcpServer) {
19859
20459
  return {
19860
20460
  kind: "unsupported",
19861
- reason: "Could not resolve the ADHDev MCP server entrypoint without relying on a PATH bin shim"
20461
+ reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
19862
20462
  };
19863
20463
  }
19864
20464
  return {
19865
20465
  kind: "auto_import",
19866
20466
  serverName,
19867
- configPath: join17(workspace, path26),
20467
+ configPath: resolveMcpConfigPath(path27, workspace),
19868
20468
  configFormat: mcpConfig.format,
19869
20469
  mcpServer
19870
20470
  };
@@ -19898,14 +20498,85 @@ function resolveMeshCoordinatorSetup(options) {
19898
20498
  function renderMeshCoordinatorTemplate(template, values) {
19899
20499
  return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
19900
20500
  }
20501
+ function resolveMcpConfigPath(configPath, workspace) {
20502
+ const trimmed = configPath.trim();
20503
+ if (trimmed === "~") return os17.homedir();
20504
+ if (trimmed.startsWith("~/")) return join18(os17.homedir(), trimmed.slice(2));
20505
+ if (isAbsolute10(trimmed)) return trimmed;
20506
+ return join18(workspace, trimmed);
20507
+ }
19901
20508
  function resolveAdhdevMcpServerLaunch(options) {
19902
20509
  const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
19903
20510
  if (!entryPath) return null;
20511
+ const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
20512
+ if (!nodeExecutable) return null;
19904
20513
  return {
19905
- command: options.nodeExecutable?.trim() || process.execPath,
20514
+ command: nodeExecutable,
19906
20515
  args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
19907
20516
  };
19908
20517
  }
20518
+ function resolveMcpNodeExecutable(explicitExecutable) {
20519
+ const explicit = explicitExecutable?.trim();
20520
+ if (explicit) return explicit;
20521
+ const candidates = [];
20522
+ const addCandidate = (candidate) => {
20523
+ const trimmed = candidate?.trim();
20524
+ if (!trimmed) return;
20525
+ const normalized = normalizeExistingPath(trimmed) || trimmed;
20526
+ if (!candidates.includes(normalized)) candidates.push(normalized);
20527
+ };
20528
+ addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
20529
+ addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
20530
+ addCandidate(process.env.npm_node_execpath);
20531
+ addNodeCandidatesFromPath(process.env.PATH, addCandidate);
20532
+ addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
20533
+ addCandidate("/opt/homebrew/bin/node");
20534
+ addCandidate("/usr/local/bin/node");
20535
+ addCandidate("/usr/bin/node");
20536
+ addCandidate(process.execPath);
20537
+ for (const candidate of candidates) {
20538
+ if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
20539
+ }
20540
+ return null;
20541
+ }
20542
+ function addNodeCandidatesFromPath(pathValue, addCandidate) {
20543
+ for (const entry of (pathValue || "").split(":")) {
20544
+ const dir = entry.trim();
20545
+ if (!dir) continue;
20546
+ addCandidate(join18(dir, "node"));
20547
+ }
20548
+ }
20549
+ function addNodeCandidatesFromNvm(homeDir, addCandidate) {
20550
+ const versionsDir = join18(homeDir, ".nvm", "versions", "node");
20551
+ try {
20552
+ const versionDirs = readdirSync6(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
20553
+ for (const versionDir of versionDirs) {
20554
+ addCandidate(join18(versionsDir, versionDir, "bin", "node"));
20555
+ }
20556
+ } catch {
20557
+ }
20558
+ }
20559
+ function compareNodeVersionNamesDescending(a, b) {
20560
+ const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
20561
+ const left = parse(a);
20562
+ const right = parse(b);
20563
+ for (let i = 0; i < Math.max(left.length, right.length); i++) {
20564
+ const diff = (right[i] || 0) - (left[i] || 0);
20565
+ if (diff !== 0) return diff;
20566
+ }
20567
+ return b.localeCompare(a);
20568
+ }
20569
+ function nodeRuntimeSupportsWebSocket(nodeExecutable) {
20570
+ try {
20571
+ execFileSync2(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
20572
+ stdio: "ignore",
20573
+ timeout: 3e3
20574
+ });
20575
+ return true;
20576
+ } catch {
20577
+ return false;
20578
+ }
20579
+ }
19909
20580
  function resolveAdhdevMcpEntryPath(explicitPath) {
19910
20581
  const explicit = explicitPath?.trim();
19911
20582
  if (explicit) return normalizeExistingPath(explicit) || explicit;
@@ -19918,7 +20589,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19918
20589
  const addPackagedCandidates = (baseFile) => {
19919
20590
  if (!baseFile) return;
19920
20591
  const realBase = normalizeExistingPath(baseFile) || baseFile;
19921
- const dir = dirname3(realBase);
20592
+ const dir = dirname4(realBase);
19922
20593
  addCandidate(resolve13(dir, "../vendor/mcp-server/index.js"));
19923
20594
  addCandidate(resolve13(dir, "../../vendor/mcp-server/index.js"));
19924
20595
  addCandidate(resolve13(dir, "../../../vendor/mcp-server/index.js"));
@@ -19931,7 +20602,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19931
20602
  if (normalized) return normalized;
19932
20603
  }
19933
20604
  try {
19934
- const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join17(process.cwd(), "adhdev-daemon.js");
20605
+ const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join18(process.cwd(), "adhdev-daemon.js");
19935
20606
  const req = createRequire2(requireBase);
19936
20607
  const resolvedModule = req.resolve("@adhdev/mcp-server");
19937
20608
  return normalizeExistingPath(resolvedModule) || resolvedModule;
@@ -19941,16 +20612,110 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19941
20612
  }
19942
20613
  function normalizeExistingPath(filePath) {
19943
20614
  try {
19944
- if (!existsSync14(filePath)) return null;
20615
+ if (!existsSync15(filePath)) return null;
19945
20616
  return realpathSync2.native(filePath);
19946
20617
  } catch {
19947
20618
  return null;
19948
20619
  }
19949
20620
  }
19950
20621
 
20622
+ // src/mesh/mesh-events.ts
20623
+ init_mesh_config();
20624
+ init_logger();
20625
+ function readNonEmptyString(value) {
20626
+ return typeof value === "string" && value.trim() ? value.trim() : "";
20627
+ }
20628
+ function formatCompletionMetadata(event) {
20629
+ const parts = [
20630
+ readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
20631
+ readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
20632
+ readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
20633
+ ].filter(Boolean);
20634
+ return parts.length > 0 ? ` (${parts.join("; ")})` : "";
20635
+ }
20636
+ function buildMeshSystemMessage(args) {
20637
+ const metadata = formatCompletionMetadata(args.metadataEvent);
20638
+ if (args.event === "agent:generating_completed") {
20639
+ 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.`;
20640
+ }
20641
+ if (args.event === "agent:waiting_approval") {
20642
+ return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
20643
+ }
20644
+ return "";
20645
+ }
20646
+ function injectMeshSystemMessage(components, args) {
20647
+ const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
20648
+ const instState = inst.getState();
20649
+ if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
20650
+ if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
20651
+ return true;
20652
+ });
20653
+ if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
20654
+ const messageText = buildMeshSystemMessage({
20655
+ event: args.event,
20656
+ nodeLabel: args.nodeLabel,
20657
+ metadataEvent: args.metadataEvent
20658
+ });
20659
+ if (!messageText) return { success: false, error: "unsupported mesh event" };
20660
+ for (const coord of coordinatorInstances) {
20661
+ const coordState = coord.getState();
20662
+ LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
20663
+ coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
20664
+ }
20665
+ return { success: true, forwarded: coordinatorInstances.length };
20666
+ }
20667
+ function handleMeshForwardEvent(components, payload) {
20668
+ const eventName = readNonEmptyString(payload.event);
20669
+ if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
20670
+ return { success: false, error: "unsupported mesh event" };
20671
+ }
20672
+ const meshId = readNonEmptyString(payload.meshId);
20673
+ if (!meshId) return { success: false, error: "meshId required" };
20674
+ const nodeId = readNonEmptyString(payload.nodeId);
20675
+ const workspace = readNonEmptyString(payload.workspace);
20676
+ const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
20677
+ return injectMeshSystemMessage(components, {
20678
+ meshId,
20679
+ nodeLabel,
20680
+ event: eventName,
20681
+ metadataEvent: {
20682
+ targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
20683
+ providerType: readNonEmptyString(payload.providerType),
20684
+ providerSessionId: readNonEmptyString(payload.providerSessionId)
20685
+ }
20686
+ });
20687
+ }
20688
+ function setupMeshEventForwarding(components) {
20689
+ components.instanceManager.onEvent((event) => {
20690
+ if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
20691
+ const instanceId = readNonEmptyString(event.instanceId);
20692
+ if (!instanceId) return;
20693
+ const sourceInstance = components.instanceManager.getInstance(instanceId);
20694
+ if (!sourceInstance || sourceInstance.category !== "cli") return;
20695
+ const state = sourceInstance.getState();
20696
+ const workspace = readNonEmptyString(state.workspace);
20697
+ if (!workspace) return;
20698
+ const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
20699
+ const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
20700
+ const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
20701
+ const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
20702
+ if (!meshId) return;
20703
+ const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
20704
+ const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
20705
+ const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
20706
+ injectMeshSystemMessage(components, {
20707
+ meshId,
20708
+ sourceInstanceId: instanceId,
20709
+ nodeLabel,
20710
+ event: event.event,
20711
+ metadataEvent: event
20712
+ });
20713
+ });
20714
+ }
20715
+
19951
20716
  // src/status/snapshot.ts
19952
20717
  init_config();
19953
- import * as os17 from "os";
20718
+ import * as os18 from "os";
19954
20719
  init_terminal_screen();
19955
20720
  init_logger();
19956
20721
  var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
@@ -20005,8 +20770,8 @@ function buildAvailableProviders(providerLoader) {
20005
20770
  }
20006
20771
  function buildMachineInfo(profile = "full") {
20007
20772
  const base = {
20008
- hostname: os17.hostname(),
20009
- platform: os17.platform()
20773
+ hostname: os18.hostname(),
20774
+ platform: os18.platform()
20010
20775
  };
20011
20776
  if (profile === "live") {
20012
20777
  return base;
@@ -20015,23 +20780,23 @@ function buildMachineInfo(profile = "full") {
20015
20780
  const memSnap2 = getHostMemorySnapshot();
20016
20781
  return {
20017
20782
  ...base,
20018
- arch: os17.arch(),
20019
- cpus: os17.cpus().length,
20783
+ arch: os18.arch(),
20784
+ cpus: os18.cpus().length,
20020
20785
  totalMem: memSnap2.totalMem,
20021
- release: os17.release()
20786
+ release: os18.release()
20022
20787
  };
20023
20788
  }
20024
20789
  const memSnap = getHostMemorySnapshot();
20025
20790
  return {
20026
20791
  ...base,
20027
- arch: os17.arch(),
20028
- cpus: os17.cpus().length,
20792
+ arch: os18.arch(),
20793
+ cpus: os18.cpus().length,
20029
20794
  totalMem: memSnap.totalMem,
20030
20795
  freeMem: memSnap.freeMem,
20031
20796
  availableMem: memSnap.availableMem,
20032
- loadavg: os17.loadavg(),
20033
- uptime: os17.uptime(),
20034
- release: os17.release()
20797
+ loadavg: os18.loadavg(),
20798
+ uptime: os18.uptime(),
20799
+ release: os18.release()
20035
20800
  };
20036
20801
  }
20037
20802
  function parseMessageTime(value) {
@@ -20262,17 +21027,17 @@ function buildStatusSnapshot(options) {
20262
21027
  }
20263
21028
 
20264
21029
  // src/commands/upgrade-helper.ts
20265
- import { execFileSync as execFileSync2 } from "child_process";
21030
+ import { execFileSync as execFileSync3 } from "child_process";
20266
21031
  import { spawn as spawn3 } from "child_process";
20267
21032
  import * as fs9 from "fs";
20268
- import * as os18 from "os";
20269
- import * as path20 from "path";
21033
+ import * as os19 from "os";
21034
+ import * as path21 from "path";
20270
21035
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
20271
21036
  function getUpgradeLogPath() {
20272
- const home = os18.homedir();
20273
- const dir = path20.join(home, ".adhdev");
21037
+ const home = os19.homedir();
21038
+ const dir = path21.join(home, ".adhdev");
20274
21039
  fs9.mkdirSync(dir, { recursive: true });
20275
- return path20.join(dir, "daemon-upgrade.log");
21040
+ return path21.join(dir, "daemon-upgrade.log");
20276
21041
  }
20277
21042
  function appendUpgradeLog(message) {
20278
21043
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -20283,14 +21048,14 @@ function appendUpgradeLog(message) {
20283
21048
  }
20284
21049
  }
20285
21050
  function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
20286
- const binDir = path20.dirname(nodeExecutable);
21051
+ const binDir = path21.dirname(nodeExecutable);
20287
21052
  if (platform10 === "win32") {
20288
- const npmCliPath = path20.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
21053
+ const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
20289
21054
  if (fs9.existsSync(npmCliPath)) {
20290
21055
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
20291
21056
  }
20292
21057
  for (const candidate of ["npm.exe", "npm"]) {
20293
- const candidatePath = path20.join(binDir, candidate);
21058
+ const candidatePath = path21.join(binDir, candidate);
20294
21059
  if (fs9.existsSync(candidatePath)) {
20295
21060
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
20296
21061
  }
@@ -20298,7 +21063,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
20298
21063
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
20299
21064
  }
20300
21065
  for (const candidate of ["npm"]) {
20301
- const candidatePath = path20.join(binDir, candidate);
21066
+ const candidatePath = path21.join(binDir, candidate);
20302
21067
  if (fs9.existsSync(candidatePath)) {
20303
21068
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
20304
21069
  }
@@ -20315,13 +21080,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20315
21080
  let currentDir = resolvedPath;
20316
21081
  try {
20317
21082
  if (fs9.statSync(resolvedPath).isFile()) {
20318
- currentDir = path20.dirname(resolvedPath);
21083
+ currentDir = path21.dirname(resolvedPath);
20319
21084
  }
20320
21085
  } catch {
20321
- currentDir = path20.dirname(resolvedPath);
21086
+ currentDir = path21.dirname(resolvedPath);
20322
21087
  }
20323
21088
  while (true) {
20324
- const packageJsonPath = path20.join(currentDir, "package.json");
21089
+ const packageJsonPath = path21.join(currentDir, "package.json");
20325
21090
  try {
20326
21091
  if (fs9.existsSync(packageJsonPath)) {
20327
21092
  const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
@@ -20332,7 +21097,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20332
21097
  }
20333
21098
  } catch {
20334
21099
  }
20335
- const parentDir = path20.dirname(currentDir);
21100
+ const parentDir = path21.dirname(currentDir);
20336
21101
  if (parentDir === currentDir) {
20337
21102
  return null;
20338
21103
  }
@@ -20340,13 +21105,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20340
21105
  }
20341
21106
  }
20342
21107
  function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
20343
- const nodeModulesDir = packageName.startsWith("@") ? path20.dirname(path20.dirname(packageRoot)) : path20.dirname(packageRoot);
20344
- if (path20.basename(nodeModulesDir) !== "node_modules") {
21108
+ const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
21109
+ if (path21.basename(nodeModulesDir) !== "node_modules") {
20345
21110
  return null;
20346
21111
  }
20347
- const maybeLibDir = path20.dirname(nodeModulesDir);
20348
- if (path20.basename(maybeLibDir) === "lib") {
20349
- return path20.dirname(maybeLibDir);
21112
+ const maybeLibDir = path21.dirname(nodeModulesDir);
21113
+ if (path21.basename(maybeLibDir) === "lib") {
21114
+ return path21.dirname(maybeLibDir);
20350
21115
  }
20351
21116
  return maybeLibDir;
20352
21117
  }
@@ -20382,7 +21147,7 @@ function getNpmExecOptions(platform10 = process.platform) {
20382
21147
  }
20383
21148
  function execNpmCommandSync(args, options = {}, surface) {
20384
21149
  const execOptions = surface?.execOptions || getNpmExecOptions();
20385
- return execFileSync2(
21150
+ return execFileSync3(
20386
21151
  surface?.npmExecutable || "npm",
20387
21152
  [...surface?.npmArgsPrefix || [], ...args],
20388
21153
  {
@@ -20395,7 +21160,7 @@ function execNpmCommandSync(args, options = {}, surface) {
20395
21160
  function killPid(pid) {
20396
21161
  try {
20397
21162
  if (process.platform === "win32") {
20398
- execFileSync2("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
21163
+ execFileSync3("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
20399
21164
  } else {
20400
21165
  process.kill(pid, "SIGTERM");
20401
21166
  }
@@ -20407,7 +21172,7 @@ function killPid(pid) {
20407
21172
  function getWindowsProcessCommandLine(pid) {
20408
21173
  const pidFilter = `ProcessId=${pid}`;
20409
21174
  try {
20410
- const psOut = execFileSync2("powershell.exe", [
21175
+ const psOut = execFileSync3("powershell.exe", [
20411
21176
  "-NoProfile",
20412
21177
  "-NonInteractive",
20413
21178
  "-ExecutionPolicy",
@@ -20419,7 +21184,7 @@ function getWindowsProcessCommandLine(pid) {
20419
21184
  } catch {
20420
21185
  }
20421
21186
  try {
20422
- const wmicOut = execFileSync2("wmic", [
21187
+ const wmicOut = execFileSync3("wmic", [
20423
21188
  "process",
20424
21189
  "where",
20425
21190
  pidFilter,
@@ -20435,7 +21200,7 @@ function getProcessCommandLine(pid) {
20435
21200
  if (!Number.isFinite(pid) || pid <= 0) return null;
20436
21201
  if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
20437
21202
  try {
20438
- const text = execFileSync2("ps", ["-o", "command=", "-p", String(pid)], {
21203
+ const text = execFileSync3("ps", ["-o", "command=", "-p", String(pid)], {
20439
21204
  encoding: "utf8",
20440
21205
  timeout: 3e3,
20441
21206
  stdio: ["ignore", "pipe", "ignore"]
@@ -20461,7 +21226,7 @@ async function waitForPidExit(pid, timeoutMs) {
20461
21226
  }
20462
21227
  }
20463
21228
  function stopSessionHostProcesses(appName) {
20464
- const pidFile = path20.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
21229
+ const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
20465
21230
  try {
20466
21231
  if (fs9.existsSync(pidFile)) {
20467
21232
  const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
@@ -20478,7 +21243,7 @@ function stopSessionHostProcesses(appName) {
20478
21243
  }
20479
21244
  }
20480
21245
  function removeDaemonPidFile() {
20481
- const pidFile = path20.join(os18.homedir(), ".adhdev", "daemon.pid");
21246
+ const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
20482
21247
  try {
20483
21248
  fs9.unlinkSync(pidFile);
20484
21249
  } catch {
@@ -20489,7 +21254,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
20489
21254
  const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
20490
21255
  if (!npmRoot) return;
20491
21256
  const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
20492
- const binDir = process.platform === "win32" ? npmPrefix : path20.join(npmPrefix, "bin");
21257
+ const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
20493
21258
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
20494
21259
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
20495
21260
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -20497,25 +21262,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
20497
21262
  }
20498
21263
  if (pkgName.startsWith("@")) {
20499
21264
  const [scope, name] = pkgName.split("/");
20500
- const scopeDir = path20.join(npmRoot, scope);
21265
+ const scopeDir = path21.join(npmRoot, scope);
20501
21266
  if (!fs9.existsSync(scopeDir)) return;
20502
21267
  for (const entry of fs9.readdirSync(scopeDir)) {
20503
21268
  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)}`);
21269
+ fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
21270
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
20506
21271
  }
20507
21272
  } else {
20508
21273
  for (const entry of fs9.readdirSync(npmRoot)) {
20509
21274
  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)}`);
21275
+ fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
21276
+ appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
20512
21277
  }
20513
21278
  }
20514
21279
  if (fs9.existsSync(binDir)) {
20515
21280
  for (const entry of fs9.readdirSync(binDir)) {
20516
21281
  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)}`);
21282
+ fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
21283
+ appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
20519
21284
  }
20520
21285
  }
20521
21286
  }
@@ -20551,7 +21316,7 @@ async function runDaemonUpgradeHelper(payload) {
20551
21316
  cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
20552
21317
  const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
20553
21318
  appendUpgradeLog(`Installing ${spec}`);
20554
- const installOutput = execFileSync2(
21319
+ const installOutput = execFileSync3(
20555
21320
  installCommand.command,
20556
21321
  installCommand.args,
20557
21322
  {
@@ -20616,6 +21381,56 @@ function normalizeReleaseChannel(value) {
20616
21381
  function resolveUpgradeChannel(args) {
20617
21382
  return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
20618
21383
  }
21384
+ function readProviderPriorityFromPolicy(policy) {
21385
+ const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
21386
+ const raw = record.providerPriority;
21387
+ if (!Array.isArray(raw)) return [];
21388
+ const seen = /* @__PURE__ */ new Set();
21389
+ return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
21390
+ if (seen.has(type)) return false;
21391
+ seen.add(type);
21392
+ return true;
21393
+ });
21394
+ }
21395
+ async function resolveProviderTypeFromPriority(args) {
21396
+ if (!args.providerPriority.length) {
21397
+ return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
21398
+ }
21399
+ const failed = [];
21400
+ for (const requestedType of args.providerPriority) {
21401
+ const normalizedType = args.providerLoader.resolveAlias(requestedType);
21402
+ if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
21403
+ failed.push(`${requestedType}: disabled`);
21404
+ continue;
21405
+ }
21406
+ const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
21407
+ args.providerLoader.setCliDetectionResults([{
21408
+ id: normalizedType,
21409
+ installed: !!detected,
21410
+ path: detected?.path
21411
+ }], false);
21412
+ args.onStatusChange?.();
21413
+ if (detected) return { providerType: normalizedType };
21414
+ failed.push(`${requestedType}: not detected`);
21415
+ }
21416
+ return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
21417
+ }
21418
+ function loadYamlModule() {
21419
+ return yaml;
21420
+ }
21421
+ function getMcpServersKey(format) {
21422
+ return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
21423
+ }
21424
+ function parseMeshCoordinatorMcpConfig(text, format) {
21425
+ if (!text.trim()) return {};
21426
+ if (format === "claude_mcp_json") return JSON.parse(text);
21427
+ const parsed = loadYamlModule().load(text);
21428
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
21429
+ }
21430
+ function serializeMeshCoordinatorMcpConfig(config, format) {
21431
+ if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
21432
+ return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
21433
+ }
20619
21434
  var CHAT_COMMANDS = [
20620
21435
  "send_chat",
20621
21436
  "new_chat",
@@ -20714,6 +21529,154 @@ var DaemonCommandRouter = class {
20714
21529
  constructor(deps) {
20715
21530
  this.deps = deps;
20716
21531
  }
21532
+ getCachedInlineMesh(meshId, inlineMesh) {
21533
+ if (inlineMesh && typeof inlineMesh === "object") {
21534
+ this.inlineMeshCache.set(meshId, inlineMesh);
21535
+ return inlineMesh;
21536
+ }
21537
+ return this.inlineMeshCache.get(meshId);
21538
+ }
21539
+ async getMeshForCommand(meshId, inlineMesh) {
21540
+ try {
21541
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21542
+ const mesh = getMesh3(meshId);
21543
+ if (mesh) return { mesh, inline: false };
21544
+ } catch {
21545
+ }
21546
+ const cached = this.getCachedInlineMesh(meshId, inlineMesh);
21547
+ return cached ? { mesh: cached, inline: true } : null;
21548
+ }
21549
+ updateInlineMeshNode(meshId, mesh, node) {
21550
+ if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
21551
+ const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
21552
+ if (idx >= 0) mesh.nodes[idx] = node;
21553
+ else mesh.nodes.push(node);
21554
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21555
+ this.inlineMeshCache.set(meshId, mesh);
21556
+ }
21557
+ removeInlineMeshNode(meshId, mesh, nodeId) {
21558
+ if (!mesh || !Array.isArray(mesh.nodes)) return false;
21559
+ const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
21560
+ if (idx === -1) return false;
21561
+ mesh.nodes.splice(idx, 1);
21562
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21563
+ this.inlineMeshCache.set(meshId, mesh);
21564
+ return true;
21565
+ }
21566
+ normalizeMeshSessionCleanupMode(value) {
21567
+ return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
21568
+ }
21569
+ sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
21570
+ const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
21571
+ if (!sessionId) return false;
21572
+ if (sessionIds?.size) return sessionIds.has(sessionId);
21573
+ const workspace = typeof node?.workspace === "string" ? node.workspace : "";
21574
+ if (workspace && record?.workspace === workspace) return true;
21575
+ if (record?.meta?.meshNodeId === nodeId) return true;
21576
+ return false;
21577
+ }
21578
+ isCompletedHostedSession(record) {
21579
+ return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
21580
+ }
21581
+ async cleanupMeshSessions(args) {
21582
+ if (args.mode === "preserve") {
21583
+ return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
21584
+ }
21585
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
21586
+ const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
21587
+ const sessions = await this.deps.sessionHostControl.listSessions();
21588
+ const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
21589
+ const hasExplicitSessionIds = !!requestedSessionIds?.size;
21590
+ const stoppedSessionIds = [];
21591
+ const deletedSessionIds = [];
21592
+ const skippedSessionIds = [];
21593
+ const skippedLiveSessionIds = [];
21594
+ const deleteUnsupportedSessionIds = [];
21595
+ const recordsRemainSessionIds = [];
21596
+ const errors = [];
21597
+ const matchedBySurfaceKind = {
21598
+ live_runtime: 0,
21599
+ recovery_snapshot: 0,
21600
+ inactive_record: 0
21601
+ };
21602
+ for (const record of matched) {
21603
+ const surfaceKind = getSessionHostSurfaceKind(record);
21604
+ matchedBySurfaceKind[surfaceKind] += 1;
21605
+ }
21606
+ for (const record of matched) {
21607
+ const sessionId = String(record.sessionId);
21608
+ const completed = this.isCompletedHostedSession(record);
21609
+ const surfaceKind = getSessionHostSurfaceKind(record);
21610
+ const liveRuntime = surfaceKind === "live_runtime";
21611
+ if (!hasExplicitSessionIds && liveRuntime) {
21612
+ skippedSessionIds.push(sessionId);
21613
+ skippedLiveSessionIds.push(sessionId);
21614
+ continue;
21615
+ }
21616
+ try {
21617
+ if (args.mode === "stop") {
21618
+ if (!completed) {
21619
+ if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
21620
+ stoppedSessionIds.push(sessionId);
21621
+ } else {
21622
+ skippedSessionIds.push(sessionId);
21623
+ }
21624
+ continue;
21625
+ }
21626
+ if (args.mode === "delete_stopped") {
21627
+ if (completed) {
21628
+ if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
21629
+ deletedSessionIds.push(sessionId);
21630
+ } else {
21631
+ skippedSessionIds.push(sessionId);
21632
+ }
21633
+ continue;
21634
+ }
21635
+ if (args.mode === "stop_and_delete") {
21636
+ if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
21637
+ deletedSessionIds.push(sessionId);
21638
+ continue;
21639
+ }
21640
+ } catch (e) {
21641
+ const message = e?.message || String(e);
21642
+ if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
21643
+ deleteUnsupportedSessionIds.push(sessionId);
21644
+ recordsRemainSessionIds.push(sessionId);
21645
+ if (args.mode === "stop_and_delete" && !completed) {
21646
+ try {
21647
+ await this.deps.sessionHostControl.stopSession(sessionId);
21648
+ stoppedSessionIds.push(sessionId);
21649
+ } catch (stopError) {
21650
+ errors.push({ sessionId, error: stopError?.message || String(stopError) });
21651
+ continue;
21652
+ }
21653
+ }
21654
+ skippedSessionIds.push(sessionId);
21655
+ continue;
21656
+ }
21657
+ errors.push({ sessionId, error: message });
21658
+ }
21659
+ }
21660
+ const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
21661
+ return {
21662
+ success: errors.length === 0,
21663
+ mode: args.mode,
21664
+ dryRun: args.dryRun === true,
21665
+ matchedCount: matched.length,
21666
+ matchedBySurfaceKind,
21667
+ stoppedSessionIds,
21668
+ deletedSessionIds,
21669
+ skippedSessionIds,
21670
+ skippedLiveSessionIds,
21671
+ ...deleteUnsupported ? {
21672
+ deleteUnsupported: true,
21673
+ effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
21674
+ deleteUnsupportedSessionIds,
21675
+ recordsRemainSessionIds
21676
+ } : {},
21677
+ ...errors.length ? { errors } : {}
21678
+ };
21679
+ }
20717
21680
  async traceSessionHostAction(action, args, run, summarizeResult) {
20718
21681
  const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
20719
21682
  const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
@@ -20833,6 +21796,9 @@ var DaemonCommandRouter = class {
20833
21796
  async executeDaemonCommand(cmd, args) {
20834
21797
  switch (cmd) {
20835
21798
  // ─── CLI / ACP commands ───
21799
+ case "mesh_forward_event": {
21800
+ return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
21801
+ }
20836
21802
  case "launch_cli":
20837
21803
  case "stop_cli":
20838
21804
  case "set_cli_view_mode":
@@ -21377,7 +22343,26 @@ var DaemonCommandRouter = class {
21377
22343
  if (!name) return { success: false, error: "name required" };
21378
22344
  try {
21379
22345
  const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21380
- const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
22346
+ const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
22347
+ return { success: true, mesh };
22348
+ } catch (e) {
22349
+ return { success: false, error: e.message };
22350
+ }
22351
+ }
22352
+ case "update_mesh": {
22353
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22354
+ if (!meshId) return { success: false, error: "meshId required" };
22355
+ try {
22356
+ const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22357
+ const patch = {};
22358
+ if (typeof args?.name === "string") patch.name = args.name;
22359
+ if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
22360
+ if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
22361
+ if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
22362
+ if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
22363
+ const mesh = updateMesh2(meshId, patch);
22364
+ if (!mesh) return { success: false, error: "Mesh not found" };
22365
+ this.inlineMeshCache.set(meshId, mesh);
21381
22366
  return { success: true, mesh };
21382
22367
  } catch (e) {
21383
22368
  return { success: false, error: e.message };
@@ -21401,21 +22386,164 @@ var DaemonCommandRouter = class {
21401
22386
  if (!workspace) return { success: false, error: "workspace required" };
21402
22387
  try {
21403
22388
  const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21404
- const node = addNode3(meshId, { workspace });
22389
+ const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
22390
+ const readOnly = args?.readOnly === true;
22391
+ const policy = {
22392
+ ...readOnly ? { readOnly: true } : {},
22393
+ ...providerPriority.length ? { providerPriority } : {}
22394
+ };
22395
+ const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
21405
22396
  if (!node) return { success: false, error: "Mesh not found" };
21406
22397
  return { success: true, node };
21407
22398
  } catch (e) {
21408
22399
  return { success: false, error: e.message };
21409
22400
  }
21410
22401
  }
22402
+ case "update_mesh_node": {
22403
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22404
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
22405
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
22406
+ try {
22407
+ const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22408
+ const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
22409
+ if (Array.isArray(args?.providerPriority)) {
22410
+ const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
22411
+ delete policy.provider_priority;
22412
+ if (providerPriority.length) {
22413
+ policy.providerPriority = providerPriority;
22414
+ } else {
22415
+ delete policy.providerPriority;
22416
+ }
22417
+ }
22418
+ const node = updateNode2(meshId, nodeId, { policy });
22419
+ if (!node) return { success: false, error: "Mesh node not found" };
22420
+ return { success: true, node };
22421
+ } catch (e) {
22422
+ return { success: false, error: e.message };
22423
+ }
22424
+ }
22425
+ case "cleanup_mesh_sessions": {
22426
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22427
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
22428
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
22429
+ try {
22430
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22431
+ const mesh = meshRecord?.mesh;
22432
+ if (!mesh) return { success: false, error: "Mesh not found" };
22433
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
22434
+ if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
22435
+ const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
22436
+ const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
22437
+ const result = await this.cleanupMeshSessions({
22438
+ meshId,
22439
+ nodeId,
22440
+ node,
22441
+ mode,
22442
+ sessionIds,
22443
+ dryRun: args?.dryRun === true
22444
+ });
22445
+ return result;
22446
+ } catch (e) {
22447
+ return { success: false, error: e.message };
22448
+ }
22449
+ }
21411
22450
  case "remove_mesh_node": {
21412
22451
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21413
22452
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
21414
22453
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
21415
22454
  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 };
22455
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22456
+ const mesh = meshRecord?.mesh;
22457
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
22458
+ const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
22459
+ args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
22460
+ );
22461
+ let sessionCleanup;
22462
+ if (node && sessionCleanupMode !== "preserve") {
22463
+ sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
22464
+ if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
22465
+ }
22466
+ if (node?.isLocalWorktree && node.workspace) {
22467
+ try {
22468
+ const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
22469
+ const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
22470
+ if (repoRoot) {
22471
+ const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22472
+ await removeWorktree2(repoRoot, node.workspace);
22473
+ }
22474
+ } catch (e) {
22475
+ LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
22476
+ }
22477
+ }
22478
+ let removed = false;
22479
+ if (meshRecord?.inline) {
22480
+ removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
22481
+ } else {
22482
+ const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22483
+ removed = removeNode3(meshId, nodeId);
22484
+ }
22485
+ return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
22486
+ } catch (e) {
22487
+ return { success: false, error: e.message };
22488
+ }
22489
+ }
22490
+ case "clone_mesh_node": {
22491
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22492
+ const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
22493
+ const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
22494
+ const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
22495
+ if (!meshId) return { success: false, error: "meshId required" };
22496
+ if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
22497
+ if (!branch) return { success: false, error: "branch required" };
22498
+ try {
22499
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22500
+ const mesh = meshRecord?.mesh;
22501
+ if (!mesh) return { success: false, error: "Mesh not found" };
22502
+ const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
22503
+ if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
22504
+ const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
22505
+ const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22506
+ const result = await createWorktree2({
22507
+ repoRoot,
22508
+ branch,
22509
+ baseBranch,
22510
+ meshName: mesh.name
22511
+ });
22512
+ let node;
22513
+ if (meshRecord.inline) {
22514
+ const { randomUUID: randomUUID8 } = await import("crypto");
22515
+ node = {
22516
+ id: `node_${randomUUID8().replace(/-/g, "")}`,
22517
+ workspace: result.worktreePath,
22518
+ repoRoot: result.worktreePath,
22519
+ daemonId: sourceNode.daemonId,
22520
+ userOverrides: { ...sourceNode.userOverrides || {} },
22521
+ policy: { ...sourceNode.policy || {} },
22522
+ isLocalWorktree: true,
22523
+ worktreeBranch: result.branch,
22524
+ clonedFromNodeId: sourceNodeId
22525
+ };
22526
+ this.updateInlineMeshNode(meshId, mesh, node);
22527
+ } else {
22528
+ const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22529
+ node = addNode3(meshId, {
22530
+ workspace: result.worktreePath,
22531
+ repoRoot: result.worktreePath,
22532
+ daemonId: sourceNode.daemonId,
22533
+ userOverrides: { ...sourceNode.userOverrides || {} },
22534
+ isLocalWorktree: true,
22535
+ worktreeBranch: result.branch,
22536
+ clonedFromNodeId: sourceNodeId,
22537
+ policy: { ...sourceNode.policy || {} }
22538
+ });
22539
+ if (!node) return { success: false, error: "Failed to register worktree node" };
22540
+ }
22541
+ return {
22542
+ success: true,
22543
+ node,
22544
+ worktreePath: result.worktreePath,
22545
+ branch: result.branch
22546
+ };
21419
22547
  } catch (e) {
21420
22548
  return { success: false, error: e.message };
21421
22549
  }
@@ -21423,7 +22551,7 @@ var DaemonCommandRouter = class {
21423
22551
  // ─── Mesh Coordinator Launch ───
21424
22552
  case "launch_mesh_coordinator": {
21425
22553
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21426
- const cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "claude-cli";
22554
+ let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
21427
22555
  if (!meshId) return { success: false, error: "meshId required" };
21428
22556
  try {
21429
22557
  const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
@@ -21451,9 +22579,29 @@ var DaemonCommandRouter = class {
21451
22579
  }
21452
22580
  const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
21453
22581
  if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
22582
+ if (!cliType) {
22583
+ const resolved = await resolveProviderTypeFromPriority({
22584
+ nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
22585
+ providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
22586
+ providerLoader: this.deps.providerLoader,
22587
+ onStatusChange: this.deps.onStatusChange
22588
+ });
22589
+ if (!resolved.providerType) {
22590
+ return {
22591
+ success: false,
22592
+ code: "mesh_coordinator_provider_priority_unusable",
22593
+ error: resolved.error || "No usable provider found from node providerPriority",
22594
+ meshId,
22595
+ cliType,
22596
+ workspace
22597
+ };
22598
+ }
22599
+ cliType = resolved.providerType;
22600
+ }
21454
22601
  const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
21455
22602
  const coordinatorSetup = resolveMeshCoordinatorSetup({
21456
22603
  provider: providerMeta,
22604
+ cliType,
21457
22605
  meshId,
21458
22606
  workspace
21459
22607
  });
@@ -21478,7 +22626,8 @@ var DaemonCommandRouter = class {
21478
22626
  meshCoordinatorSetup: coordinatorSetup
21479
22627
  };
21480
22628
  }
21481
- if (coordinatorSetup.configFormat !== "claude_mcp_json") {
22629
+ const configFormat = coordinatorSetup.configFormat;
22630
+ if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
21482
22631
  return {
21483
22632
  success: false,
21484
22633
  code: "mesh_coordinator_unsupported",
@@ -21488,17 +22637,34 @@ var DaemonCommandRouter = class {
21488
22637
  workspace
21489
22638
  };
21490
22639
  }
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
- }
22640
+ let systemPrompt = "";
22641
+ try {
22642
+ systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
22643
+ } catch (error) {
22644
+ const message = error?.message || String(error);
22645
+ LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
22646
+ return {
22647
+ success: false,
22648
+ code: "mesh_coordinator_prompt_failed",
22649
+ error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
22650
+ meshId,
22651
+ cliType,
22652
+ workspace
22653
+ };
21501
22654
  }
22655
+ const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
22656
+ const { dirname: dirname9 } = await import("path");
22657
+ const mcpConfigPath = coordinatorSetup.configPath;
22658
+ const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
22659
+ const returnManualFallback = (message) => ({
22660
+ success: false,
22661
+ code: "mesh_coordinator_manual_mcp_setup_required",
22662
+ error: message,
22663
+ meshId,
22664
+ cliType,
22665
+ workspace,
22666
+ meshCoordinatorSetup: hermesManualFallback
22667
+ });
21502
22668
  const mcpServerEntry = {
21503
22669
  command: coordinatorSetup.mcpServer.command,
21504
22670
  args: coordinatorSetup.mcpServer.args
@@ -21509,24 +22675,55 @@ var DaemonCommandRouter = class {
21509
22675
  ADHDEV_MCP_TRANSPORT: "ipc"
21510
22676
  };
21511
22677
  }
22678
+ try {
22679
+ mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
22680
+ } catch (error) {
22681
+ const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
22682
+ LOG.error("MeshCoordinator", message);
22683
+ if (hermesManualFallback) return returnManualFallback(message);
22684
+ return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
22685
+ }
22686
+ const hadExistingMcpConfig = existsSync23(mcpConfigPath);
22687
+ let existingMcpConfig = {};
22688
+ if (hadExistingMcpConfig) {
22689
+ try {
22690
+ existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
22691
+ copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
22692
+ } catch (error) {
22693
+ LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
22694
+ return {
22695
+ success: false,
22696
+ code: "mesh_coordinator_config_parse_failed",
22697
+ error: `Failed to parse existing MCP config at ${mcpConfigPath}`
22698
+ };
22699
+ }
22700
+ }
22701
+ const mcpServersKey = getMcpServersKey(configFormat);
22702
+ const existingServers = existingMcpConfig[mcpServersKey];
21512
22703
  const mcpConfig = {
21513
22704
  ...existingMcpConfig,
21514
- mcpServers: {
21515
- ...existingMcpConfig.mcpServers || {},
22705
+ [mcpServersKey]: {
22706
+ ...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
21516
22707
  [coordinatorSetup.serverName]: mcpServerEntry
21517
22708
  }
21518
22709
  };
21519
- writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
21520
- LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
21521
- let systemPrompt = "";
21522
22710
  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).`;
22711
+ writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
22712
+ } catch (error) {
22713
+ const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
22714
+ LOG.error("MeshCoordinator", message);
22715
+ if (hermesManualFallback) return returnManualFallback(message);
22716
+ return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
21526
22717
  }
22718
+ LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
21527
22719
  const cliArgs = [];
22720
+ const launchEnv = {};
21528
22721
  if (systemPrompt) {
21529
- cliArgs.push("--append-system-prompt", systemPrompt);
22722
+ if (configFormat === "hermes_config_yaml") {
22723
+ launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
22724
+ } else {
22725
+ cliArgs.push("--append-system-prompt", systemPrompt);
22726
+ }
21530
22727
  }
21531
22728
  if (cliType === "claude-cli") {
21532
22729
  cliArgs.push("--mcp-config", coordinatorSetup.configPath);
@@ -21535,6 +22732,7 @@ var DaemonCommandRouter = class {
21535
22732
  cliType,
21536
22733
  dir: workspace,
21537
22734
  cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
22735
+ env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
21538
22736
  settings: {
21539
22737
  meshCoordinatorFor: meshId
21540
22738
  }
@@ -21714,6 +22912,12 @@ var DaemonStatusReporter = class {
21714
22912
  if (providerType) {
21715
22913
  payload.providerType = providerType;
21716
22914
  }
22915
+ if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
22916
+ payload.providerSessionId = event.providerSessionId.trim();
22917
+ }
22918
+ if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
22919
+ payload.workspaceName = event.workspaceName.trim();
22920
+ }
21717
22921
  if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
21718
22922
  payload.duration = event.duration;
21719
22923
  }
@@ -21935,7 +23139,8 @@ function prepareSessionChatTailUpdate(input) {
21935
23139
  update: null
21936
23140
  };
21937
23141
  }
21938
- const messages = Array.isArray(result.messages) ? result.messages : [];
23142
+ const fullMessages = normalizeChatMessages(Array.isArray(result.messages) ? result.messages : []);
23143
+ const messages = filterUserFacingChatMessages(fullMessages);
21939
23144
  const title = typeof result.title === "string" ? result.title : void 0;
21940
23145
  const activeModal = normalizeChatTailActiveModal(result.activeModal);
21941
23146
  const status = typeof result.status === "string" ? result.status : "idle";
@@ -22961,7 +24166,10 @@ var ProviderInstanceManager = class {
22961
24166
  this.instances.get(id).dispose();
22962
24167
  }
22963
24168
  this.instances.set(id, instance);
22964
- await instance.init(context);
24169
+ await instance.init({
24170
+ ...context,
24171
+ emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
24172
+ });
22965
24173
  }
22966
24174
  /**
22967
24175
  * Instance remove
@@ -23123,6 +24331,17 @@ var ProviderInstanceManager = class {
23123
24331
  onEvent(listener) {
23124
24332
  this.eventListeners.push(listener);
23125
24333
  }
24334
+ emitProviderEvent(providerType, instanceId, event) {
24335
+ const payload = {
24336
+ ...event,
24337
+ providerType,
24338
+ instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
24339
+ targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
24340
+ };
24341
+ for (const listener of this.eventListeners) {
24342
+ listener(payload);
24343
+ }
24344
+ }
23126
24345
  emitPendingEvents(providerType, state, extra = {}) {
23127
24346
  for (const event of state.pendingEvents) {
23128
24347
  for (const listener of this.eventListeners) {
@@ -23195,11 +24414,11 @@ var ProviderInstanceManager = class {
23195
24414
 
23196
24415
  // src/providers/version-archive.ts
23197
24416
  import * as fs11 from "fs";
23198
- import * as path21 from "path";
23199
- import * as os19 from "os";
24417
+ import * as path22 from "path";
24418
+ import * as os20 from "os";
23200
24419
  import { execSync as execSync5 } from "child_process";
23201
24420
  import { platform as platform8 } from "os";
23202
- var ARCHIVE_PATH = path21.join(os19.homedir(), ".adhdev", "version-history.json");
24421
+ var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
23203
24422
  var MAX_ENTRIES_PER_PROVIDER = 20;
23204
24423
  var VersionArchive = class {
23205
24424
  history = {};
@@ -23246,7 +24465,7 @@ var VersionArchive = class {
23246
24465
  }
23247
24466
  save() {
23248
24467
  try {
23249
- fs11.mkdirSync(path21.dirname(ARCHIVE_PATH), { recursive: true });
24468
+ fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
23250
24469
  fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
23251
24470
  } catch {
23252
24471
  }
@@ -23302,8 +24521,8 @@ function getVersion(binary, versionCommand) {
23302
24521
  function checkPathExists2(paths) {
23303
24522
  for (const p of paths) {
23304
24523
  if (p.includes("*")) {
23305
- const home = os19.homedir();
23306
- const resolved = p.replace(/\*/g, home.split(path21.sep).pop() || "");
24524
+ const home = os20.homedir();
24525
+ const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
23307
24526
  if (fs11.existsSync(resolved)) return resolved;
23308
24527
  } else {
23309
24528
  if (fs11.existsSync(p)) return p;
@@ -23313,7 +24532,7 @@ function checkPathExists2(paths) {
23313
24532
  }
23314
24533
  function getMacAppVersion(appPath) {
23315
24534
  if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
23316
- const plistPath = path21.join(appPath, "Contents", "Info.plist");
24535
+ const plistPath = path22.join(appPath, "Contents", "Info.plist");
23317
24536
  if (!fs11.existsSync(plistPath)) return null;
23318
24537
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
23319
24538
  return raw || null;
@@ -23339,7 +24558,7 @@ async function detectAllVersions(loader, archive) {
23339
24558
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
23340
24559
  let resolvedBin = cliBin;
23341
24560
  if (!resolvedBin && appPath && currentOs === "darwin") {
23342
- const bundled = path21.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
24561
+ const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
23343
24562
  if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
23344
24563
  }
23345
24564
  info.installed = !!(appPath || resolvedBin);
@@ -23380,7 +24599,7 @@ async function detectAllVersions(loader, archive) {
23380
24599
  // src/daemon/dev-server.ts
23381
24600
  import * as http2 from "http";
23382
24601
  import * as fs15 from "fs";
23383
- import * as path25 from "path";
24602
+ import * as path26 from "path";
23384
24603
  init_config();
23385
24604
 
23386
24605
  // src/daemon/scaffold-template.ts
@@ -23732,7 +24951,7 @@ init_logger();
23732
24951
  // src/daemon/dev-cdp-handlers.ts
23733
24952
  init_logger();
23734
24953
  import * as fs12 from "fs";
23735
- import * as path22 from "path";
24954
+ import * as path23 from "path";
23736
24955
  async function handleCdpEvaluate(ctx, req, res) {
23737
24956
  const body = await ctx.readBody(req);
23738
24957
  const { expression, timeout, ideType } = body;
@@ -23910,17 +25129,17 @@ async function handleScriptHints(ctx, type, _req, res) {
23910
25129
  return;
23911
25130
  }
23912
25131
  let scriptsPath = "";
23913
- const directScripts = path22.join(dir, "scripts.js");
25132
+ const directScripts = path23.join(dir, "scripts.js");
23914
25133
  if (fs12.existsSync(directScripts)) {
23915
25134
  scriptsPath = directScripts;
23916
25135
  } else {
23917
- const scriptsDir = path22.join(dir, "scripts");
25136
+ const scriptsDir = path23.join(dir, "scripts");
23918
25137
  if (fs12.existsSync(scriptsDir)) {
23919
25138
  const versions = fs12.readdirSync(scriptsDir).filter((d) => {
23920
- return fs12.statSync(path22.join(scriptsDir, d)).isDirectory();
25139
+ return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
23921
25140
  }).sort().reverse();
23922
25141
  for (const ver of versions) {
23923
- const p = path22.join(scriptsDir, ver, "scripts.js");
25142
+ const p = path23.join(scriptsDir, ver, "scripts.js");
23924
25143
  if (fs12.existsSync(p)) {
23925
25144
  scriptsPath = p;
23926
25145
  break;
@@ -24749,7 +25968,7 @@ async function handleDomContext(ctx, type, req, res) {
24749
25968
 
24750
25969
  // src/daemon/dev-cli-debug.ts
24751
25970
  import * as fs13 from "fs";
24752
- import * as path23 from "path";
25971
+ import * as path24 from "path";
24753
25972
  function slugifyFixtureName(value) {
24754
25973
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
24755
25974
  return normalized || `fixture-${Date.now()}`;
@@ -24759,11 +25978,11 @@ function getCliFixtureDir(ctx, type) {
24759
25978
  if (!providerDir) {
24760
25979
  throw new Error(`Provider directory not found for '${type}'`);
24761
25980
  }
24762
- return path23.join(providerDir, "fixtures");
25981
+ return path24.join(providerDir, "fixtures");
24763
25982
  }
24764
25983
  function readCliFixture(ctx, type, name) {
24765
25984
  const fixtureDir = getCliFixtureDir(ctx, type);
24766
- const filePath = path23.join(fixtureDir, `${name}.json`);
25985
+ const filePath = path24.join(fixtureDir, `${name}.json`);
24767
25986
  if (!fs13.existsSync(filePath)) {
24768
25987
  throw new Error(`Fixture not found: ${filePath}`);
24769
25988
  }
@@ -24931,7 +26150,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
24931
26150
  if (!adapter) return null;
24932
26151
  return { target, instance, adapter };
24933
26152
  }
24934
- function sleep(ms) {
26153
+ function sleep2(ms) {
24935
26154
  return new Promise((resolve16) => setTimeout(resolve16, ms));
24936
26155
  }
24937
26156
  async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
@@ -24948,7 +26167,7 @@ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
24948
26167
  return bundle;
24949
26168
  }
24950
26169
  }
24951
- await sleep(100);
26170
+ await sleep2(100);
24952
26171
  }
24953
26172
  return getCliTargetBundle(ctx, type, instanceId);
24954
26173
  }
@@ -25004,7 +26223,7 @@ async function runCliExerciseInternal(ctx, body) {
25004
26223
  const message = String(lastLaunchError.message || "");
25005
26224
  const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
25006
26225
  if (!retryable || attempt === 2) break;
25007
- await sleep(1e3);
26226
+ await sleep2(1e3);
25008
26227
  }
25009
26228
  }
25010
26229
  if (!launched) {
@@ -25067,16 +26286,16 @@ async function runCliExerciseInternal(ctx, body) {
25067
26286
  const modal = debug?.activeModal || trace?.activeModal || null;
25068
26287
  noteStatus(status);
25069
26288
  if (resolveActiveModalIfNeeded(status, modal)) {
25070
- await sleep(150);
26289
+ await sleep2(150);
25071
26290
  continue;
25072
26291
  }
25073
26292
  const startupParseGate = !!debug?.startupParseGate;
25074
26293
  if (status === "idle" && !startupParseGate) break;
25075
- await sleep(150);
26294
+ await sleep2(150);
25076
26295
  }
25077
26296
  ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
25078
26297
  while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
25079
- await sleep(150);
26298
+ await sleep2(150);
25080
26299
  bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
25081
26300
  if (!bundle) {
25082
26301
  throw new Error("CLI instance disappeared during exercise");
@@ -25530,7 +26749,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
25530
26749
  },
25531
26750
  notes: typeof body?.notes === "string" ? body.notes : void 0
25532
26751
  };
25533
- const filePath = path23.join(fixtureDir, `${name}.json`);
26752
+ const filePath = path24.join(fixtureDir, `${name}.json`);
25534
26753
  fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
25535
26754
  ctx.json(res, 200, {
25536
26755
  saved: true,
@@ -25554,7 +26773,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
25554
26773
  return;
25555
26774
  }
25556
26775
  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);
26776
+ const fullPath = path24.join(fixtureDir, file);
25558
26777
  try {
25559
26778
  const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
25560
26779
  return {
@@ -25690,8 +26909,8 @@ async function handleCliRaw(ctx, req, res) {
25690
26909
 
25691
26910
  // src/daemon/dev-auto-implement.ts
25692
26911
  import * as fs14 from "fs";
25693
- import * as path24 from "path";
25694
- import * as os20 from "os";
26912
+ import * as path25 from "path";
26913
+ import * as os21 from "os";
25695
26914
  function getAutoImplPid(ctx) {
25696
26915
  const pid = ctx.autoImplProcess?.pid;
25697
26916
  return typeof pid === "number" && pid > 0 ? pid : null;
@@ -25740,22 +26959,22 @@ function getLatestScriptVersionDir(scriptsDir) {
25740
26959
  if (!fs14.existsSync(scriptsDir)) return null;
25741
26960
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
25742
26961
  try {
25743
- return fs14.statSync(path24.join(scriptsDir, d)).isDirectory();
26962
+ return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
25744
26963
  } catch {
25745
26964
  return false;
25746
26965
  }
25747
26966
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
25748
26967
  if (versions.length === 0) return null;
25749
- return path24.join(scriptsDir, versions[0]);
26968
+ return path25.join(scriptsDir, versions[0]);
25750
26969
  }
25751
26970
  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}`)) {
26971
+ const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
26972
+ const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
26973
+ const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
26974
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
25756
26975
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
25757
26976
  }
25758
- if (path24.basename(desiredDir) !== type) {
26977
+ if (path25.basename(desiredDir) !== type) {
25759
26978
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
25760
26979
  }
25761
26980
  const sourceDir = ctx.findProviderDir(type);
@@ -25763,11 +26982,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
25763
26982
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
25764
26983
  }
25765
26984
  if (!fs14.existsSync(desiredDir)) {
25766
- fs14.mkdirSync(path24.dirname(desiredDir), { recursive: true });
26985
+ fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
25767
26986
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
25768
26987
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
25769
26988
  }
25770
- const providerJson = path24.join(desiredDir, "provider.json");
26989
+ const providerJson = path25.join(desiredDir, "provider.json");
25771
26990
  if (!fs14.existsSync(providerJson)) {
25772
26991
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
25773
26992
  }
@@ -25778,13 +26997,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
25778
26997
  const refDir = ctx.findProviderDir(referenceType);
25779
26998
  if (!refDir || !fs14.existsSync(refDir)) return {};
25780
26999
  const referenceScripts = {};
25781
- const scriptsDir = path24.join(refDir, "scripts");
27000
+ const scriptsDir = path25.join(refDir, "scripts");
25782
27001
  const latestDir = getLatestScriptVersionDir(scriptsDir);
25783
27002
  if (!latestDir) return referenceScripts;
25784
27003
  for (const file of fs14.readdirSync(latestDir)) {
25785
27004
  if (!file.endsWith(".js")) continue;
25786
27005
  try {
25787
- referenceScripts[file] = fs14.readFileSync(path24.join(latestDir, file), "utf-8");
27006
+ referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
25788
27007
  } catch {
25789
27008
  }
25790
27009
  }
@@ -25892,9 +27111,9 @@ async function handleAutoImplement(ctx, type, req, res) {
25892
27111
  });
25893
27112
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
25894
27113
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
25895
- const tmpDir = path24.join(os20.tmpdir(), "adhdev-autoimpl");
27114
+ const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
25896
27115
  if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
25897
- const promptFile = path24.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
27116
+ const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
25898
27117
  fs14.writeFileSync(promptFile, prompt, "utf-8");
25899
27118
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
25900
27119
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -26047,7 +27266,7 @@ async function handleAutoImplement(ctx, type, req, res) {
26047
27266
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
26048
27267
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
26049
27268
  let shellCmd;
26050
- const isWin = os20.platform() === "win32";
27269
+ const isWin = os21.platform() === "win32";
26051
27270
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
26052
27271
  const promptMode = autoImpl?.promptMode ?? "stdin";
26053
27272
  const extraArgs = autoImpl?.extraArgs ?? [];
@@ -26086,7 +27305,7 @@ async function handleAutoImplement(ctx, type, req, res) {
26086
27305
  try {
26087
27306
  const pty = __require("node-pty");
26088
27307
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
26089
- const isWin2 = os20.platform() === "win32";
27308
+ const isWin2 = os21.platform() === "win32";
26090
27309
  child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
26091
27310
  name: "xterm-256color",
26092
27311
  cols: 120,
@@ -26326,7 +27545,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26326
27545
  setMode: "set_mode.js"
26327
27546
  };
26328
27547
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26329
- const scriptsDir = path24.join(providerDir, "scripts");
27548
+ const scriptsDir = path25.join(providerDir, "scripts");
26330
27549
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
26331
27550
  if (latestScriptsDir) {
26332
27551
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26337,7 +27556,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26337
27556
  for (const file of fs14.readdirSync(latestScriptsDir)) {
26338
27557
  if (file.endsWith(".js") && targetFileNames.has(file)) {
26339
27558
  try {
26340
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27559
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26341
27560
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26342
27561
  lines.push("```javascript");
26343
27562
  lines.push(content);
@@ -26354,7 +27573,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26354
27573
  lines.push("");
26355
27574
  for (const file of refFiles) {
26356
27575
  try {
26357
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27576
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26358
27577
  lines.push(`### \`${file}\` \u{1F512}`);
26359
27578
  lines.push("```javascript");
26360
27579
  lines.push(content);
@@ -26395,10 +27614,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26395
27614
  lines.push("");
26396
27615
  }
26397
27616
  }
26398
- const docsDir = path24.join(providerDir, "../../docs");
27617
+ const docsDir = path25.join(providerDir, "../../docs");
26399
27618
  const loadGuide = (name) => {
26400
27619
  try {
26401
- const p = path24.join(docsDir, name);
27620
+ const p = path25.join(docsDir, name);
26402
27621
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
26403
27622
  } catch {
26404
27623
  }
@@ -26635,7 +27854,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26635
27854
  parseApproval: "parse_approval.js"
26636
27855
  };
26637
27856
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26638
- const scriptsDir = path24.join(providerDir, "scripts");
27857
+ const scriptsDir = path25.join(providerDir, "scripts");
26639
27858
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
26640
27859
  if (latestScriptsDir) {
26641
27860
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26647,7 +27866,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26647
27866
  if (!file.endsWith(".js")) continue;
26648
27867
  if (!targetFileNames.has(file)) continue;
26649
27868
  try {
26650
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27869
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26651
27870
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26652
27871
  lines.push("```javascript");
26653
27872
  lines.push(content);
@@ -26663,7 +27882,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26663
27882
  lines.push("");
26664
27883
  for (const file of refFiles) {
26665
27884
  try {
26666
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27885
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26667
27886
  lines.push(`### \`${file}\` \u{1F512}`);
26668
27887
  lines.push("```javascript");
26669
27888
  lines.push(content);
@@ -26696,10 +27915,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26696
27915
  lines.push("");
26697
27916
  }
26698
27917
  }
26699
- const docsDir = path24.join(providerDir, "../../docs");
27918
+ const docsDir = path25.join(providerDir, "../../docs");
26700
27919
  const loadGuide = (name) => {
26701
27920
  try {
26702
- const p = path24.join(docsDir, name);
27921
+ const p = path25.join(docsDir, name);
26703
27922
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
26704
27923
  } catch {
26705
27924
  }
@@ -27146,8 +28365,8 @@ var DevServer = class _DevServer {
27146
28365
  }
27147
28366
  getEndpointList() {
27148
28367
  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}`;
28368
+ const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
28369
+ return `${r.method.padEnd(5)} ${path27}`;
27151
28370
  });
27152
28371
  }
27153
28372
  async start(port = DEV_SERVER_PORT) {
@@ -27435,12 +28654,12 @@ var DevServer = class _DevServer {
27435
28654
  // ─── DevConsole SPA ───
27436
28655
  getConsoleDistDir() {
27437
28656
  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")
28657
+ path26.resolve(__dirname, "../../web-devconsole/dist"),
28658
+ path26.resolve(__dirname, "../../../web-devconsole/dist"),
28659
+ path26.join(process.cwd(), "packages/web-devconsole/dist")
27441
28660
  ];
27442
28661
  for (const dir of candidates) {
27443
- if (fs15.existsSync(path25.join(dir, "index.html"))) return dir;
28662
+ if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
27444
28663
  }
27445
28664
  return null;
27446
28665
  }
@@ -27450,7 +28669,7 @@ var DevServer = class _DevServer {
27450
28669
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
27451
28670
  return;
27452
28671
  }
27453
- const htmlPath = path25.join(distDir, "index.html");
28672
+ const htmlPath = path26.join(distDir, "index.html");
27454
28673
  try {
27455
28674
  const html = fs15.readFileSync(htmlPath, "utf-8");
27456
28675
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -27475,15 +28694,15 @@ var DevServer = class _DevServer {
27475
28694
  this.json(res, 404, { error: "Not found" });
27476
28695
  return;
27477
28696
  }
27478
- const safePath = path25.normalize(pathname).replace(/^\.\.\//, "");
27479
- const filePath = path25.join(distDir, safePath);
28697
+ const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
28698
+ const filePath = path26.join(distDir, safePath);
27480
28699
  if (!filePath.startsWith(distDir)) {
27481
28700
  this.json(res, 403, { error: "Forbidden" });
27482
28701
  return;
27483
28702
  }
27484
28703
  try {
27485
28704
  const content = fs15.readFileSync(filePath);
27486
- const ext = path25.extname(filePath);
28705
+ const ext = path26.extname(filePath);
27487
28706
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
27488
28707
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
27489
28708
  res.end(content);
@@ -27596,9 +28815,9 @@ var DevServer = class _DevServer {
27596
28815
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
27597
28816
  if (entry.isDirectory()) {
27598
28817
  files.push({ path: rel, size: 0, type: "dir" });
27599
- scan(path25.join(d, entry.name), rel);
28818
+ scan(path26.join(d, entry.name), rel);
27600
28819
  } else {
27601
- const stat2 = fs15.statSync(path25.join(d, entry.name));
28820
+ const stat2 = fs15.statSync(path26.join(d, entry.name));
27602
28821
  files.push({ path: rel, size: stat2.size, type: "file" });
27603
28822
  }
27604
28823
  }
@@ -27621,7 +28840,7 @@ var DevServer = class _DevServer {
27621
28840
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
27622
28841
  return;
27623
28842
  }
27624
- const fullPath = path25.resolve(dir, path25.normalize(filePath));
28843
+ const fullPath = path26.resolve(dir, path26.normalize(filePath));
27625
28844
  if (!fullPath.startsWith(dir)) {
27626
28845
  this.json(res, 403, { error: "Forbidden" });
27627
28846
  return;
@@ -27646,14 +28865,14 @@ var DevServer = class _DevServer {
27646
28865
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
27647
28866
  return;
27648
28867
  }
27649
- const fullPath = path25.resolve(dir, path25.normalize(filePath));
28868
+ const fullPath = path26.resolve(dir, path26.normalize(filePath));
27650
28869
  if (!fullPath.startsWith(dir)) {
27651
28870
  this.json(res, 403, { error: "Forbidden" });
27652
28871
  return;
27653
28872
  }
27654
28873
  try {
27655
28874
  if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
27656
- fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
28875
+ fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
27657
28876
  fs15.writeFileSync(fullPath, content, "utf-8");
27658
28877
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
27659
28878
  this.providerLoader.reload();
@@ -27670,7 +28889,7 @@ var DevServer = class _DevServer {
27670
28889
  return;
27671
28890
  }
27672
28891
  for (const name of ["scripts.js", "provider.json"]) {
27673
- const p = path25.join(dir, name);
28892
+ const p = path26.join(dir, name);
27674
28893
  if (fs15.existsSync(p)) {
27675
28894
  const source = fs15.readFileSync(p, "utf-8");
27676
28895
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -27691,8 +28910,8 @@ var DevServer = class _DevServer {
27691
28910
  this.json(res, 404, { error: `Provider not found: ${type}` });
27692
28911
  return;
27693
28912
  }
27694
- const target = fs15.existsSync(path25.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
27695
- const targetPath = path25.join(dir, target);
28913
+ const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
28914
+ const targetPath = path26.join(dir, target);
27696
28915
  try {
27697
28916
  if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
27698
28917
  fs15.writeFileSync(targetPath, source, "utf-8");
@@ -27839,7 +29058,7 @@ var DevServer = class _DevServer {
27839
29058
  }
27840
29059
  let targetDir;
27841
29060
  targetDir = this.providerLoader.getUserProviderDir(category, type);
27842
- const jsonPath = path25.join(targetDir, "provider.json");
29061
+ const jsonPath = path26.join(targetDir, "provider.json");
27843
29062
  if (fs15.existsSync(jsonPath)) {
27844
29063
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
27845
29064
  return;
@@ -27851,8 +29070,8 @@ var DevServer = class _DevServer {
27851
29070
  const createdFiles = ["provider.json"];
27852
29071
  if (result.files) {
27853
29072
  for (const [relPath, content] of Object.entries(result.files)) {
27854
- const fullPath = path25.join(targetDir, relPath);
27855
- fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
29073
+ const fullPath = path26.join(targetDir, relPath);
29074
+ fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
27856
29075
  fs15.writeFileSync(fullPath, content, "utf-8");
27857
29076
  createdFiles.push(relPath);
27858
29077
  }
@@ -27905,22 +29124,22 @@ var DevServer = class _DevServer {
27905
29124
  if (!fs15.existsSync(scriptsDir)) return null;
27906
29125
  const versions = fs15.readdirSync(scriptsDir).filter((d) => {
27907
29126
  try {
27908
- return fs15.statSync(path25.join(scriptsDir, d)).isDirectory();
29127
+ return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
27909
29128
  } catch {
27910
29129
  return false;
27911
29130
  }
27912
29131
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
27913
29132
  if (versions.length === 0) return null;
27914
- return path25.join(scriptsDir, versions[0]);
29133
+ return path26.join(scriptsDir, versions[0]);
27915
29134
  }
27916
29135
  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}`)) {
29136
+ const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
29137
+ const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
29138
+ const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
29139
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
27921
29140
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
27922
29141
  }
27923
- if (path25.basename(desiredDir) !== type) {
29142
+ if (path26.basename(desiredDir) !== type) {
27924
29143
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
27925
29144
  }
27926
29145
  const sourceDir = this.findProviderDir(type);
@@ -27928,11 +29147,11 @@ var DevServer = class _DevServer {
27928
29147
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
27929
29148
  }
27930
29149
  if (!fs15.existsSync(desiredDir)) {
27931
- fs15.mkdirSync(path25.dirname(desiredDir), { recursive: true });
29150
+ fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
27932
29151
  fs15.cpSync(sourceDir, desiredDir, { recursive: true });
27933
29152
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
27934
29153
  }
27935
- const providerJson = path25.join(desiredDir, "provider.json");
29154
+ const providerJson = path26.join(desiredDir, "provider.json");
27936
29155
  if (!fs15.existsSync(providerJson)) {
27937
29156
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
27938
29157
  }
@@ -27968,7 +29187,7 @@ var DevServer = class _DevServer {
27968
29187
  setMode: "set_mode.js"
27969
29188
  };
27970
29189
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
27971
- const scriptsDir = path25.join(providerDir, "scripts");
29190
+ const scriptsDir = path26.join(providerDir, "scripts");
27972
29191
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
27973
29192
  if (latestScriptsDir) {
27974
29193
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -27979,7 +29198,7 @@ var DevServer = class _DevServer {
27979
29198
  for (const file of fs15.readdirSync(latestScriptsDir)) {
27980
29199
  if (file.endsWith(".js") && targetFileNames.has(file)) {
27981
29200
  try {
27982
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29201
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
27983
29202
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
27984
29203
  lines.push("```javascript");
27985
29204
  lines.push(content);
@@ -27996,7 +29215,7 @@ var DevServer = class _DevServer {
27996
29215
  lines.push("");
27997
29216
  for (const file of refFiles) {
27998
29217
  try {
27999
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29218
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28000
29219
  lines.push(`### \`${file}\` \u{1F512}`);
28001
29220
  lines.push("```javascript");
28002
29221
  lines.push(content);
@@ -28037,10 +29256,10 @@ var DevServer = class _DevServer {
28037
29256
  lines.push("");
28038
29257
  }
28039
29258
  }
28040
- const docsDir = path25.join(providerDir, "../../docs");
29259
+ const docsDir = path26.join(providerDir, "../../docs");
28041
29260
  const loadGuide = (name) => {
28042
29261
  try {
28043
- const p = path25.join(docsDir, name);
29262
+ const p = path26.join(docsDir, name);
28044
29263
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
28045
29264
  } catch {
28046
29265
  }
@@ -28214,7 +29433,7 @@ var DevServer = class _DevServer {
28214
29433
  parseApproval: "parse_approval.js"
28215
29434
  };
28216
29435
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
28217
- const scriptsDir = path25.join(providerDir, "scripts");
29436
+ const scriptsDir = path26.join(providerDir, "scripts");
28218
29437
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
28219
29438
  if (latestScriptsDir) {
28220
29439
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -28226,7 +29445,7 @@ var DevServer = class _DevServer {
28226
29445
  if (!file.endsWith(".js")) continue;
28227
29446
  if (!targetFileNames.has(file)) continue;
28228
29447
  try {
28229
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29448
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28230
29449
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
28231
29450
  lines.push("```javascript");
28232
29451
  lines.push(content);
@@ -28242,7 +29461,7 @@ var DevServer = class _DevServer {
28242
29461
  lines.push("");
28243
29462
  for (const file of refFiles) {
28244
29463
  try {
28245
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29464
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28246
29465
  lines.push(`### \`${file}\` \u{1F512}`);
28247
29466
  lines.push("```javascript");
28248
29467
  lines.push(content);
@@ -28275,10 +29494,10 @@ var DevServer = class _DevServer {
28275
29494
  lines.push("");
28276
29495
  }
28277
29496
  }
28278
- const docsDir = path25.join(providerDir, "../../docs");
29497
+ const docsDir = path26.join(providerDir, "../../docs");
28279
29498
  const loadGuide = (name) => {
28280
29499
  try {
28281
- const p = path25.join(docsDir, name);
29500
+ const p = path26.join(docsDir, name);
28282
29501
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
28283
29502
  } catch {
28284
29503
  }
@@ -28969,29 +30188,58 @@ import {
28969
30188
  } from "@adhdev/session-host-core";
28970
30189
  var STARTUP_TIMEOUT_MS = DEFAULT_SESSION_HOST_READY_TIMEOUT_MS;
28971
30190
  var STARTUP_POLL_MS = 200;
28972
- async function canConnect(endpoint) {
30191
+ var SessionHostCompatibilityError = class extends Error {
30192
+ constructor(message) {
30193
+ super(message);
30194
+ this.name = "SessionHostCompatibilityError";
30195
+ }
30196
+ };
30197
+ function getMissingRequestTypes(diagnostics, requiredRequestTypes) {
30198
+ const supported = new Set(diagnostics?.supportedRequestTypes || []);
30199
+ return requiredRequestTypes.filter((requestType) => !supported.has(requestType));
30200
+ }
30201
+ async function assertRequiredRequestTypes(client, requiredRequestTypes) {
30202
+ if (requiredRequestTypes.length === 0) return;
30203
+ const response = await client.request({
30204
+ type: "get_host_diagnostics",
30205
+ payload: { includeSessions: false }
30206
+ });
30207
+ const missing = getMissingRequestTypes(response.success ? response.result : void 0, requiredRequestTypes);
30208
+ if (missing.length > 0) {
30209
+ const detail = response.success ? "" : ` (${response.error || "capability probe failed"})`;
30210
+ throw new SessionHostCompatibilityError(
30211
+ `Session host does not support required request types: ${missing.join(", ")}${detail}`
30212
+ );
30213
+ }
30214
+ }
30215
+ async function canConnect(endpoint, requiredRequestTypes = []) {
28973
30216
  const client = new SessionHostClient2({ endpoint });
28974
30217
  try {
28975
30218
  await client.connect();
28976
- await client.close();
30219
+ await assertRequiredRequestTypes(client, requiredRequestTypes);
28977
30220
  return true;
28978
- } catch {
30221
+ } catch (error) {
30222
+ if (error instanceof SessionHostCompatibilityError) throw error;
28979
30223
  return false;
30224
+ } finally {
30225
+ await client.close().catch(() => {
30226
+ });
28980
30227
  }
28981
30228
  }
28982
- async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
30229
+ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS, requiredRequestTypes = []) {
28983
30230
  const deadline = Date.now() + timeoutMs;
28984
30231
  while (Date.now() < deadline) {
28985
- if (await canConnect(endpoint)) return;
30232
+ if (await canConnect(endpoint, requiredRequestTypes)) return;
28986
30233
  await new Promise((resolve16) => setTimeout(resolve16, STARTUP_POLL_MS));
28987
30234
  }
28988
30235
  throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
28989
30236
  }
28990
30237
  async function ensureSessionHostReady(options) {
28991
30238
  const endpoint = getDefaultSessionHostEndpoint(options.appName || "adhdev");
28992
- if (await canConnect(endpoint)) return endpoint;
30239
+ const requiredRequestTypes = options.requiredRequestTypes || [];
30240
+ if (await canConnect(endpoint, requiredRequestTypes)) return endpoint;
28993
30241
  options.spawnHost();
28994
- await waitForReady(endpoint, options.timeoutMs);
30242
+ await waitForReady(endpoint, options.timeoutMs, requiredRequestTypes);
28995
30243
  return endpoint;
28996
30244
  }
28997
30245
  async function listHostedCliRuntimes(endpoint) {
@@ -29283,48 +30531,6 @@ var SessionRegistry = class {
29283
30531
  // src/boot/daemon-lifecycle.ts
29284
30532
  init_logger();
29285
30533
  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
30534
  async function initDaemonComponents(config) {
29329
30535
  installGlobalInterceptor();
29330
30536
  const appConfig = loadConfig();
@@ -29556,6 +30762,12 @@ export {
29556
30762
  AcpProviderInstance,
29557
30763
  AgentStreamPoller,
29558
30764
  BUILTIN_CHAT_MESSAGE_KINDS,
30765
+ CHAT_MESSAGE_ACTIVITY_SOURCES,
30766
+ CHAT_MESSAGE_AUDIENCES,
30767
+ CHAT_MESSAGE_INTERNAL_SOURCES,
30768
+ CHAT_MESSAGE_SOURCES,
30769
+ CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES,
30770
+ CHAT_MESSAGE_VISIBILITIES,
29559
30771
  CdpDomHandlers,
29560
30772
  CliProviderInstance,
29561
30773
  DAEMON_WS_PATH,
@@ -29618,6 +30830,7 @@ export {
29618
30830
  buildThoughtChatMessage,
29619
30831
  buildToolChatMessage,
29620
30832
  buildUserChatMessage,
30833
+ classifyChatMessageVisibility,
29621
30834
  classifyHotChatSessionsForSubscriptionFlush,
29622
30835
  clearDebugTrace,
29623
30836
  compareGitSnapshots,
@@ -29630,12 +30843,17 @@ export {
29630
30843
  createGitWorkspaceMonitor,
29631
30844
  createInteractionId,
29632
30845
  createMesh,
30846
+ createWorktree,
29633
30847
  deleteMesh,
29634
30848
  detectAllVersions,
29635
30849
  detectCLIs,
29636
30850
  detectIDEs,
29637
30851
  ensureSessionHostReady,
29638
30852
  execNpmCommandSync,
30853
+ filterActivityChatMessages,
30854
+ filterChatMessagesByVisibility,
30855
+ filterInternalChatMessages,
30856
+ filterUserFacingChatMessages,
29639
30857
  findCdpManager,
29640
30858
  flattenMessageParts,
29641
30859
  forwardAgentStreamsToIdeInstance,
@@ -29666,22 +30884,26 @@ export {
29666
30884
  initDaemonComponents,
29667
30885
  installExtensions,
29668
30886
  installGlobalInterceptor,
30887
+ isActivityChatMessage,
29669
30888
  isBuiltinChatMessageKind,
29670
30889
  isCdpConnected,
29671
30890
  isExtensionInstalled,
29672
30891
  isGitCommandName,
29673
30892
  isIdeRunning,
30893
+ isInternalChatMessage,
29674
30894
  isManagedStatusWaiting,
29675
30895
  isManagedStatusWorking,
29676
30896
  isPathInside,
29677
30897
  isSessionHostLiveRuntime,
29678
30898
  isSessionHostRecoverySnapshot,
29679
30899
  isSetupComplete,
30900
+ isUserFacingChatMessage,
29680
30901
  killIdeProcess,
29681
30902
  launchIDE,
29682
30903
  launchWithCdp,
29683
30904
  listHostedCliRuntimes,
29684
30905
  listMeshes,
30906
+ listWorktrees,
29685
30907
  loadConfig,
29686
30908
  loadState,
29687
30909
  logCommand,
@@ -29701,6 +30923,7 @@ export {
29701
30923
  normalizeSessionModalFields,
29702
30924
  parsePorcelainV2Status,
29703
30925
  parseProviderSourceConfigUpdate,
30926
+ parseWorktreeListOutput,
29704
30927
  partitionSessionHostDiagnosticsSessions,
29705
30928
  partitionSessionHostRecords,
29706
30929
  prepareSessionChatTailUpdate,
@@ -29710,6 +30933,7 @@ export {
29710
30933
  recordDebugTrace,
29711
30934
  registerExtensionProviders,
29712
30935
  removeNode,
30936
+ removeWorktree,
29713
30937
  resetConfig,
29714
30938
  resetDebugRuntimeConfig,
29715
30939
  resetState,
@@ -29719,6 +30943,7 @@ export {
29719
30943
  resolveGitRepository,
29720
30944
  resolveSessionHostAppName,
29721
30945
  resolveSessionHostAppNameResolution,
30946
+ resolveWorktreePath,
29722
30947
  runAsyncBatch,
29723
30948
  runGit,
29724
30949
  saveConfig,