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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -1
  2. package/dist/cli-adapters/provider-cli-runtime.d.ts +1 -0
  3. package/dist/commands/cli-manager.d.ts +17 -4
  4. package/dist/commands/mesh-coordinator.d.ts +2 -0
  5. package/dist/commands/router.d.ts +11 -0
  6. package/dist/config/mesh-config.d.ts +3 -0
  7. package/dist/git/git-types.d.ts +1 -1
  8. package/dist/git/git-worktree.d.ts +64 -0
  9. package/dist/git/index.d.ts +2 -0
  10. package/dist/index.js +1382 -430
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +1409 -461
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/mesh/coordinator-prompt.d.ts +1 -0
  15. package/dist/mesh/mesh-events.d.ts +9 -0
  16. package/dist/providers/chat-message-normalization.d.ts +11 -0
  17. package/dist/providers/cli-provider-instance.d.ts +3 -0
  18. package/dist/providers/provider-instance-manager.d.ts +1 -0
  19. package/dist/providers/provider-instance.d.ts +2 -0
  20. package/dist/repo-mesh-types.d.ts +13 -0
  21. package/dist/shared-types.d.ts +4 -0
  22. package/package.json +4 -5
  23. package/src/cli-adapters/provider-cli-adapter.ts +28 -7
  24. package/src/cli-adapters/provider-cli-runtime.ts +3 -2
  25. package/src/commands/chat-commands.ts +94 -8
  26. package/src/commands/cli-manager.ts +78 -5
  27. package/src/commands/handler.ts +13 -4
  28. package/src/commands/mesh-coordinator.ts +149 -6
  29. package/src/commands/router.d.ts +1 -0
  30. package/src/commands/router.ts +554 -34
  31. package/src/config/mesh-config.ts +23 -2
  32. package/src/git/git-commands.ts +5 -1
  33. package/src/git/git-types.ts +1 -0
  34. package/src/git/git-worktree.ts +214 -0
  35. package/src/git/index.ts +14 -0
  36. package/src/mesh/coordinator-prompt.ts +25 -10
  37. package/src/mesh/mesh-events.ts +109 -43
  38. package/src/providers/chat-message-normalization.ts +54 -0
  39. package/src/providers/cli-provider-instance.d.ts +2 -0
  40. package/src/providers/cli-provider-instance.ts +55 -7
  41. package/src/providers/provider-instance-manager.ts +20 -1
  42. package/src/providers/provider-instance.ts +2 -0
  43. package/src/repo-mesh-types.ts +15 -0
  44. package/src/shared-types.ts +4 -0
  45. package/src/status/builders.ts +17 -12
  46. package/src/status/reporter.ts +6 -0
package/dist/index.mjs CHANGED
@@ -36,11 +36,140 @@ var init_repo_mesh_types = __esm({
36
36
  requireApprovalForPush: true,
37
37
  requireApprovalForDestructiveGit: true,
38
38
  dirtyWorkspaceBehavior: "warn",
39
- maxParallelTasks: 2
39
+ maxParallelTasks: 2,
40
+ sessionCleanupOnNodeRemove: "preserve"
40
41
  };
41
42
  }
42
43
  });
43
44
 
45
+ // src/git/git-worktree.ts
46
+ var git_worktree_exports = {};
47
+ __export(git_worktree_exports, {
48
+ createWorktree: () => createWorktree,
49
+ listWorktrees: () => listWorktrees,
50
+ parseWorktreeListOutput: () => parseWorktreeListOutput,
51
+ removeWorktree: () => removeWorktree,
52
+ resolveWorktreePath: () => resolveWorktreePath
53
+ });
54
+ import * as path4 from "path";
55
+ import { mkdir } from "fs/promises";
56
+ import { existsSync } from "fs";
57
+ import { execFile as execFile2 } from "child_process";
58
+ import { promisify as promisify2 } from "util";
59
+ function resolveWorktreePath(repoRoot, meshName, branch) {
60
+ const safeBranch = branch.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
61
+ const safeMeshName = meshName.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
62
+ const parentDir = path4.dirname(repoRoot);
63
+ return path4.join(parentDir, WORKTREE_DIR_NAME, safeMeshName, safeBranch);
64
+ }
65
+ async function createWorktree(opts) {
66
+ const { repoRoot, branch, baseBranch, meshName } = opts;
67
+ const targetDir = opts.targetDir || resolveWorktreePath(repoRoot, meshName, branch);
68
+ if (existsSync(targetDir)) {
69
+ throw new Error(`Worktree target directory already exists: ${targetDir}`);
70
+ }
71
+ await mkdir(path4.dirname(targetDir), { recursive: true });
72
+ const args = ["worktree", "add", targetDir, "-b", branch];
73
+ if (baseBranch) {
74
+ args.push(baseBranch);
75
+ }
76
+ try {
77
+ await execFileAsync2("git", args, {
78
+ cwd: repoRoot,
79
+ encoding: "utf8",
80
+ timeout: GIT_TIMEOUT_MS,
81
+ maxBuffer: GIT_MAX_BUFFER,
82
+ windowsHide: true
83
+ });
84
+ } catch (error) {
85
+ const stderr = typeof error.stderr === "string" ? error.stderr : "";
86
+ if (/already exists/i.test(stderr)) {
87
+ throw new Error(`Branch '${branch}' already exists or is checked out in another worktree`);
88
+ }
89
+ throw new Error(`git worktree add failed: ${stderr.trim() || error.message}`);
90
+ }
91
+ return {
92
+ success: true,
93
+ worktreePath: targetDir,
94
+ branch
95
+ };
96
+ }
97
+ async function removeWorktree(repoRoot, worktreePath) {
98
+ if (!existsSync(worktreePath)) {
99
+ await pruneWorktrees(repoRoot);
100
+ return { success: true, removedPath: worktreePath };
101
+ }
102
+ try {
103
+ await execFileAsync2("git", ["worktree", "remove", worktreePath, "--force"], {
104
+ cwd: repoRoot,
105
+ encoding: "utf8",
106
+ timeout: GIT_TIMEOUT_MS,
107
+ maxBuffer: GIT_MAX_BUFFER,
108
+ windowsHide: true
109
+ });
110
+ } catch (error) {
111
+ const stderr = typeof error.stderr === "string" ? error.stderr : "";
112
+ throw new Error(`git worktree remove failed: ${stderr.trim() || error.message}`);
113
+ }
114
+ return { success: true, removedPath: worktreePath };
115
+ }
116
+ async function listWorktrees(repoRoot) {
117
+ const { stdout } = await execFileAsync2("git", ["worktree", "list", "--porcelain"], {
118
+ cwd: repoRoot,
119
+ encoding: "utf8",
120
+ timeout: GIT_TIMEOUT_MS,
121
+ maxBuffer: GIT_MAX_BUFFER,
122
+ windowsHide: true
123
+ });
124
+ return parseWorktreeListOutput(stdout);
125
+ }
126
+ function parseWorktreeListOutput(output) {
127
+ const entries = [];
128
+ const blocks = output.trim().split(/\n\n+/);
129
+ for (const block of blocks) {
130
+ if (!block.trim()) continue;
131
+ const lines = block.trim().split("\n");
132
+ const entry = { path: "", head: "", branch: null, bare: false };
133
+ for (const line of lines) {
134
+ if (line.startsWith("worktree ")) {
135
+ entry.path = line.slice("worktree ".length).trim();
136
+ } else if (line.startsWith("HEAD ")) {
137
+ entry.head = line.slice("HEAD ".length).trim();
138
+ } else if (line.startsWith("branch ")) {
139
+ const ref = line.slice("branch ".length).trim();
140
+ entry.branch = ref.replace(/^refs\/heads\//, "");
141
+ } else if (line === "bare") {
142
+ entry.bare = true;
143
+ }
144
+ }
145
+ if (entry.path) {
146
+ entries.push(entry);
147
+ }
148
+ }
149
+ return entries;
150
+ }
151
+ async function pruneWorktrees(repoRoot) {
152
+ try {
153
+ await execFileAsync2("git", ["worktree", "prune"], {
154
+ cwd: repoRoot,
155
+ encoding: "utf8",
156
+ timeout: GIT_TIMEOUT_MS,
157
+ windowsHide: true
158
+ });
159
+ } catch {
160
+ }
161
+ }
162
+ var execFileAsync2, WORKTREE_DIR_NAME, GIT_TIMEOUT_MS, GIT_MAX_BUFFER;
163
+ var init_git_worktree = __esm({
164
+ "src/git/git-worktree.ts"() {
165
+ "use strict";
166
+ execFileAsync2 = promisify2(execFile2);
167
+ WORKTREE_DIR_NAME = ".adhdev-worktrees";
168
+ GIT_TIMEOUT_MS = 3e4;
169
+ GIT_MAX_BUFFER = 4 * 1024 * 1024;
170
+ }
171
+ });
172
+
44
173
  // src/config/config.ts
45
174
  var config_exports = {};
46
175
  __export(config_exports, {
@@ -56,8 +185,8 @@ __export(config_exports, {
56
185
  updateConfig: () => updateConfig
57
186
  });
58
187
  import { homedir } from "os";
59
- import { join } from "path";
60
- import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
188
+ import { join as join2 } from "path";
189
+ import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
61
190
  import { randomUUID } from "crypto";
62
191
  function resolveProviderSourceMode(providerSourceMode, legacyDisableUpstream) {
63
192
  if (providerSourceMode === "normal" || providerSourceMode === "no-upstream") {
@@ -151,18 +280,18 @@ function ensureMachineId(config) {
151
280
  };
152
281
  }
153
282
  function getConfigDir() {
154
- const dir = join(homedir(), ".adhdev");
155
- if (!existsSync(dir)) {
283
+ const dir = join2(homedir(), ".adhdev");
284
+ if (!existsSync2(dir)) {
156
285
  mkdirSync(dir, { recursive: true });
157
286
  }
158
287
  return dir;
159
288
  }
160
289
  function getConfigPath() {
161
- return join(getConfigDir(), "config.json");
290
+ return join2(getConfigDir(), "config.json");
162
291
  }
163
292
  function migrateStateToStateFile(raw) {
164
- const statePath = join(getConfigDir(), "state.json");
165
- if (existsSync(statePath)) return;
293
+ const statePath = join2(getConfigDir(), "state.json");
294
+ if (existsSync2(statePath)) return;
166
295
  const recentActivity = Array.isArray(raw.recentActivity) ? raw.recentActivity : [];
167
296
  const savedProviderSessions = Array.isArray(raw.savedProviderSessions) ? raw.savedProviderSessions : [];
168
297
  const legacySessionReads = isPlainObject(raw.recentSessionReads) ? raw.recentSessionReads : {};
@@ -186,7 +315,7 @@ function migrateStateToStateFile(raw) {
186
315
  }
187
316
  function loadConfig() {
188
317
  const configPath = getConfigPath();
189
- if (!existsSync(configPath)) {
318
+ if (!existsSync2(configPath)) {
190
319
  const initialized = ensureMachineId({ ...DEFAULT_CONFIG });
191
320
  try {
192
321
  saveConfig(initialized.config);
@@ -217,7 +346,7 @@ function saveConfig(config) {
217
346
  const configPath = getConfigPath();
218
347
  const dir = getConfigDir();
219
348
  const normalized = normalizeConfig(config);
220
- if (!existsSync(dir)) {
349
+ if (!existsSync2(dir)) {
221
350
  mkdirSync(dir, { recursive: true, mode: 448 });
222
351
  }
223
352
  writeFileSync(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
@@ -295,17 +424,17 @@ __export(mesh_config_exports, {
295
424
  updateMesh: () => updateMesh,
296
425
  updateNode: () => updateNode
297
426
  });
298
- import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
299
- import { join as join3 } from "path";
427
+ import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
428
+ import { join as join4 } from "path";
300
429
  import { randomUUID as randomUUID3 } from "crypto";
301
430
  function getMeshConfigPath() {
302
- return join3(getConfigDir(), "meshes.json");
431
+ return join4(getConfigDir(), "meshes.json");
303
432
  }
304
433
  function loadMeshConfig() {
305
- const path26 = getMeshConfigPath();
306
- if (!existsSync3(path26)) return { meshes: [] };
434
+ const path27 = getMeshConfigPath();
435
+ if (!existsSync4(path27)) return { meshes: [] };
307
436
  try {
308
- const raw = JSON.parse(readFileSync2(path26, "utf-8"));
437
+ const raw = JSON.parse(readFileSync2(path27, "utf-8"));
309
438
  if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
310
439
  return raw;
311
440
  } catch {
@@ -313,16 +442,16 @@ function loadMeshConfig() {
313
442
  }
314
443
  }
315
444
  function saveMeshConfig(config) {
316
- const path26 = getMeshConfigPath();
317
- writeFileSync2(path26, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
445
+ const path27 = getMeshConfigPath();
446
+ writeFileSync2(path27, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
318
447
  }
319
448
  function normalizeRepoIdentity(remoteUrl) {
320
449
  let identity = remoteUrl.trim();
321
450
  if (identity.startsWith("http://") || identity.startsWith("https://")) {
322
451
  try {
323
452
  const url = new URL(identity);
324
- const path26 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
325
- return `${url.hostname}/${path26}`;
453
+ const path27 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
454
+ return `${url.hostname}/${path27}`;
326
455
  } catch {
327
456
  }
328
457
  }
@@ -330,6 +459,18 @@ function normalizeRepoIdentity(remoteUrl) {
330
459
  if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
331
460
  return identity;
332
461
  }
462
+ function mergeMeshPolicy(base, patch) {
463
+ const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
464
+ if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
465
+ policy.dirtyWorkspaceBehavior = "warn";
466
+ }
467
+ const maxParallelTasks = Number(policy.maxParallelTasks);
468
+ policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
469
+ if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
470
+ policy.sessionCleanupOnNodeRemove = "preserve";
471
+ }
472
+ return policy;
473
+ }
333
474
  function listMeshes() {
334
475
  return loadMeshConfig().meshes;
335
476
  }
@@ -353,7 +494,7 @@ function createMesh(opts) {
353
494
  repoIdentity,
354
495
  repoRemoteUrl: opts.repoRemoteUrl,
355
496
  defaultBranch: opts.defaultBranch,
356
- policy: { ...DEFAULT_MESH_POLICY, ...opts.policy },
497
+ policy: mergeMeshPolicy(void 0, opts.policy),
357
498
  coordinator: opts.coordinator || {},
358
499
  nodes: [],
359
500
  createdAt: now,
@@ -369,7 +510,7 @@ function updateMesh(meshId, opts) {
369
510
  if (!mesh) return void 0;
370
511
  if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
371
512
  if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
372
- if (opts.policy) mesh.policy = { ...mesh.policy, ...opts.policy };
513
+ if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
373
514
  if (opts.coordinator) mesh.coordinator = opts.coordinator;
374
515
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
375
516
  saveMeshConfig(config);
@@ -397,9 +538,12 @@ function addNode(meshId, opts) {
397
538
  id: `node_${randomUUID3().replace(/-/g, "")}`,
398
539
  workspace: opts.workspace.trim(),
399
540
  repoRoot: opts.repoRoot,
541
+ daemonId: opts.daemonId,
400
542
  userOverrides: opts.userOverrides || {},
401
543
  policy: opts.policy || {},
402
- isLocalWorktree: opts.isLocalWorktree
544
+ isLocalWorktree: opts.isLocalWorktree,
545
+ worktreeBranch: opts.worktreeBranch,
546
+ clonedFromNodeId: opts.clonedFromNodeId
403
547
  };
404
548
  mesh.nodes.push(node);
405
549
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -429,11 +573,13 @@ function updateNode(meshId, nodeId, opts) {
429
573
  saveMeshConfig(config);
430
574
  return node;
431
575
  }
576
+ var SESSION_CLEANUP_MODES;
432
577
  var init_mesh_config = __esm({
433
578
  "src/config/mesh-config.ts"() {
434
579
  "use strict";
435
580
  init_config();
436
581
  init_repo_mesh_types();
582
+ SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
437
583
  }
438
584
  });
439
585
 
@@ -443,7 +589,7 @@ __export(coordinator_prompt_exports, {
443
589
  buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
444
590
  });
445
591
  function buildCoordinatorSystemPrompt(ctx) {
446
- const { mesh, status, userInstruction } = ctx;
592
+ const { mesh, status, userInstruction, coordinatorCliType } = ctx;
447
593
  const sections = [];
448
594
  sections.push(`You are a **Repo Mesh Coordinator** \u2014 a technical team lead who orchestrates work across multiple agent sessions on a shared Git repository.
449
595
 
@@ -457,15 +603,15 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
457
603
  } else {
458
604
  sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
459
605
  }
460
- sections.push(buildPolicySection(mesh.policy));
606
+ sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
461
607
  sections.push(TOOLS_SECTION);
462
608
  sections.push(WORKFLOW_SECTION);
463
- sections.push(RULES_SECTION);
609
+ sections.push(buildRulesSection(coordinatorCliType));
464
610
  if (userInstruction) {
465
611
  sections.push(`## Additional Context
466
612
  ${userInstruction}`);
467
613
  }
468
- if (mesh.coordinator.systemPromptSuffix) {
614
+ if (mesh.coordinator?.systemPromptSuffix) {
469
615
  sections.push(mesh.coordinator.systemPromptSuffix);
470
616
  }
471
617
  return sections.join("\n\n");
@@ -510,10 +656,29 @@ function buildPolicySection(policy) {
510
656
  return `## Policy
511
657
  ${rules.join("\n")}`;
512
658
  }
513
- var TOOLS_SECTION, WORKFLOW_SECTION, RULES_SECTION;
659
+ function buildRulesSection(coordinatorCliType) {
660
+ const coordinatorNote = coordinatorCliType ? `
661
+ - **Coordinator runtime is not a delegation default.** This coordinator is running as \`${coordinatorCliType}\`, but delegated node sessions must follow the user's requested provider, not the coordinator's own runtime.` : "";
662
+ return `## Rules
663
+
664
+ - **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
665
+ - **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
666
+ - **Respect explicit provider requests.** If the user names an agent/provider, pass the matching provider type to \`mesh_launch_session\`: Hermes \u2192 \`hermes-cli\`, Claude Code/Claude \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`. Never substitute \`claude-cli\` just because the coordinator itself is Claude Code.
667
+ - **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
668
+ - **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
669
+ - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
670
+ - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
671
+ - **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
672
+ - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
673
+ - **Never fabricate tool results.** Always call the actual tool; never pretend you did.
674
+ - **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
675
+ - **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
676
+ }
677
+ var TOOLS_SECTION, WORKFLOW_SECTION;
514
678
  var init_coordinator_prompt = __esm({
515
679
  "src/mesh/coordinator-prompt.ts"() {
516
680
  "use strict";
681
+ init_repo_mesh_types();
517
682
  TOOLS_SECTION = `## Available Tools
518
683
 
519
684
  | Tool | Purpose |
@@ -525,36 +690,29 @@ var init_coordinator_prompt = __esm({
525
690
  | \`mesh_read_chat\` | Read an agent's recent messages to check progress |
526
691
  | \`mesh_git_status\` | Check git status on a specific node |
527
692
  | \`mesh_checkpoint\` | Create a git checkpoint on a node |
528
- | \`mesh_approve\` | Approve/reject a pending agent action |`;
693
+ | \`mesh_approve\` | Approve/reject a pending agent action |
694
+ | \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
695
+ | \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |`;
529
696
  WORKFLOW_SECTION = `## Orchestration Workflow
530
697
 
531
698
  1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
532
699
  2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
533
700
  3. **Delegate** \u2014 For each task:
534
701
  a. Pick the best node (consider: health, dirty state, current workload).
535
- b. If no session exists, call \`mesh_launch_session\` to start one.
536
- c. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
702
+ b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
703
+ c. If no session exists, call \`mesh_launch_session\` to start one.
704
+ d. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
537
705
  4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
538
706
  5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
539
707
  6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
540
- 7. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
541
- RULES_SECTION = `## Rules
542
-
543
- - **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
544
- - **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
545
- - **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
546
- - **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
547
- - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
548
- - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
549
- - **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
550
- - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
551
- - **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
708
+ 7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
709
+ 8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
552
710
  }
553
711
  });
554
712
 
555
713
  // src/logging/logger.ts
556
714
  import * as fs2 from "fs";
557
- import * as path9 from "path";
715
+ import * as path10 from "path";
558
716
  import * as os4 from "os";
559
717
  function setLogLevel(level) {
560
718
  currentLevel = level;
@@ -570,13 +728,13 @@ function getDaemonLogDir() {
570
728
  return LOG_DIR;
571
729
  }
572
730
  function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
573
- return path9.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
731
+ return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
574
732
  }
575
733
  function checkDateRotation() {
576
734
  const today = getDateStr();
577
735
  if (today !== currentDate) {
578
736
  currentDate = today;
579
- currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
737
+ currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
580
738
  cleanOldLogs();
581
739
  }
582
740
  }
@@ -590,7 +748,7 @@ function cleanOldLogs() {
590
748
  const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
591
749
  if (dateMatch && dateMatch[1] < cutoffStr) {
592
750
  try {
593
- fs2.unlinkSync(path9.join(LOG_DIR, file));
751
+ fs2.unlinkSync(path10.join(LOG_DIR, file));
594
752
  } catch {
595
753
  }
596
754
  }
@@ -713,7 +871,7 @@ var init_logger = __esm({
713
871
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
714
872
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
715
873
  currentLevel = "info";
716
- LOG_DIR = process.platform === "win32" ? path9.join(process.env.LOCALAPPDATA || process.env.APPDATA || path9.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path9.join(os4.homedir(), "Library", "Logs", "adhdev") : path9.join(os4.homedir(), ".local", "share", "adhdev", "logs");
874
+ LOG_DIR = process.platform === "win32" ? path10.join(process.env.LOCALAPPDATA || process.env.APPDATA || path10.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path10.join(os4.homedir(), "Library", "Logs", "adhdev") : path10.join(os4.homedir(), ".local", "share", "adhdev", "logs");
717
875
  MAX_LOG_SIZE = 5 * 1024 * 1024;
718
876
  MAX_LOG_DAYS = 7;
719
877
  try {
@@ -721,16 +879,16 @@ var init_logger = __esm({
721
879
  } catch {
722
880
  }
723
881
  currentDate = getDateStr();
724
- currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
882
+ currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
725
883
  cleanOldLogs();
726
884
  try {
727
- const oldLog = path9.join(LOG_DIR, "daemon.log");
885
+ const oldLog = path10.join(LOG_DIR, "daemon.log");
728
886
  if (fs2.existsSync(oldLog)) {
729
887
  const stat2 = fs2.statSync(oldLog);
730
888
  const oldDate = stat2.mtime.toISOString().slice(0, 10);
731
- fs2.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
889
+ fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
732
890
  }
733
- const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
891
+ const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
734
892
  if (fs2.existsSync(oldLogBackup)) {
735
893
  fs2.unlinkSync(oldLogBackup);
736
894
  }
@@ -762,7 +920,7 @@ var init_logger = __esm({
762
920
  }
763
921
  };
764
922
  interceptorInstalled = false;
765
- LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
923
+ LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
766
924
  }
767
925
  });
768
926
 
@@ -1171,7 +1329,7 @@ var init_pty_transport = __esm({
1171
1329
 
1172
1330
  // src/cli-adapters/provider-cli-shared.ts
1173
1331
  import * as os9 from "os";
1174
- import * as path13 from "path";
1332
+ import * as path14 from "path";
1175
1333
  import { execSync as execSync3 } from "child_process";
1176
1334
  function stripAnsi(str) {
1177
1335
  return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
@@ -1236,9 +1394,9 @@ function buildCliScreenSnapshot(text) {
1236
1394
  function findBinary(name) {
1237
1395
  const trimmed = String(name || "").trim();
1238
1396
  if (!trimmed) return trimmed;
1239
- const expanded = trimmed.startsWith("~") ? path13.join(os9.homedir(), trimmed.slice(1)) : trimmed;
1240
- if (path13.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
1241
- return path13.isAbsolute(expanded) ? expanded : path13.resolve(expanded);
1397
+ const expanded = trimmed.startsWith("~") ? path14.join(os9.homedir(), trimmed.slice(1)) : trimmed;
1398
+ if (path14.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
1399
+ return path14.isAbsolute(expanded) ? expanded : path14.resolve(expanded);
1242
1400
  }
1243
1401
  const isWin = os9.platform() === "win32";
1244
1402
  try {
@@ -1254,7 +1412,7 @@ function findBinary(name) {
1254
1412
  }
1255
1413
  }
1256
1414
  function isScriptBinary(binaryPath) {
1257
- if (!path13.isAbsolute(binaryPath)) return false;
1415
+ if (!path14.isAbsolute(binaryPath)) return false;
1258
1416
  try {
1259
1417
  const fs16 = __require("fs");
1260
1418
  const resolved = fs16.realpathSync(binaryPath);
@@ -1270,7 +1428,7 @@ function isScriptBinary(binaryPath) {
1270
1428
  }
1271
1429
  }
1272
1430
  function looksLikeMachOOrElf(filePath) {
1273
- if (!path13.isAbsolute(filePath)) return false;
1431
+ if (!path14.isAbsolute(filePath)) return false;
1274
1432
  try {
1275
1433
  const fs16 = __require("fs");
1276
1434
  const resolved = fs16.realpathSync(filePath);
@@ -1484,10 +1642,10 @@ var init_provider_cli_config = __esm({
1484
1642
 
1485
1643
  // src/cli-adapters/provider-cli-runtime.ts
1486
1644
  import * as os10 from "os";
1487
- import * as path14 from "path";
1645
+ import * as path15 from "path";
1488
1646
  import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from "@adhdev/session-host-core";
1489
1647
  function resolveCliSpawnPlan(options) {
1490
- const { provider, runtimeSettings, workingDir, extraArgs } = options;
1648
+ const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
1491
1649
  const { spawn: spawnConfig } = provider;
1492
1650
  const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
1493
1651
  const binaryPath = findBinary(configuredCommand);
@@ -1495,9 +1653,9 @@ function resolveCliSpawnPlan(options) {
1495
1653
  const allArgs = [...spawnConfig.args, ...extraArgs];
1496
1654
  let shellCmd;
1497
1655
  let shellArgs;
1498
- const useShellUnix = !isWin && (!!spawnConfig.shell || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1656
+ const useShellUnix = !isWin && (!!spawnConfig.shell || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1499
1657
  const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1500
- const useShellWin = !!spawnConfig.shell || isCmdShim || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1658
+ const useShellWin = !!spawnConfig.shell || isCmdShim || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
1501
1659
  const useShell = isWin ? useShellWin : useShellUnix;
1502
1660
  if (useShell) {
1503
1661
  shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
@@ -1511,7 +1669,7 @@ function resolveCliSpawnPlan(options) {
1511
1669
  shellCmd = binaryPath;
1512
1670
  shellArgs = allArgs;
1513
1671
  }
1514
- const env = buildCliSpawnEnv(process.env, spawnConfig.env);
1672
+ const env = buildCliSpawnEnv(process.env, { ...spawnConfig.env || {}, ...extraEnv || {} });
1515
1673
  env.TERMINAL_CWD = workingDir;
1516
1674
  return {
1517
1675
  binaryPath,
@@ -1610,8 +1768,9 @@ var init_provider_cli_adapter = __esm({
1610
1768
  init_provider_cli_runtime();
1611
1769
  init_provider_cli_shared();
1612
1770
  ProviderCliAdapter = class _ProviderCliAdapter {
1613
- constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
1771
+ constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
1614
1772
  this.extraArgs = extraArgs;
1773
+ this.extraEnv = extraEnv;
1615
1774
  this.provider = provider;
1616
1775
  this.transportFactory = transportFactory;
1617
1776
  this.cliType = provider.type;
@@ -1762,8 +1921,9 @@ var init_provider_cli_adapter = __esm({
1762
1921
  const currentSnapshot = normalizeScreenSnapshot(screenText);
1763
1922
  const lastSnapshot = this.lastScreenSnapshot;
1764
1923
  if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
1765
- const staleSnapshotLooksActive = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel/i.test(lastSnapshot);
1766
- const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:\n|\r|$)/.test(screenText) && !/\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel/i.test(screenText);
1924
+ const activeScreenPattern = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel|Enter to confirm\s*[·•-]\s*Esc to cancel|\b(?:MCP servers?|tool calls?)\b[^\n\r]{0,160}\brequire approval\b/i;
1925
+ const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
1926
+ const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
1767
1927
  if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
1768
1928
  if (currentSnapshot.length >= lastSnapshot.length) return screenText;
1769
1929
  return `${screenText}
@@ -1926,7 +2086,8 @@ ${lastSnapshot}`;
1926
2086
  provider: this.provider,
1927
2087
  runtimeSettings: this.runtimeSettings,
1928
2088
  workingDir: this.workingDir,
1929
- extraArgs: this.extraArgs
2089
+ extraArgs: this.extraArgs,
2090
+ extraEnv: this.extraEnv
1930
2091
  });
1931
2092
  LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
1932
2093
  this.resetTraceSession();
@@ -3124,9 +3285,8 @@ ${lastSnapshot}`;
3124
3285
  };
3125
3286
  this.recordTrace("submit_echo_missing", diagnostic);
3126
3287
  if (this.requirePromptEchoBeforeSubmit) {
3127
- const message = `${this.cliName} prompt echo was not observed on the PTY screen before submit`;
3128
- LOG.warn("CLI", `[${this.cliType}] ${message} elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
3129
- completion.rejectOnce(new Error(message));
3288
+ LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending guarded submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
3289
+ this.submitSendKey(state, completion);
3130
3290
  return;
3131
3291
  }
3132
3292
  LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
@@ -3173,7 +3333,14 @@ ${lastSnapshot}`;
3173
3333
  })() : null;
3174
3334
  const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
3175
3335
  if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
3176
- throw new Error(`${this.cliName} is still processing the previous prompt`);
3336
+ const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
3337
+ const parsedHasActionableModal = Boolean(
3338
+ parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
3339
+ );
3340
+ const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
3341
+ if (!terminalLooksIdle) {
3342
+ throw new Error(`${this.cliName} is still processing the previous prompt`);
3343
+ }
3177
3344
  }
3178
3345
  if (this.isWaitingForResponse && !allowInputDuringGeneration) {
3179
3346
  if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
@@ -4547,6 +4714,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
4547
4714
  "dirty_index_required",
4548
4715
  "conflict",
4549
4716
  "invalid_args",
4717
+ "nothing_to_commit",
4550
4718
  "git_command_failed"
4551
4719
  ]);
4552
4720
  function failure(reason, error) {
@@ -4791,7 +4959,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
4791
4959
  } catch (err) {
4792
4960
  const output = (err?.stdout || "") + (err?.stderr || "");
4793
4961
  if (/nothing to commit/i.test(output)) {
4794
- throw new GitCommandError("git_command_failed", "Nothing to commit");
4962
+ throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
4963
+ stdout: err?.stdout,
4964
+ stderr: err?.stderr
4965
+ });
4795
4966
  }
4796
4967
  throw err;
4797
4968
  }
@@ -4983,20 +5154,23 @@ var TurnSnapshotTracker = class {
4983
5154
  }
4984
5155
  };
4985
5156
 
5157
+ // src/git/index.ts
5158
+ init_git_worktree();
5159
+
4986
5160
  // src/index.ts
4987
5161
  init_config();
4988
5162
 
4989
5163
  // src/config/workspaces.ts
4990
5164
  import * as fs from "fs";
4991
5165
  import * as os from "os";
4992
- import * as path4 from "path";
5166
+ import * as path5 from "path";
4993
5167
  import { randomUUID as randomUUID2 } from "crypto";
4994
5168
  var MAX_WORKSPACES = 50;
4995
5169
  function expandPath(p) {
4996
5170
  const t = (p || "").trim();
4997
5171
  if (!t) return "";
4998
- if (t.startsWith("~")) return path4.join(os.homedir(), t.slice(1).replace(/^\//, ""));
4999
- return path4.resolve(t);
5172
+ if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
5173
+ return path5.resolve(t);
5000
5174
  }
5001
5175
  function validateWorkspacePath(absPath) {
5002
5176
  try {
@@ -5010,7 +5184,7 @@ function validateWorkspacePath(absPath) {
5010
5184
  }
5011
5185
  }
5012
5186
  function defaultWorkspaceLabel(absPath) {
5013
- const base = path4.basename(absPath) || absPath;
5187
+ const base = path5.basename(absPath) || absPath;
5014
5188
  return base;
5015
5189
  }
5016
5190
  function getDefaultWorkspacePath(config) {
@@ -5101,9 +5275,9 @@ function resolveIdeLaunchWorkspace(args, config) {
5101
5275
  return getDefaultWorkspacePath(config) || void 0;
5102
5276
  }
5103
5277
  function findWorkspaceByPath(config, rawPath) {
5104
- const abs = path4.resolve(expandPath(rawPath));
5278
+ const abs = path5.resolve(expandPath(rawPath));
5105
5279
  if (!abs) return void 0;
5106
- return (config.workspaces || []).find((w) => path4.resolve(expandPath(w.path)) === abs);
5280
+ return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
5107
5281
  }
5108
5282
  function addWorkspaceEntry(config, rawPath, label, options) {
5109
5283
  const abs = expandPath(rawPath);
@@ -5119,7 +5293,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
5119
5293
  const v = validateWorkspacePath(abs);
5120
5294
  if (!v.ok) return { error: v.error };
5121
5295
  const list = [...config.workspaces || []];
5122
- if (list.some((w) => path4.resolve(w.path) === abs)) {
5296
+ if (list.some((w) => path5.resolve(w.path) === abs)) {
5123
5297
  return { error: "Workspace already in list" };
5124
5298
  }
5125
5299
  if (list.length >= MAX_WORKSPACES) {
@@ -5153,7 +5327,7 @@ function setDefaultWorkspaceId(config, id) {
5153
5327
  }
5154
5328
 
5155
5329
  // src/config/recent-activity.ts
5156
- import * as path5 from "path";
5330
+ import * as path6 from "path";
5157
5331
 
5158
5332
  // src/providers/summary-metadata.ts
5159
5333
  function normalizeSummaryItem(item) {
@@ -5222,9 +5396,9 @@ var MAX_ACTIVITY = 30;
5222
5396
  function normalizeWorkspace(workspace) {
5223
5397
  if (!workspace) return "";
5224
5398
  try {
5225
- return path5.resolve(expandPath(workspace));
5399
+ return path6.resolve(expandPath(workspace));
5226
5400
  } catch {
5227
- return path5.resolve(workspace);
5401
+ return path6.resolve(workspace);
5228
5402
  }
5229
5403
  }
5230
5404
  function buildRecentActivityKey(entry) {
@@ -5392,14 +5566,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
5392
5566
  }
5393
5567
 
5394
5568
  // src/config/saved-sessions.ts
5395
- import * as path6 from "path";
5569
+ import * as path7 from "path";
5396
5570
  var MAX_SAVED_SESSIONS = 500;
5397
5571
  function normalizeWorkspace2(workspace) {
5398
5572
  if (!workspace) return "";
5399
5573
  try {
5400
- return path6.resolve(expandPath(workspace));
5574
+ return path7.resolve(expandPath(workspace));
5401
5575
  } catch {
5402
- return path6.resolve(workspace);
5576
+ return path7.resolve(workspace);
5403
5577
  }
5404
5578
  }
5405
5579
  function buildSavedProviderSessionKey(providerSessionId) {
@@ -5505,8 +5679,8 @@ async function syncMeshes(transport) {
5505
5679
 
5506
5680
  // src/config/state-store.ts
5507
5681
  init_config();
5508
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5509
- import { join as join4 } from "path";
5682
+ import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5683
+ import { join as join5 } from "path";
5510
5684
  var DEFAULT_STATE = {
5511
5685
  recentActivity: [],
5512
5686
  savedProviderSessions: [],
@@ -5519,7 +5693,7 @@ function isPlainObject2(value) {
5519
5693
  return !!value && typeof value === "object" && !Array.isArray(value);
5520
5694
  }
5521
5695
  function getStatePath() {
5522
- return join4(getConfigDir(), "state.json");
5696
+ return join5(getConfigDir(), "state.json");
5523
5697
  }
5524
5698
  function normalizeState(raw) {
5525
5699
  const parsed = isPlainObject2(raw) ? raw : {};
@@ -5555,7 +5729,7 @@ function normalizeState(raw) {
5555
5729
  }
5556
5730
  function loadState() {
5557
5731
  const statePath = getStatePath();
5558
- if (!existsSync4(statePath)) {
5732
+ if (!existsSync5(statePath)) {
5559
5733
  return { ...DEFAULT_STATE };
5560
5734
  }
5561
5735
  try {
@@ -5576,9 +5750,9 @@ function resetState() {
5576
5750
 
5577
5751
  // src/detection/ide-detector.ts
5578
5752
  import { execSync } from "child_process";
5579
- import { existsSync as existsSync5 } from "fs";
5753
+ import { existsSync as existsSync6 } from "fs";
5580
5754
  import { platform, homedir as homedir3 } from "os";
5581
- import * as path7 from "path";
5755
+ import * as path8 from "path";
5582
5756
  var BUILTIN_IDE_DEFINITIONS = [];
5583
5757
  var registeredIDEs = /* @__PURE__ */ new Map();
5584
5758
  function registerIDEDefinition(def) {
@@ -5597,10 +5771,10 @@ function getMergedDefinitions() {
5597
5771
  function findCliCommand(command) {
5598
5772
  const trimmed = String(command || "").trim();
5599
5773
  if (!trimmed) return null;
5600
- if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5601
- const candidate = trimmed.startsWith("~") ? path7.join(homedir3(), trimmed.slice(1)) : trimmed;
5602
- const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
5603
- return existsSync5(resolved) ? resolved : null;
5774
+ if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5775
+ const candidate = trimmed.startsWith("~") ? path8.join(homedir3(), trimmed.slice(1)) : trimmed;
5776
+ const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
5777
+ return existsSync6(resolved) ? resolved : null;
5604
5778
  }
5605
5779
  try {
5606
5780
  const result = execSync(
@@ -5627,31 +5801,31 @@ function getIdeVersion(cliCommand) {
5627
5801
  function checkPathExists(paths) {
5628
5802
  const home = homedir3();
5629
5803
  for (const p of paths) {
5630
- const normalized = p.startsWith("~") ? path7.join(home, p.slice(1)) : p;
5804
+ const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
5631
5805
  if (normalized.includes("*")) {
5632
5806
  const username = home.split(/[\\/]/).pop() || "";
5633
5807
  const resolved = normalized.replace("*", username);
5634
- if (existsSync5(resolved)) return resolved;
5808
+ if (existsSync6(resolved)) return resolved;
5635
5809
  } else {
5636
- if (existsSync5(normalized)) return normalized;
5810
+ if (existsSync6(normalized)) return normalized;
5637
5811
  }
5638
5812
  }
5639
5813
  return null;
5640
5814
  }
5641
5815
  async function detectIDEs(providerLoader) {
5642
- const os21 = platform();
5816
+ const os22 = platform();
5643
5817
  const results = [];
5644
5818
  for (const def of getMergedDefinitions()) {
5645
5819
  const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
5646
- const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os21] || []) || []);
5820
+ const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
5647
5821
  let resolvedCli = cliPath;
5648
- if (!resolvedCli && appPath && os21 === "darwin") {
5822
+ if (!resolvedCli && appPath && os22 === "darwin") {
5649
5823
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
5650
- if (existsSync5(bundledCli)) resolvedCli = bundledCli;
5824
+ if (existsSync6(bundledCli)) resolvedCli = bundledCli;
5651
5825
  }
5652
- if (!resolvedCli && appPath && os21 === "win32") {
5653
- const { dirname: dirname8 } = await import("path");
5654
- const appDir = dirname8(appPath);
5826
+ if (!resolvedCli && appPath && os22 === "win32") {
5827
+ const { dirname: dirname9 } = await import("path");
5828
+ const appDir = dirname9(appPath);
5655
5829
  const candidates = [
5656
5830
  `${appDir}\\\\bin\\\\${def.cli}.cmd`,
5657
5831
  `${appDir}\\\\bin\\\\${def.cli}`,
@@ -5660,13 +5834,13 @@ async function detectIDEs(providerLoader) {
5660
5834
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
5661
5835
  ];
5662
5836
  for (const c of candidates) {
5663
- if (existsSync5(c)) {
5837
+ if (existsSync6(c)) {
5664
5838
  resolvedCli = c;
5665
5839
  break;
5666
5840
  }
5667
5841
  }
5668
5842
  }
5669
- const installed = os21 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
5843
+ const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
5670
5844
  const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
5671
5845
  results.push({
5672
5846
  id: def.id,
@@ -5685,8 +5859,8 @@ async function detectIDEs(providerLoader) {
5685
5859
  // src/detection/cli-detector.ts
5686
5860
  import { exec } from "child_process";
5687
5861
  import * as os2 from "os";
5688
- import * as path8 from "path";
5689
- import { existsSync as existsSync6 } from "fs";
5862
+ import * as path9 from "path";
5863
+ import { existsSync as existsSync7 } from "fs";
5690
5864
  function parseVersion(raw) {
5691
5865
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
5692
5866
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
@@ -5698,19 +5872,19 @@ function shellQuote(value) {
5698
5872
  function expandHome(value) {
5699
5873
  const trimmed = value.trim();
5700
5874
  if (!trimmed.startsWith("~")) return trimmed;
5701
- return path8.join(os2.homedir(), trimmed.slice(1));
5875
+ return path9.join(os2.homedir(), trimmed.slice(1));
5702
5876
  }
5703
5877
  function isExplicitCommandPath(command) {
5704
5878
  const trimmed = command.trim();
5705
- return path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
5879
+ return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
5706
5880
  }
5707
5881
  function resolveCommandPath(command) {
5708
5882
  const trimmed = command.trim();
5709
5883
  if (!trimmed) return null;
5710
5884
  if (isExplicitCommandPath(trimmed)) {
5711
5885
  const expanded = expandHome(trimmed);
5712
- const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
5713
- return existsSync6(candidate) ? candidate : null;
5886
+ const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
5887
+ return existsSync7(candidate) ? candidate : null;
5714
5888
  }
5715
5889
  return null;
5716
5890
  }
@@ -7978,9 +8152,9 @@ ${cleanBody}`;
7978
8152
 
7979
8153
  // src/config/chat-history.ts
7980
8154
  import * as fs3 from "fs";
7981
- import * as path10 from "path";
8155
+ import * as path11 from "path";
7982
8156
  import * as os5 from "os";
7983
- var HISTORY_DIR = path10.join(os5.homedir(), ".adhdev", "history");
8157
+ var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
7984
8158
  var RETAIN_DAYS = 30;
7985
8159
  var SAVED_HISTORY_INDEX_VERSION = 1;
7986
8160
  var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
@@ -8143,7 +8317,7 @@ function extractSavedHistorySessionIdFromFile(file) {
8143
8317
  function buildSavedHistoryFileSignatureMap(dir, files) {
8144
8318
  return new Map(files.map((file) => {
8145
8319
  try {
8146
- const stat2 = fs3.statSync(path10.join(dir, file));
8320
+ const stat2 = fs3.statSync(path11.join(dir, file));
8147
8321
  return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
8148
8322
  } catch {
8149
8323
  return [file, `${file}:missing`];
@@ -8154,7 +8328,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
8154
8328
  return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
8155
8329
  }
8156
8330
  function getSavedHistoryIndexFilePath(dir) {
8157
- return path10.join(dir, SAVED_HISTORY_INDEX_FILE);
8331
+ return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
8158
8332
  }
8159
8333
  function getSavedHistoryIndexLockPath(dir) {
8160
8334
  return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
@@ -8256,7 +8430,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
8256
8430
  }
8257
8431
  for (const file of Array.from(currentEntries.keys())) {
8258
8432
  if (incomingFiles.has(file)) continue;
8259
- if (!fs3.existsSync(path10.join(dir, file))) {
8433
+ if (!fs3.existsSync(path11.join(dir, file))) {
8260
8434
  currentEntries.delete(file);
8261
8435
  }
8262
8436
  }
@@ -8282,7 +8456,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
8282
8456
  const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
8283
8457
  const files = listHistoryFiles(dir);
8284
8458
  for (const file of files) {
8285
- const stat2 = fs3.statSync(path10.join(dir, file));
8459
+ const stat2 = fs3.statSync(path11.join(dir, file));
8286
8460
  if (stat2.mtimeMs > indexStat.mtimeMs) return true;
8287
8461
  }
8288
8462
  return false;
@@ -8292,14 +8466,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
8292
8466
  }
8293
8467
  function buildSavedHistoryFileSignature(dir, file) {
8294
8468
  try {
8295
- const stat2 = fs3.statSync(path10.join(dir, file));
8469
+ const stat2 = fs3.statSync(path11.join(dir, file));
8296
8470
  return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
8297
8471
  } catch {
8298
8472
  return `${file}:missing`;
8299
8473
  }
8300
8474
  }
8301
8475
  function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
8302
- const filePath = path10.join(dir, file);
8476
+ const filePath = path11.join(dir, file);
8303
8477
  const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
8304
8478
  const currentEntry = entries.get(file) || null;
8305
8479
  const nextSummary = updater(currentEntry?.summary || null);
@@ -8372,7 +8546,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
8372
8546
  function computeSavedHistoryFileSummary(dir, file) {
8373
8547
  const historySessionId = extractSavedHistorySessionIdFromFile(file);
8374
8548
  if (!historySessionId) return null;
8375
- const filePath = path10.join(dir, file);
8549
+ const filePath = path11.join(dir, file);
8376
8550
  const content = fs3.readFileSync(filePath, "utf-8");
8377
8551
  const lines = content.split("\n").filter(Boolean);
8378
8552
  let messageCount = 0;
@@ -8459,7 +8633,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
8459
8633
  const summaryBySessionId = /* @__PURE__ */ new Map();
8460
8634
  const nextPersistedEntries = /* @__PURE__ */ new Map();
8461
8635
  for (const file of files.slice().sort()) {
8462
- const filePath = path10.join(dir, file);
8636
+ const filePath = path11.join(dir, file);
8463
8637
  const signature = fileSignatures.get(file) || `${file}:missing`;
8464
8638
  const cached = savedHistoryFileSummaryCache.get(filePath);
8465
8639
  const persisted = persistedEntries.get(file);
@@ -8579,12 +8753,12 @@ var ChatHistoryWriter = class {
8579
8753
  });
8580
8754
  }
8581
8755
  if (newMessages.length === 0) return;
8582
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8756
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8583
8757
  fs3.mkdirSync(dir, { recursive: true });
8584
8758
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8585
8759
  const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
8586
8760
  const fileName = `${filePrefix}${date}.jsonl`;
8587
- const filePath = path10.join(dir, fileName);
8761
+ const filePath = path11.join(dir, fileName);
8588
8762
  const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
8589
8763
  fs3.appendFileSync(filePath, lines, "utf-8");
8590
8764
  updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
@@ -8675,11 +8849,11 @@ var ChatHistoryWriter = class {
8675
8849
  const ws = String(workspace || "").trim();
8676
8850
  if (!id || !ws) return;
8677
8851
  try {
8678
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8852
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8679
8853
  fs3.mkdirSync(dir, { recursive: true });
8680
8854
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8681
8855
  const fileName = `${this.sanitize(id)}_${date}.jsonl`;
8682
- const filePath = path10.join(dir, fileName);
8856
+ const filePath = path11.join(dir, fileName);
8683
8857
  const record = {
8684
8858
  ts: (/* @__PURE__ */ new Date()).toISOString(),
8685
8859
  receivedAt: Date.now(),
@@ -8725,14 +8899,14 @@ var ChatHistoryWriter = class {
8725
8899
  this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
8726
8900
  this.lastSeenCounts.delete(fromDedupKey);
8727
8901
  }
8728
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8902
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8729
8903
  if (!fs3.existsSync(dir)) return;
8730
8904
  const fromPrefix = `${this.sanitize(fromId)}_`;
8731
8905
  const toPrefix = `${this.sanitize(toId)}_`;
8732
8906
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
8733
8907
  for (const file of files) {
8734
- const sourcePath = path10.join(dir, file);
8735
- const targetPath = path10.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
8908
+ const sourcePath = path11.join(dir, file);
8909
+ const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
8736
8910
  const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
8737
8911
  const rewritten = sourceLines.map((line) => {
8738
8912
  try {
@@ -8766,13 +8940,13 @@ var ChatHistoryWriter = class {
8766
8940
  const sessionId = String(historySessionId || "").trim();
8767
8941
  if (!sessionId) return;
8768
8942
  try {
8769
- const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
8943
+ const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
8770
8944
  if (!fs3.existsSync(dir)) return;
8771
8945
  const prefix = `${this.sanitize(sessionId)}_`;
8772
8946
  const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
8773
8947
  const seen = /* @__PURE__ */ new Set();
8774
8948
  for (const file of files) {
8775
- const filePath = path10.join(dir, file);
8949
+ const filePath = path11.join(dir, file);
8776
8950
  const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
8777
8951
  const next = [];
8778
8952
  for (const line of lines) {
@@ -8826,11 +9000,11 @@ var ChatHistoryWriter = class {
8826
9000
  const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
8827
9001
  const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
8828
9002
  for (const dir of agentDirs) {
8829
- const dirPath = path10.join(HISTORY_DIR, dir.name);
9003
+ const dirPath = path11.join(HISTORY_DIR, dir.name);
8830
9004
  const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
8831
9005
  let removedAny = false;
8832
9006
  for (const file of files) {
8833
- const filePath = path10.join(dirPath, file);
9007
+ const filePath = path11.join(dirPath, file);
8834
9008
  const stat2 = fs3.statSync(filePath);
8835
9009
  if (stat2.mtimeMs < cutoff) {
8836
9010
  fs3.unlinkSync(filePath);
@@ -8880,13 +9054,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
8880
9054
  function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
8881
9055
  try {
8882
9056
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
8883
- const dir = path10.join(HISTORY_DIR, sanitized);
9057
+ const dir = path11.join(HISTORY_DIR, sanitized);
8884
9058
  if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
8885
9059
  const files = listHistoryFiles(dir, historySessionId);
8886
9060
  const allMessages = [];
8887
9061
  const seen = /* @__PURE__ */ new Set();
8888
9062
  for (const file of files) {
8889
- const filePath = path10.join(dir, file);
9063
+ const filePath = path11.join(dir, file);
8890
9064
  const content = fs3.readFileSync(filePath, "utf-8");
8891
9065
  const lines = content.trim().split("\n").filter(Boolean);
8892
9066
  for (let i = 0; i < lines.length; i++) {
@@ -8910,7 +9084,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
8910
9084
  function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
8911
9085
  try {
8912
9086
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
8913
- const dir = path10.join(HISTORY_DIR, sanitized);
9087
+ const dir = path11.join(HISTORY_DIR, sanitized);
8914
9088
  if (!fs3.existsSync(dir)) {
8915
9089
  savedHistorySessionCache.delete(sanitized);
8916
9090
  return { sessions: [], hasMore: false };
@@ -8971,11 +9145,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
8971
9145
  }
8972
9146
  function readExistingSessionStartRecord(agentType, historySessionId) {
8973
9147
  try {
8974
- const dir = path10.join(HISTORY_DIR, agentType);
9148
+ const dir = path11.join(HISTORY_DIR, agentType);
8975
9149
  if (!fs3.existsSync(dir)) return null;
8976
9150
  const files = listHistoryFiles(dir, historySessionId).sort();
8977
9151
  for (const file of files) {
8978
- const lines = fs3.readFileSync(path10.join(dir, file), "utf-8").split("\n").filter(Boolean);
9152
+ const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
8979
9153
  for (const line of lines) {
8980
9154
  try {
8981
9155
  const parsed = JSON.parse(line);
@@ -8995,16 +9169,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
8995
9169
  function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
8996
9170
  if (records.length === 0) return false;
8997
9171
  try {
8998
- const dir = path10.join(HISTORY_DIR, agentType);
9172
+ const dir = path11.join(HISTORY_DIR, agentType);
8999
9173
  fs3.mkdirSync(dir, { recursive: true });
9000
9174
  const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
9001
9175
  for (const file of fs3.readdirSync(dir)) {
9002
9176
  if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
9003
- fs3.unlinkSync(path10.join(dir, file));
9177
+ fs3.unlinkSync(path11.join(dir, file));
9004
9178
  }
9005
9179
  }
9006
9180
  const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
9007
- const filePath = path10.join(dir, `${prefix}${targetDate}.jsonl`);
9181
+ const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
9008
9182
  fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
9009
9183
  `, "utf-8");
9010
9184
  invalidatePersistedSavedHistoryIndex(agentType, dir);
@@ -10999,6 +11173,14 @@ function getActiveChatOptions(profile) {
10999
11173
  if (profile === "full") return {};
11000
11174
  return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
11001
11175
  }
11176
+ function resolveSessionStatus(activeChat, providerStatus) {
11177
+ const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
11178
+ const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
11179
+ if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
11180
+ if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
11181
+ if (topLevelStatus !== "idle") return topLevelStatus;
11182
+ return chatStatus;
11183
+ }
11002
11184
  function shouldIncludeSessionControls(profile) {
11003
11185
  return profile !== "live";
11004
11186
  }
@@ -11077,9 +11259,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
11077
11259
  providerName: state.name,
11078
11260
  kind: "workspace",
11079
11261
  transport: "cdp-page",
11080
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11081
- activeModal: activeChat?.activeModal || null
11082
- }),
11262
+ status: resolveSessionStatus(activeChat, state.status),
11083
11263
  title,
11084
11264
  workspace,
11085
11265
  ...git && { git },
@@ -11114,9 +11294,7 @@ function buildExtensionAgentSession(parent, ext, options) {
11114
11294
  providerSessionId: ext.providerSessionId,
11115
11295
  kind: "agent",
11116
11296
  transport: "cdp-webview",
11117
- status: normalizeManagedStatus(activeChat?.status || ext.status, {
11118
- activeModal: activeChat?.activeModal || null
11119
- }),
11297
+ status: resolveSessionStatus(activeChat, ext.status),
11120
11298
  title: activeChat?.title || ext.name,
11121
11299
  workspace,
11122
11300
  ...git && { git },
@@ -11166,9 +11344,7 @@ function buildCliSession(state, options) {
11166
11344
  providerSessionId: state.providerSessionId,
11167
11345
  kind: "agent",
11168
11346
  transport: "pty",
11169
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11170
- activeModal: activeChat?.activeModal || null
11171
- }),
11347
+ status: resolveSessionStatus(activeChat, state.status),
11172
11348
  title: activeChat?.title || state.name,
11173
11349
  workspace,
11174
11350
  ...git && { git },
@@ -11216,9 +11392,7 @@ function buildAcpSession(state, options) {
11216
11392
  providerName: state.name,
11217
11393
  kind: "agent",
11218
11394
  transport: "acp",
11219
- status: normalizeManagedStatus(activeChat?.status || state.status, {
11220
- activeModal: activeChat?.activeModal || null
11221
- }),
11395
+ status: resolveSessionStatus(activeChat, state.status),
11222
11396
  title: activeChat?.title || state.name,
11223
11397
  workspace,
11224
11398
  ...git && { git },
@@ -11341,7 +11515,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
11341
11515
  // src/commands/chat-commands.ts
11342
11516
  import * as fs4 from "fs";
11343
11517
  import * as os6 from "os";
11344
- import * as path11 from "path";
11518
+ import * as path12 from "path";
11345
11519
  import { randomUUID as randomUUID5 } from "crypto";
11346
11520
 
11347
11521
  // src/providers/provider-input-support.ts
@@ -11704,6 +11878,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
11704
11878
  return raw;
11705
11879
  }
11706
11880
  }
11881
+ function isGeneratingLikeStatus(status) {
11882
+ return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
11883
+ }
11884
+ function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
11885
+ if (!isGeneratingLikeStatus(parsedStatus)) return false;
11886
+ if (hasNonEmptyModalButtons(activeModal)) return false;
11887
+ const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
11888
+ if (adapterRawStatus !== "idle") return false;
11889
+ if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
11890
+ return true;
11891
+ }
11892
+ function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
11893
+ if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
11894
+ return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
11895
+ }
11896
+ function finalizeStreamingMessagesWhenIdle(messages, status) {
11897
+ if (status !== "idle") return messages;
11898
+ return messages.map((message) => {
11899
+ const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
11900
+ const hasStreamingMeta = meta?.streaming === true;
11901
+ if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
11902
+ return {
11903
+ ...message,
11904
+ ...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
11905
+ ...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
11906
+ };
11907
+ });
11908
+ }
11707
11909
  function buildReadChatCommandResult(payload, args) {
11708
11910
  let validatedPayload;
11709
11911
  const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
@@ -11852,7 +12054,7 @@ function buildDebugBundleText(bundle) {
11852
12054
  }
11853
12055
  function getChatDebugBundleDir() {
11854
12056
  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");
12057
+ return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
11856
12058
  }
11857
12059
  function safeBundleIdSegment(value, fallback) {
11858
12060
  const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
@@ -11868,6 +12070,14 @@ function buildChatDebugBundleSummary(bundle) {
11868
12070
  const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
11869
12071
  const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
11870
12072
  const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
12073
+ const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
12074
+ const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
12075
+ const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
12076
+ const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
12077
+ const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
12078
+ const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
12079
+ const cliStatus = typeof cli?.status === "string" ? cli.status : "";
12080
+ const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
11871
12081
  return {
11872
12082
  createdAt: bundle.createdAt,
11873
12083
  targetSessionId: target.targetSessionId,
@@ -11876,8 +12086,22 @@ function buildChatDebugBundleSummary(bundle) {
11876
12086
  readChatSuccess: readChat.success,
11877
12087
  readChatStatus: readChat.status,
11878
12088
  readChatTotalMessages: readChat.totalMessages,
12089
+ readChatReturnedMessages,
11879
12090
  cliStatus: cli?.status,
12091
+ cliParsedStatus: cliParsedStatus || void 0,
11880
12092
  cliMessageCount: cli?.messageCount,
12093
+ cliParsedMessageCount,
12094
+ cliPartialResponseChars: cliPartialResponse.length,
12095
+ parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
12096
+ parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
12097
+ readChatDebug: Object.keys(debugReadChat).length ? {
12098
+ adapterStatus: debugReadChat.adapterStatus,
12099
+ parsedStatus: debugReadChat.parsedStatus,
12100
+ returnedStatus: debugReadChat.returnedStatus,
12101
+ parsedMsgCount: debugReadChat.parsedMsgCount,
12102
+ returnedMsgCount: debugReadChat.returnedMsgCount,
12103
+ shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
12104
+ } : void 0,
11881
12105
  hasFrontendSnapshot: !!frontend
11882
12106
  };
11883
12107
  }
@@ -11885,7 +12109,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
11885
12109
  const bundleId = createChatDebugBundleId(targetSessionId);
11886
12110
  const dir = getChatDebugBundleDir();
11887
12111
  fs4.mkdirSync(dir, { recursive: true });
11888
- const savedPath = path11.join(dir, `${bundleId}.json`);
12112
+ const savedPath = path12.join(dir, `${bundleId}.json`);
11889
12113
  const json = `${JSON.stringify(bundle, null, 2)}
11890
12114
  `;
11891
12115
  fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
@@ -12115,7 +12339,7 @@ async function handleChatHistory(h, args) {
12115
12339
  }
12116
12340
  }
12117
12341
  async function handleReadChat(h, args) {
12118
- const provider = h.getProvider(args?.agentType);
12342
+ const provider = h.getProvider(args?.agentType || args?.providerType);
12119
12343
  const transport = getTargetTransport(h, provider);
12120
12344
  const historySessionId = getHistorySessionId(h, args);
12121
12345
  const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
@@ -12142,10 +12366,13 @@ async function handleReadChat(h, args) {
12142
12366
  const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
12143
12367
  const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
12144
12368
  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}`);
12369
+ const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
12370
+ const runtimeMessageMerger = getTargetInstance(h, args);
12371
+ const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
12372
+ const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
12373
+ 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
12374
  return buildReadChatCommandResult({
12148
- messages: parsedRecord.messages,
12375
+ messages: returnedMessages,
12149
12376
  status: returnedStatus,
12150
12377
  activeModal,
12151
12378
  debugReadChat: {
@@ -12156,7 +12383,7 @@ async function handleReadChat(h, args) {
12156
12383
  returnedStatus: String(returnedStatus || ""),
12157
12384
  shouldPreferAdapterMessages: false,
12158
12385
  parsedMsgCount: parsedRecord.messages.length,
12159
- returnedMsgCount: parsedRecord.messages.length
12386
+ returnedMsgCount: returnedMessages.length
12160
12387
  },
12161
12388
  ...title ? { title } : {},
12162
12389
  ...providerSessionId ? { providerSessionId } : {},
@@ -12901,9 +13128,17 @@ async function handleResolveAction(h, args) {
12901
13128
  const targetState = targetInstance?.getState?.();
12902
13129
  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
13130
  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"}`);
13131
+ const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
13132
+ try {
13133
+ return parseMaybeJson(adapter.getScriptParsedStatus());
13134
+ } catch {
13135
+ return null;
13136
+ }
13137
+ })() : null;
13138
+ 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;
13139
+ const effectiveModal = statusModal || surfacedModal || parsedModal;
13140
+ const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
13141
+ 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
13142
  if (!effectiveModal) {
12908
13143
  return { success: false, error: "Not in approval state" };
12909
13144
  }
@@ -13029,7 +13264,7 @@ async function handleResolveAction(h, args) {
13029
13264
 
13030
13265
  // src/commands/cdp-commands.ts
13031
13266
  import * as fs5 from "fs";
13032
- import * as path12 from "path";
13267
+ import * as path13 from "path";
13033
13268
  import * as os7 from "os";
13034
13269
  var KEY_TO_VK = {
13035
13270
  Backspace: 8,
@@ -13286,25 +13521,25 @@ function resolveSafePath(requestedPath) {
13286
13521
  const inputPath = rawPath || ".";
13287
13522
  const home = os7.homedir();
13288
13523
  if (inputPath.startsWith("~")) {
13289
- return path12.resolve(path12.join(home, inputPath.slice(1)));
13524
+ return path13.resolve(path13.join(home, inputPath.slice(1)));
13290
13525
  }
13291
13526
  if (process.platform === "win32") {
13292
13527
  const normalized = normalizeWindowsRequestedPath(inputPath);
13293
- if (path12.win32.isAbsolute(normalized)) {
13294
- return path12.win32.normalize(normalized);
13528
+ if (path13.win32.isAbsolute(normalized)) {
13529
+ return path13.win32.normalize(normalized);
13295
13530
  }
13296
- return path12.win32.resolve(normalized);
13531
+ return path13.win32.resolve(normalized);
13297
13532
  }
13298
- if (path12.isAbsolute(inputPath)) {
13299
- return path12.normalize(inputPath);
13533
+ if (path13.isAbsolute(inputPath)) {
13534
+ return path13.normalize(inputPath);
13300
13535
  }
13301
- return path12.resolve(inputPath);
13536
+ return path13.resolve(inputPath);
13302
13537
  }
13303
13538
  function listDirectoryEntriesSafe(dirPath) {
13304
13539
  const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
13305
13540
  const files = [];
13306
13541
  for (const entry of entries) {
13307
- const entryPath = path12.join(dirPath, entry.name);
13542
+ const entryPath = path13.join(dirPath, entry.name);
13308
13543
  try {
13309
13544
  if (entry.isDirectory()) {
13310
13545
  files.push({ name: entry.name, type: "directory" });
@@ -13358,7 +13593,7 @@ async function handleFileRead(h, args) {
13358
13593
  async function handleFileWrite(h, args) {
13359
13594
  try {
13360
13595
  const filePath = resolveSafePath(args?.path);
13361
- fs5.mkdirSync(path12.dirname(filePath), { recursive: true });
13596
+ fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
13362
13597
  fs5.writeFileSync(filePath, args?.content || "", "utf-8");
13363
13598
  return { success: true, path: filePath };
13364
13599
  } catch (e) {
@@ -14142,9 +14377,11 @@ var DaemonCommandHandler = class {
14142
14377
  }
14143
14378
  const sessionLookupFailed = !!targetSessionId && !session;
14144
14379
  const managerKey = this.extractIdeType(args, sessionLookupFailed);
14145
- let providerType;
14380
+ let providerType = args?.agentType || args?.providerType;
14146
14381
  if (!sessionLookupFailed) {
14147
- providerType = session?.providerType || args?.agentType || args?.providerType || this.inferProviderType(managerKey);
14382
+ providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
14383
+ } else if (!providerType) {
14384
+ providerType = this.inferProviderType(managerKey);
14148
14385
  }
14149
14386
  return { session, managerKey, providerType, sessionLookupFailed };
14150
14387
  }
@@ -14224,7 +14461,8 @@ var DaemonCommandHandler = class {
14224
14461
  "pty_resize",
14225
14462
  "invoke_provider_script"
14226
14463
  ]);
14227
- if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd)) {
14464
+ 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);
14465
+ if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
14228
14466
  const result2 = {
14229
14467
  success: false,
14230
14468
  error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
@@ -14478,16 +14716,16 @@ var DaemonCommandHandler = class {
14478
14716
  // src/commands/cli-manager.ts
14479
14717
  init_provider_cli_adapter();
14480
14718
  import * as os13 from "os";
14481
- import * as path16 from "path";
14719
+ import * as path17 from "path";
14482
14720
  import * as crypto4 from "crypto";
14483
- import { existsSync as existsSync11 } from "fs";
14721
+ import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
14484
14722
  import { execFileSync } from "child_process";
14485
14723
  import chalk from "chalk";
14486
14724
  init_config();
14487
14725
 
14488
14726
  // src/providers/cli-provider-instance.ts
14489
14727
  import * as os12 from "os";
14490
- import * as path15 from "path";
14728
+ import * as path16 from "path";
14491
14729
  import * as crypto3 from "crypto";
14492
14730
  import * as fs6 from "fs";
14493
14731
  import { createRequire } from "module";
@@ -14546,7 +14784,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
14546
14784
  var CachedDatabaseSync = null;
14547
14785
  function getDatabaseSync() {
14548
14786
  if (CachedDatabaseSync) return CachedDatabaseSync;
14549
- const requireFn = typeof __require === "function" ? __require : createRequire(path15.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
14787
+ const requireFn = typeof __require === "function" ? __require : createRequire(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
14550
14788
  const sqliteModule = requireFn(`node:${"sqlite"}`);
14551
14789
  CachedDatabaseSync = sqliteModule.DatabaseSync;
14552
14790
  if (!CachedDatabaseSync) {
@@ -14599,7 +14837,7 @@ var CliProviderInstance = class {
14599
14837
  this.providerSessionId = options?.providerSessionId;
14600
14838
  this.launchMode = options?.launchMode || "new";
14601
14839
  this.onProviderSessionResolved = options?.onProviderSessionResolved;
14602
- this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
14840
+ this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
14603
14841
  this.monitor = new StatusMonitor();
14604
14842
  this.historyWriter = new ChatHistoryWriter();
14605
14843
  }
@@ -15076,7 +15314,19 @@ var CliProviderInstance = class {
15076
15314
  }
15077
15315
  }
15078
15316
  pushEvent(event) {
15079
- this.events.push(event);
15317
+ const enrichedEvent = {
15318
+ ...event,
15319
+ instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
15320
+ targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
15321
+ providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
15322
+ workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
15323
+ providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
15324
+ };
15325
+ if (this.context?.emitProviderEvent) {
15326
+ this.context.emitProviderEvent(enrichedEvent);
15327
+ return;
15328
+ }
15329
+ this.events.push(enrichedEvent);
15080
15330
  }
15081
15331
  flushEvents() {
15082
15332
  const events = [...this.events];
@@ -15283,12 +15533,31 @@ ${effect.notification.body || ""}`.trim();
15283
15533
  );
15284
15534
  }
15285
15535
  }
15536
+ mergeRuntimeChatMessages(parsedMessages) {
15537
+ return this.mergeConversationMessages(parsedMessages);
15538
+ }
15286
15539
  mergeConversationMessages(parsedMessages) {
15287
15540
  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;
15541
+ const parsedEntries = parsedMessages.map((message, index) => ({
15542
+ message,
15543
+ index,
15544
+ source: "parsed"
15545
+ }));
15546
+ const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
15547
+ message: entry.message,
15548
+ index: parsedMessages.length + index,
15549
+ source: "runtime"
15550
+ }));
15551
+ const getTime = (message) => {
15552
+ const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
15553
+ return Number.isFinite(value) && value > 0 ? value : 0;
15554
+ };
15555
+ return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
15556
+ const aTime = getTime(a.message);
15557
+ const bTime = getTime(b.message);
15558
+ if (aTime && bTime && aTime !== bTime) return aTime - bTime;
15559
+ if (aTime && !bTime && a.source === "runtime" && b.source === "parsed") return -1;
15560
+ if (!aTime && bTime && a.source === "parsed" && b.source === "runtime") return 1;
15292
15561
  return a.index - b.index;
15293
15562
  }).map((entry) => entry.message));
15294
15563
  }
@@ -16617,17 +16886,17 @@ function shouldRestoreHostedRuntime(record, managerTag) {
16617
16886
  // src/commands/cli-manager.ts
16618
16887
  function isExplicitCommand(command) {
16619
16888
  const trimmed = command.trim();
16620
- return path16.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
16889
+ return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
16621
16890
  }
16622
16891
  function expandExecutable(command) {
16623
16892
  const trimmed = command.trim();
16624
- return trimmed.startsWith("~") ? path16.join(os13.homedir(), trimmed.slice(1)) : trimmed;
16893
+ return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
16625
16894
  }
16626
16895
  function commandExists(command) {
16627
16896
  const trimmed = command.trim();
16628
16897
  if (!trimmed) return false;
16629
16898
  if (isExplicitCommand(trimmed)) {
16630
- return existsSync11(expandExecutable(trimmed));
16899
+ return existsSync12(expandExecutable(trimmed));
16631
16900
  }
16632
16901
  try {
16633
16902
  execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -16645,6 +16914,35 @@ function colorize(color, text) {
16645
16914
  const fn = chalkApi?.[color];
16646
16915
  return typeof fn === "function" ? fn(text) : text;
16647
16916
  }
16917
+ var COORDINATOR_DELEGATED_ENV_UNSETS = {
16918
+ ADHDEV_INLINE_MESH: "",
16919
+ ADHDEV_MCP_TRANSPORT: "",
16920
+ ADHDEV_MESH_ID: "",
16921
+ HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
16922
+ };
16923
+ function hasCliArg(args, flag) {
16924
+ return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
16925
+ }
16926
+ function ensureEmptyDelegatedMcpConfig(workspace) {
16927
+ const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
16928
+ mkdirSync7(baseDir, { recursive: true });
16929
+ const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
16930
+ const filePath = path17.join(baseDir, `${workspaceHash}.json`);
16931
+ writeFileSync7(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
16932
+ return filePath;
16933
+ }
16934
+ function buildCoordinatorDelegatedCliLaunchOptions(input) {
16935
+ const cliType = String(input.cliType || "").trim();
16936
+ const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
16937
+ const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
16938
+ if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
16939
+ cliArgs.unshift("--ignore-user-config");
16940
+ }
16941
+ if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
16942
+ cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
16943
+ }
16944
+ return { cliArgs, env };
16945
+ }
16648
16946
  function isUuid(value) {
16649
16947
  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
16948
  }
@@ -16815,7 +17113,7 @@ var DaemonCliManager = class {
16815
17113
  attachExisting
16816
17114
  }) || void 0;
16817
17115
  }
16818
- createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
17116
+ createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
16819
17117
  const normalizedType = this.providerLoader.resolveAlias(cliType);
16820
17118
  const provider = this.providerLoader.getMeta(normalizedType);
16821
17119
  if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
@@ -16829,7 +17127,7 @@ var DaemonCliManager = class {
16829
17127
  providerSessionId,
16830
17128
  attachExisting
16831
17129
  );
16832
- return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
17130
+ return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
16833
17131
  }
16834
17132
  throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
16835
17133
  }
@@ -16902,7 +17200,7 @@ var DaemonCliManager = class {
16902
17200
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
16903
17201
  const trimmed = (workingDir || "").trim();
16904
17202
  if (!trimmed) throw new Error("working directory required");
16905
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path16.resolve(trimmed);
17203
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
16906
17204
  const normalizedType = this.providerLoader.resolveAlias(cliType);
16907
17205
  const rawProvider = this.providerLoader.getByAlias(cliType);
16908
17206
  const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
@@ -17032,6 +17330,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
17032
17330
  {
17033
17331
  providerSessionId: sessionBinding.providerSessionId,
17034
17332
  launchMode: sessionBinding.launchMode,
17333
+ extraEnv: options?.extraEnv,
17035
17334
  onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
17036
17335
  this.persistRecentActivity({
17037
17336
  kind: "cli",
@@ -17052,7 +17351,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
17052
17351
  resolvedCliArgs,
17053
17352
  key,
17054
17353
  sessionBinding.providerSessionId,
17055
- false
17354
+ false,
17355
+ options?.extraEnv
17056
17356
  );
17057
17357
  try {
17058
17358
  await adapter.spawn();
@@ -17276,12 +17576,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
17276
17576
  const dir = resolved.path;
17277
17577
  const launchSource = resolved.source;
17278
17578
  if (!cliType) throw new Error("cliType required");
17579
+ const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
17580
+ const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
17581
+ cliType,
17582
+ workspace: dir,
17583
+ cliArgs: args?.cliArgs,
17584
+ env: args?.env
17585
+ }) : null;
17279
17586
  const started = await this.startSession(
17280
17587
  cliType,
17281
17588
  dir,
17282
- args?.cliArgs,
17589
+ delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
17283
17590
  args?.initialModel,
17284
- { resumeSessionId: args?.resumeSessionId, settingsOverride: args?.settings }
17591
+ {
17592
+ resumeSessionId: args?.resumeSessionId,
17593
+ settingsOverride,
17594
+ extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
17595
+ }
17285
17596
  );
17286
17597
  return {
17287
17598
  success: true,
@@ -17403,11 +17714,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
17403
17714
  import { execSync as execSync4, spawn as spawn2 } from "child_process";
17404
17715
  import * as net from "net";
17405
17716
  import * as os15 from "os";
17406
- import * as path18 from "path";
17717
+ import * as path19 from "path";
17407
17718
 
17408
17719
  // src/providers/provider-loader.ts
17409
17720
  import * as fs7 from "fs";
17410
- import * as path17 from "path";
17721
+ import * as path18 from "path";
17411
17722
  import * as os14 from "os";
17412
17723
  import * as chokidar from "chokidar";
17413
17724
  init_logger();
@@ -17731,7 +18042,7 @@ var ProviderLoader = class _ProviderLoader {
17731
18042
  try {
17732
18043
  if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
17733
18044
  return ["ide", "extension", "cli", "acp"].some(
17734
- (category) => fs7.existsSync(path17.join(candidate, category))
18045
+ (category) => fs7.existsSync(path18.join(candidate, category))
17735
18046
  );
17736
18047
  } catch {
17737
18048
  return false;
@@ -17739,20 +18050,20 @@ var ProviderLoader = class _ProviderLoader {
17739
18050
  }
17740
18051
  static hasProviderRootMarker(candidate) {
17741
18052
  try {
17742
- return fs7.existsSync(path17.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
18053
+ return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
17743
18054
  } catch {
17744
18055
  return false;
17745
18056
  }
17746
18057
  }
17747
18058
  detectDefaultUserDir() {
17748
- const fallback = path17.join(os14.homedir(), ".adhdev", "providers");
18059
+ const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
17749
18060
  const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
17750
18061
  const visited = /* @__PURE__ */ new Set();
17751
18062
  for (const start of this.probeStarts) {
17752
- let current = path17.resolve(start);
18063
+ let current = path18.resolve(start);
17753
18064
  while (!visited.has(current)) {
17754
18065
  visited.add(current);
17755
- const siblingCandidate = path17.join(path17.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
18066
+ const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
17756
18067
  if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
17757
18068
  const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
17758
18069
  if (envOptIn || hasMarker) {
@@ -17774,7 +18085,7 @@ var ProviderLoader = class _ProviderLoader {
17774
18085
  return { path: siblingCandidate, source };
17775
18086
  }
17776
18087
  }
17777
- const parent = path17.dirname(current);
18088
+ const parent = path18.dirname(current);
17778
18089
  if (parent === current) break;
17779
18090
  current = parent;
17780
18091
  }
@@ -17784,11 +18095,11 @@ var ProviderLoader = class _ProviderLoader {
17784
18095
  constructor(options) {
17785
18096
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
17786
18097
  this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
17787
- this.defaultProvidersDir = path17.join(os14.homedir(), ".adhdev", "providers");
18098
+ this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
17788
18099
  const detected = this.detectDefaultUserDir();
17789
18100
  this.userDir = detected.path;
17790
18101
  this.userDirSource = detected.source;
17791
- this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
18102
+ this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
17792
18103
  this.disableUpstream = false;
17793
18104
  this.applySourceConfig({
17794
18105
  userDir: options?.userDir,
@@ -17847,7 +18158,7 @@ var ProviderLoader = class _ProviderLoader {
17847
18158
  this.userDir = detected.path;
17848
18159
  this.userDirSource = detected.source;
17849
18160
  }
17850
- this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
18161
+ this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
17851
18162
  this.disableUpstream = this.sourceMode === "no-upstream";
17852
18163
  if (this.explicitProviderDir) {
17853
18164
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
@@ -17861,7 +18172,7 @@ var ProviderLoader = class _ProviderLoader {
17861
18172
  * Canonical provider directory shape for a given root.
17862
18173
  */
17863
18174
  getProviderDir(root, category, type) {
17864
- return path17.join(root, category, type);
18175
+ return path18.join(root, category, type);
17865
18176
  }
17866
18177
  /**
17867
18178
  * Canonical user override directory for a provider.
@@ -17888,7 +18199,7 @@ var ProviderLoader = class _ProviderLoader {
17888
18199
  resolveProviderFile(type, ...segments) {
17889
18200
  const dir = this.findProviderDirInternal(type);
17890
18201
  if (!dir) return null;
17891
- return path17.join(dir, ...segments);
18202
+ return path18.join(dir, ...segments);
17892
18203
  }
17893
18204
  /**
17894
18205
  * Load all providers (3-tier priority)
@@ -17927,7 +18238,7 @@ var ProviderLoader = class _ProviderLoader {
17927
18238
  if (!fs7.existsSync(this.upstreamDir)) return false;
17928
18239
  try {
17929
18240
  return fs7.readdirSync(this.upstreamDir).some(
17930
- (d) => fs7.statSync(path17.join(this.upstreamDir, d)).isDirectory()
18241
+ (d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
17931
18242
  );
17932
18243
  } catch {
17933
18244
  return false;
@@ -18424,8 +18735,8 @@ var ProviderLoader = class _ProviderLoader {
18424
18735
  resolved._resolvedScriptDir = entry.scriptDir;
18425
18736
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
18426
18737
  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;
18738
+ const fullDir = path18.join(providerDir, entry.scriptDir);
18739
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18429
18740
  }
18430
18741
  matched = true;
18431
18742
  }
@@ -18440,8 +18751,8 @@ var ProviderLoader = class _ProviderLoader {
18440
18751
  resolved._resolvedScriptDir = base.defaultScriptDir;
18441
18752
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
18442
18753
  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;
18754
+ const fullDir = path18.join(providerDir, base.defaultScriptDir);
18755
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18445
18756
  }
18446
18757
  }
18447
18758
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -18458,8 +18769,8 @@ var ProviderLoader = class _ProviderLoader {
18458
18769
  resolved._resolvedScriptDir = dirOverride;
18459
18770
  resolved._resolvedScriptsSource = `versions:${range}`;
18460
18771
  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;
18772
+ const fullDir = path18.join(providerDir, dirOverride);
18773
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18463
18774
  }
18464
18775
  }
18465
18776
  } else if (override.scripts) {
@@ -18475,8 +18786,8 @@ var ProviderLoader = class _ProviderLoader {
18475
18786
  resolved._resolvedScriptDir = base.defaultScriptDir;
18476
18787
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
18477
18788
  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;
18789
+ const fullDir = path18.join(providerDir, base.defaultScriptDir);
18790
+ resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
18480
18791
  }
18481
18792
  }
18482
18793
  }
@@ -18508,14 +18819,14 @@ var ProviderLoader = class _ProviderLoader {
18508
18819
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
18509
18820
  return null;
18510
18821
  }
18511
- const dir = path17.join(providerDir, scriptDir);
18822
+ const dir = path18.join(providerDir, scriptDir);
18512
18823
  if (!fs7.existsSync(dir)) {
18513
18824
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
18514
18825
  return null;
18515
18826
  }
18516
18827
  const cached = this.scriptsCache.get(dir);
18517
18828
  if (cached) return cached;
18518
- const scriptsJs = path17.join(dir, "scripts.js");
18829
+ const scriptsJs = path18.join(dir, "scripts.js");
18519
18830
  if (fs7.existsSync(scriptsJs)) {
18520
18831
  try {
18521
18832
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -18557,7 +18868,7 @@ var ProviderLoader = class _ProviderLoader {
18557
18868
  return;
18558
18869
  }
18559
18870
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
18560
- this.log(`File changed: ${path17.basename(filePath)}, reloading...`);
18871
+ this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
18561
18872
  this.reload();
18562
18873
  }
18563
18874
  };
@@ -18612,7 +18923,7 @@ var ProviderLoader = class _ProviderLoader {
18612
18923
  }
18613
18924
  const https = __require("https");
18614
18925
  const { execSync: execSync7 } = __require("child_process");
18615
- const metaPath = path17.join(this.upstreamDir, _ProviderLoader.META_FILE);
18926
+ const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
18616
18927
  let prevEtag = "";
18617
18928
  let prevTimestamp = 0;
18618
18929
  try {
@@ -18672,17 +18983,17 @@ var ProviderLoader = class _ProviderLoader {
18672
18983
  return { updated: false };
18673
18984
  }
18674
18985
  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()}`);
18986
+ const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
18987
+ const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
18677
18988
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
18678
18989
  fs7.mkdirSync(tmpExtract, { recursive: true });
18679
18990
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
18680
18991
  const extracted = fs7.readdirSync(tmpExtract);
18681
18992
  const rootDir = extracted.find(
18682
- (d) => fs7.statSync(path17.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
18993
+ (d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
18683
18994
  );
18684
18995
  if (!rootDir) throw new Error("Unexpected tarball structure");
18685
- const sourceDir = path17.join(tmpExtract, rootDir);
18996
+ const sourceDir = path18.join(tmpExtract, rootDir);
18686
18997
  const backupDir = this.upstreamDir + ".bak";
18687
18998
  if (fs7.existsSync(this.upstreamDir)) {
18688
18999
  if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
@@ -18757,8 +19068,8 @@ var ProviderLoader = class _ProviderLoader {
18757
19068
  copyDirRecursive(src, dest) {
18758
19069
  fs7.mkdirSync(dest, { recursive: true });
18759
19070
  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);
19071
+ const srcPath = path18.join(src, entry.name);
19072
+ const destPath = path18.join(dest, entry.name);
18762
19073
  if (entry.isDirectory()) {
18763
19074
  this.copyDirRecursive(srcPath, destPath);
18764
19075
  } else {
@@ -18769,7 +19080,7 @@ var ProviderLoader = class _ProviderLoader {
18769
19080
  /** .meta.json save */
18770
19081
  writeMeta(metaPath, etag, timestamp) {
18771
19082
  try {
18772
- fs7.mkdirSync(path17.dirname(metaPath), { recursive: true });
19083
+ fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
18773
19084
  fs7.writeFileSync(metaPath, JSON.stringify({
18774
19085
  etag,
18775
19086
  timestamp,
@@ -18786,7 +19097,7 @@ var ProviderLoader = class _ProviderLoader {
18786
19097
  const scan = (d) => {
18787
19098
  try {
18788
19099
  for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
18789
- if (entry.isDirectory()) scan(path17.join(d, entry.name));
19100
+ if (entry.isDirectory()) scan(path18.join(d, entry.name));
18790
19101
  else if (entry.name === "provider.json") count++;
18791
19102
  }
18792
19103
  } catch {
@@ -19014,17 +19325,17 @@ var ProviderLoader = class _ProviderLoader {
19014
19325
  for (const root of searchRoots) {
19015
19326
  if (!fs7.existsSync(root)) continue;
19016
19327
  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);
19328
+ if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
19329
+ const catDir = path18.join(root, cat);
19019
19330
  if (fs7.existsSync(catDir)) {
19020
19331
  try {
19021
19332
  for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
19022
19333
  if (!entry.isDirectory()) continue;
19023
- const jsonPath = path17.join(catDir, entry.name, "provider.json");
19334
+ const jsonPath = path18.join(catDir, entry.name, "provider.json");
19024
19335
  if (fs7.existsSync(jsonPath)) {
19025
19336
  try {
19026
19337
  const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
19027
- if (data.type === type) return path17.join(catDir, entry.name);
19338
+ if (data.type === type) return path18.join(catDir, entry.name);
19028
19339
  } catch {
19029
19340
  }
19030
19341
  }
@@ -19041,7 +19352,7 @@ var ProviderLoader = class _ProviderLoader {
19041
19352
  * (template substitution is NOT applied here — scripts.js handles that)
19042
19353
  */
19043
19354
  buildScriptWrappersFromDir(dir) {
19044
- const scriptsJs = path17.join(dir, "scripts.js");
19355
+ const scriptsJs = path18.join(dir, "scripts.js");
19045
19356
  if (fs7.existsSync(scriptsJs)) {
19046
19357
  try {
19047
19358
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -19055,7 +19366,7 @@ var ProviderLoader = class _ProviderLoader {
19055
19366
  for (const file of fs7.readdirSync(dir)) {
19056
19367
  if (!file.endsWith(".js")) continue;
19057
19368
  const scriptName = toCamel(file.replace(".js", ""));
19058
- const filePath = path17.join(dir, file);
19369
+ const filePath = path18.join(dir, file);
19059
19370
  result[scriptName] = (...args) => {
19060
19371
  try {
19061
19372
  let content = fs7.readFileSync(filePath, "utf-8");
@@ -19115,7 +19426,7 @@ var ProviderLoader = class _ProviderLoader {
19115
19426
  }
19116
19427
  const hasJson = entries.some((e) => e.name === "provider.json");
19117
19428
  if (hasJson) {
19118
- const jsonPath = path17.join(d, "provider.json");
19429
+ const jsonPath = path18.join(d, "provider.json");
19119
19430
  try {
19120
19431
  const raw = fs7.readFileSync(jsonPath, "utf-8");
19121
19432
  const mod = JSON.parse(raw);
@@ -19136,7 +19447,7 @@ var ProviderLoader = class _ProviderLoader {
19136
19447
  this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
19137
19448
  } else {
19138
19449
  const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
19139
- const scriptsPath = path17.join(d, "scripts.js");
19450
+ const scriptsPath = path18.join(d, "scripts.js");
19140
19451
  if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
19141
19452
  try {
19142
19453
  delete __require.cache[__require.resolve(scriptsPath)];
@@ -19162,7 +19473,7 @@ var ProviderLoader = class _ProviderLoader {
19162
19473
  if (!entry.isDirectory()) continue;
19163
19474
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
19164
19475
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
19165
- scan(path17.join(d, entry.name));
19476
+ scan(path18.join(d, entry.name));
19166
19477
  }
19167
19478
  }
19168
19479
  };
@@ -19487,8 +19798,8 @@ function detectCurrentWorkspace(ideId) {
19487
19798
  const appNameMap = getMacAppIdentifiers();
19488
19799
  const appName = appNameMap[ideId];
19489
19800
  if (appName) {
19490
- const storagePath = path18.join(
19491
- process.env.APPDATA || path18.join(os15.homedir(), "AppData", "Roaming"),
19801
+ const storagePath = path19.join(
19802
+ process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
19492
19803
  appName,
19493
19804
  "storage.json"
19494
19805
  );
@@ -19677,9 +19988,9 @@ init_logger();
19677
19988
 
19678
19989
  // src/logging/command-log.ts
19679
19990
  import * as fs8 from "fs";
19680
- import * as path19 from "path";
19991
+ import * as path20 from "path";
19681
19992
  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");
19993
+ 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
19994
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
19684
19995
  var MAX_DAYS = 7;
19685
19996
  try {
@@ -19717,13 +20028,13 @@ function getDateStr2() {
19717
20028
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
19718
20029
  }
19719
20030
  var currentDate2 = getDateStr2();
19720
- var currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20031
+ var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
19721
20032
  var writeCount2 = 0;
19722
20033
  function checkRotation() {
19723
20034
  const today = getDateStr2();
19724
20035
  if (today !== currentDate2) {
19725
20036
  currentDate2 = today;
19726
- currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
20037
+ currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
19727
20038
  cleanOldFiles();
19728
20039
  }
19729
20040
  }
@@ -19737,7 +20048,7 @@ function cleanOldFiles() {
19737
20048
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
19738
20049
  if (dateMatch && dateMatch[1] < cutoffStr) {
19739
20050
  try {
19740
- fs8.unlinkSync(path19.join(LOG_DIR2, file));
20051
+ fs8.unlinkSync(path20.join(LOG_DIR2, file));
19741
20052
  } catch {
19742
20053
  }
19743
20054
  }
@@ -19821,13 +20132,65 @@ cleanOldFiles();
19821
20132
 
19822
20133
  // src/commands/router.ts
19823
20134
  init_logger();
20135
+ import * as yaml from "js-yaml";
19824
20136
 
19825
20137
  // src/commands/mesh-coordinator.ts
19826
- import { existsSync as existsSync14, realpathSync as realpathSync2 } from "fs";
20138
+ import { execFileSync as execFileSync2 } from "child_process";
20139
+ import { existsSync as existsSync15, readdirSync as readdirSync6, realpathSync as realpathSync2 } from "fs";
19827
20140
  import { createRequire as createRequire2 } from "module";
19828
- import { dirname as dirname3, join as join17, resolve as resolve13 } from "path";
20141
+ import * as os17 from "os";
20142
+ import { dirname as dirname4, isAbsolute as isAbsolute10, join as join18, resolve as resolve13 } from "path";
19829
20143
  var DEFAULT_SERVER_NAME = "adhdev-mesh";
19830
20144
  var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
20145
+ var HERMES_CLI_TYPE = "hermes-cli";
20146
+ var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
20147
+ function isHermesProvider(provider, cliType) {
20148
+ const type = cliType?.trim() || provider?.type?.trim() || "";
20149
+ return type === HERMES_CLI_TYPE;
20150
+ }
20151
+ function resolveHermesMeshCoordinatorSetup(options) {
20152
+ const mcpServer = resolveAdhdevMcpServerLaunch({
20153
+ meshId: options.meshId,
20154
+ nodeExecutable: options.nodeExecutable,
20155
+ adhdevMcpEntryPath: options.adhdevMcpEntryPath
20156
+ });
20157
+ if (!mcpServer) {
20158
+ return {
20159
+ kind: "unsupported",
20160
+ reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
20161
+ };
20162
+ }
20163
+ const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
20164
+ if (!configPath.trim()) {
20165
+ return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
20166
+ }
20167
+ return {
20168
+ kind: "auto_import",
20169
+ serverName: DEFAULT_SERVER_NAME,
20170
+ configPath,
20171
+ configFormat: "hermes_config_yaml",
20172
+ mcpServer
20173
+ };
20174
+ }
20175
+ function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
20176
+ return {
20177
+ kind: "manual",
20178
+ serverName: DEFAULT_SERVER_NAME,
20179
+ configFormat: "hermes_config_yaml",
20180
+ configPathCommand: HERMES_MCP_CONFIG_PATH,
20181
+ requiresRestart: true,
20182
+ 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.",
20183
+ template: renderMeshCoordinatorTemplate(
20184
+ "mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
20185
+ {
20186
+ meshId,
20187
+ workspace,
20188
+ serverName: DEFAULT_SERVER_NAME,
20189
+ adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
20190
+ }
20191
+ )
20192
+ };
20193
+ }
19831
20194
  function resolveMeshCoordinatorSetup(options) {
19832
20195
  const { provider, meshId, workspace } = options;
19833
20196
  const config = provider?.meshCoordinator;
@@ -19837,6 +20200,9 @@ function resolveMeshCoordinatorSetup(options) {
19837
20200
  reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
19838
20201
  };
19839
20202
  }
20203
+ if (isHermesProvider(provider, options.cliType)) {
20204
+ return resolveHermesMeshCoordinatorSetup(options);
20205
+ }
19840
20206
  const mcpConfig = config.mcpConfig;
19841
20207
  if (!mcpConfig || mcpConfig.mode === "none") {
19842
20208
  return {
@@ -19846,8 +20212,8 @@ function resolveMeshCoordinatorSetup(options) {
19846
20212
  }
19847
20213
  const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
19848
20214
  if (mcpConfig.mode === "auto_import") {
19849
- const path26 = mcpConfig.path?.trim();
19850
- if (!path26) {
20215
+ const path27 = mcpConfig.path?.trim();
20216
+ if (!path27) {
19851
20217
  return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
19852
20218
  }
19853
20219
  const mcpServer = resolveAdhdevMcpServerLaunch({
@@ -19858,13 +20224,13 @@ function resolveMeshCoordinatorSetup(options) {
19858
20224
  if (!mcpServer) {
19859
20225
  return {
19860
20226
  kind: "unsupported",
19861
- reason: "Could not resolve the ADHDev MCP server entrypoint without relying on a PATH bin shim"
20227
+ reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
19862
20228
  };
19863
20229
  }
19864
20230
  return {
19865
20231
  kind: "auto_import",
19866
20232
  serverName,
19867
- configPath: join17(workspace, path26),
20233
+ configPath: resolveMcpConfigPath(path27, workspace),
19868
20234
  configFormat: mcpConfig.format,
19869
20235
  mcpServer
19870
20236
  };
@@ -19898,13 +20264,84 @@ function resolveMeshCoordinatorSetup(options) {
19898
20264
  function renderMeshCoordinatorTemplate(template, values) {
19899
20265
  return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
19900
20266
  }
20267
+ function resolveMcpConfigPath(configPath, workspace) {
20268
+ const trimmed = configPath.trim();
20269
+ if (trimmed === "~") return os17.homedir();
20270
+ if (trimmed.startsWith("~/")) return join18(os17.homedir(), trimmed.slice(2));
20271
+ if (isAbsolute10(trimmed)) return trimmed;
20272
+ return join18(workspace, trimmed);
20273
+ }
19901
20274
  function resolveAdhdevMcpServerLaunch(options) {
19902
20275
  const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
19903
20276
  if (!entryPath) return null;
20277
+ const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
20278
+ if (!nodeExecutable) return null;
19904
20279
  return {
19905
- command: options.nodeExecutable?.trim() || process.execPath,
19906
- args: [entryPath, "--repo-mesh", options.meshId]
20280
+ command: nodeExecutable,
20281
+ args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
20282
+ };
20283
+ }
20284
+ function resolveMcpNodeExecutable(explicitExecutable) {
20285
+ const explicit = explicitExecutable?.trim();
20286
+ if (explicit) return explicit;
20287
+ const candidates = [];
20288
+ const addCandidate = (candidate) => {
20289
+ const trimmed = candidate?.trim();
20290
+ if (!trimmed) return;
20291
+ const normalized = normalizeExistingPath(trimmed) || trimmed;
20292
+ if (!candidates.includes(normalized)) candidates.push(normalized);
19907
20293
  };
20294
+ addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
20295
+ addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
20296
+ addCandidate(process.env.npm_node_execpath);
20297
+ addNodeCandidatesFromPath(process.env.PATH, addCandidate);
20298
+ addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
20299
+ addCandidate("/opt/homebrew/bin/node");
20300
+ addCandidate("/usr/local/bin/node");
20301
+ addCandidate("/usr/bin/node");
20302
+ addCandidate(process.execPath);
20303
+ for (const candidate of candidates) {
20304
+ if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
20305
+ }
20306
+ return null;
20307
+ }
20308
+ function addNodeCandidatesFromPath(pathValue, addCandidate) {
20309
+ for (const entry of (pathValue || "").split(":")) {
20310
+ const dir = entry.trim();
20311
+ if (!dir) continue;
20312
+ addCandidate(join18(dir, "node"));
20313
+ }
20314
+ }
20315
+ function addNodeCandidatesFromNvm(homeDir, addCandidate) {
20316
+ const versionsDir = join18(homeDir, ".nvm", "versions", "node");
20317
+ try {
20318
+ const versionDirs = readdirSync6(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
20319
+ for (const versionDir of versionDirs) {
20320
+ addCandidate(join18(versionsDir, versionDir, "bin", "node"));
20321
+ }
20322
+ } catch {
20323
+ }
20324
+ }
20325
+ function compareNodeVersionNamesDescending(a, b) {
20326
+ const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
20327
+ const left = parse(a);
20328
+ const right = parse(b);
20329
+ for (let i = 0; i < Math.max(left.length, right.length); i++) {
20330
+ const diff = (right[i] || 0) - (left[i] || 0);
20331
+ if (diff !== 0) return diff;
20332
+ }
20333
+ return b.localeCompare(a);
20334
+ }
20335
+ function nodeRuntimeSupportsWebSocket(nodeExecutable) {
20336
+ try {
20337
+ execFileSync2(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
20338
+ stdio: "ignore",
20339
+ timeout: 3e3
20340
+ });
20341
+ return true;
20342
+ } catch {
20343
+ return false;
20344
+ }
19908
20345
  }
19909
20346
  function resolveAdhdevMcpEntryPath(explicitPath) {
19910
20347
  const explicit = explicitPath?.trim();
@@ -19918,7 +20355,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19918
20355
  const addPackagedCandidates = (baseFile) => {
19919
20356
  if (!baseFile) return;
19920
20357
  const realBase = normalizeExistingPath(baseFile) || baseFile;
19921
- const dir = dirname3(realBase);
20358
+ const dir = dirname4(realBase);
19922
20359
  addCandidate(resolve13(dir, "../vendor/mcp-server/index.js"));
19923
20360
  addCandidate(resolve13(dir, "../../vendor/mcp-server/index.js"));
19924
20361
  addCandidate(resolve13(dir, "../../../vendor/mcp-server/index.js"));
@@ -19931,7 +20368,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19931
20368
  if (normalized) return normalized;
19932
20369
  }
19933
20370
  try {
19934
- const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join17(process.cwd(), "adhdev-daemon.js");
20371
+ const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join18(process.cwd(), "adhdev-daemon.js");
19935
20372
  const req = createRequire2(requireBase);
19936
20373
  const resolvedModule = req.resolve("@adhdev/mcp-server");
19937
20374
  return normalizeExistingPath(resolvedModule) || resolvedModule;
@@ -19941,16 +20378,110 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
19941
20378
  }
19942
20379
  function normalizeExistingPath(filePath) {
19943
20380
  try {
19944
- if (!existsSync14(filePath)) return null;
20381
+ if (!existsSync15(filePath)) return null;
19945
20382
  return realpathSync2.native(filePath);
19946
20383
  } catch {
19947
20384
  return null;
19948
20385
  }
19949
20386
  }
19950
20387
 
20388
+ // src/mesh/mesh-events.ts
20389
+ init_mesh_config();
20390
+ init_logger();
20391
+ function readNonEmptyString(value) {
20392
+ return typeof value === "string" && value.trim() ? value.trim() : "";
20393
+ }
20394
+ function formatCompletionMetadata(event) {
20395
+ const parts = [
20396
+ readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
20397
+ readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
20398
+ readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
20399
+ ].filter(Boolean);
20400
+ return parts.length > 0 ? ` (${parts.join("; ")})` : "";
20401
+ }
20402
+ function buildMeshSystemMessage(args) {
20403
+ const metadata = formatCompletionMetadata(args.metadataEvent);
20404
+ if (args.event === "agent:generating_completed") {
20405
+ 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.`;
20406
+ }
20407
+ if (args.event === "agent:waiting_approval") {
20408
+ return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
20409
+ }
20410
+ return "";
20411
+ }
20412
+ function injectMeshSystemMessage(components, args) {
20413
+ const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
20414
+ const instState = inst.getState();
20415
+ if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
20416
+ if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
20417
+ return true;
20418
+ });
20419
+ if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
20420
+ const messageText = buildMeshSystemMessage({
20421
+ event: args.event,
20422
+ nodeLabel: args.nodeLabel,
20423
+ metadataEvent: args.metadataEvent
20424
+ });
20425
+ if (!messageText) return { success: false, error: "unsupported mesh event" };
20426
+ for (const coord of coordinatorInstances) {
20427
+ const coordState = coord.getState();
20428
+ LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
20429
+ coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
20430
+ }
20431
+ return { success: true, forwarded: coordinatorInstances.length };
20432
+ }
20433
+ function handleMeshForwardEvent(components, payload) {
20434
+ const eventName = readNonEmptyString(payload.event);
20435
+ if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
20436
+ return { success: false, error: "unsupported mesh event" };
20437
+ }
20438
+ const meshId = readNonEmptyString(payload.meshId);
20439
+ if (!meshId) return { success: false, error: "meshId required" };
20440
+ const nodeId = readNonEmptyString(payload.nodeId);
20441
+ const workspace = readNonEmptyString(payload.workspace);
20442
+ const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
20443
+ return injectMeshSystemMessage(components, {
20444
+ meshId,
20445
+ nodeLabel,
20446
+ event: eventName,
20447
+ metadataEvent: {
20448
+ targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
20449
+ providerType: readNonEmptyString(payload.providerType),
20450
+ providerSessionId: readNonEmptyString(payload.providerSessionId)
20451
+ }
20452
+ });
20453
+ }
20454
+ function setupMeshEventForwarding(components) {
20455
+ components.instanceManager.onEvent((event) => {
20456
+ if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
20457
+ const instanceId = readNonEmptyString(event.instanceId);
20458
+ if (!instanceId) return;
20459
+ const sourceInstance = components.instanceManager.getInstance(instanceId);
20460
+ if (!sourceInstance || sourceInstance.category !== "cli") return;
20461
+ const state = sourceInstance.getState();
20462
+ const workspace = readNonEmptyString(state.workspace);
20463
+ if (!workspace) return;
20464
+ const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
20465
+ const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
20466
+ const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
20467
+ const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
20468
+ if (!meshId) return;
20469
+ const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
20470
+ const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
20471
+ const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
20472
+ injectMeshSystemMessage(components, {
20473
+ meshId,
20474
+ sourceInstanceId: instanceId,
20475
+ nodeLabel,
20476
+ event: event.event,
20477
+ metadataEvent: event
20478
+ });
20479
+ });
20480
+ }
20481
+
19951
20482
  // src/status/snapshot.ts
19952
20483
  init_config();
19953
- import * as os17 from "os";
20484
+ import * as os18 from "os";
19954
20485
  init_terminal_screen();
19955
20486
  init_logger();
19956
20487
  var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
@@ -20005,8 +20536,8 @@ function buildAvailableProviders(providerLoader) {
20005
20536
  }
20006
20537
  function buildMachineInfo(profile = "full") {
20007
20538
  const base = {
20008
- hostname: os17.hostname(),
20009
- platform: os17.platform()
20539
+ hostname: os18.hostname(),
20540
+ platform: os18.platform()
20010
20541
  };
20011
20542
  if (profile === "live") {
20012
20543
  return base;
@@ -20015,23 +20546,23 @@ function buildMachineInfo(profile = "full") {
20015
20546
  const memSnap2 = getHostMemorySnapshot();
20016
20547
  return {
20017
20548
  ...base,
20018
- arch: os17.arch(),
20019
- cpus: os17.cpus().length,
20549
+ arch: os18.arch(),
20550
+ cpus: os18.cpus().length,
20020
20551
  totalMem: memSnap2.totalMem,
20021
- release: os17.release()
20552
+ release: os18.release()
20022
20553
  };
20023
20554
  }
20024
20555
  const memSnap = getHostMemorySnapshot();
20025
20556
  return {
20026
20557
  ...base,
20027
- arch: os17.arch(),
20028
- cpus: os17.cpus().length,
20558
+ arch: os18.arch(),
20559
+ cpus: os18.cpus().length,
20029
20560
  totalMem: memSnap.totalMem,
20030
20561
  freeMem: memSnap.freeMem,
20031
20562
  availableMem: memSnap.availableMem,
20032
- loadavg: os17.loadavg(),
20033
- uptime: os17.uptime(),
20034
- release: os17.release()
20563
+ loadavg: os18.loadavg(),
20564
+ uptime: os18.uptime(),
20565
+ release: os18.release()
20035
20566
  };
20036
20567
  }
20037
20568
  function parseMessageTime(value) {
@@ -20262,17 +20793,17 @@ function buildStatusSnapshot(options) {
20262
20793
  }
20263
20794
 
20264
20795
  // src/commands/upgrade-helper.ts
20265
- import { execFileSync as execFileSync2 } from "child_process";
20796
+ import { execFileSync as execFileSync3 } from "child_process";
20266
20797
  import { spawn as spawn3 } from "child_process";
20267
20798
  import * as fs9 from "fs";
20268
- import * as os18 from "os";
20269
- import * as path20 from "path";
20799
+ import * as os19 from "os";
20800
+ import * as path21 from "path";
20270
20801
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
20271
20802
  function getUpgradeLogPath() {
20272
- const home = os18.homedir();
20273
- const dir = path20.join(home, ".adhdev");
20803
+ const home = os19.homedir();
20804
+ const dir = path21.join(home, ".adhdev");
20274
20805
  fs9.mkdirSync(dir, { recursive: true });
20275
- return path20.join(dir, "daemon-upgrade.log");
20806
+ return path21.join(dir, "daemon-upgrade.log");
20276
20807
  }
20277
20808
  function appendUpgradeLog(message) {
20278
20809
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -20283,14 +20814,14 @@ function appendUpgradeLog(message) {
20283
20814
  }
20284
20815
  }
20285
20816
  function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
20286
- const binDir = path20.dirname(nodeExecutable);
20817
+ const binDir = path21.dirname(nodeExecutable);
20287
20818
  if (platform10 === "win32") {
20288
- const npmCliPath = path20.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
20819
+ const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
20289
20820
  if (fs9.existsSync(npmCliPath)) {
20290
20821
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
20291
20822
  }
20292
20823
  for (const candidate of ["npm.exe", "npm"]) {
20293
- const candidatePath = path20.join(binDir, candidate);
20824
+ const candidatePath = path21.join(binDir, candidate);
20294
20825
  if (fs9.existsSync(candidatePath)) {
20295
20826
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
20296
20827
  }
@@ -20298,7 +20829,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
20298
20829
  return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
20299
20830
  }
20300
20831
  for (const candidate of ["npm"]) {
20301
- const candidatePath = path20.join(binDir, candidate);
20832
+ const candidatePath = path21.join(binDir, candidate);
20302
20833
  if (fs9.existsSync(candidatePath)) {
20303
20834
  return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
20304
20835
  }
@@ -20315,13 +20846,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20315
20846
  let currentDir = resolvedPath;
20316
20847
  try {
20317
20848
  if (fs9.statSync(resolvedPath).isFile()) {
20318
- currentDir = path20.dirname(resolvedPath);
20849
+ currentDir = path21.dirname(resolvedPath);
20319
20850
  }
20320
20851
  } catch {
20321
- currentDir = path20.dirname(resolvedPath);
20852
+ currentDir = path21.dirname(resolvedPath);
20322
20853
  }
20323
20854
  while (true) {
20324
- const packageJsonPath = path20.join(currentDir, "package.json");
20855
+ const packageJsonPath = path21.join(currentDir, "package.json");
20325
20856
  try {
20326
20857
  if (fs9.existsSync(packageJsonPath)) {
20327
20858
  const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
@@ -20332,7 +20863,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20332
20863
  }
20333
20864
  } catch {
20334
20865
  }
20335
- const parentDir = path20.dirname(currentDir);
20866
+ const parentDir = path21.dirname(currentDir);
20336
20867
  if (parentDir === currentDir) {
20337
20868
  return null;
20338
20869
  }
@@ -20340,13 +20871,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
20340
20871
  }
20341
20872
  }
20342
20873
  function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
20343
- const nodeModulesDir = packageName.startsWith("@") ? path20.dirname(path20.dirname(packageRoot)) : path20.dirname(packageRoot);
20344
- if (path20.basename(nodeModulesDir) !== "node_modules") {
20874
+ const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
20875
+ if (path21.basename(nodeModulesDir) !== "node_modules") {
20345
20876
  return null;
20346
20877
  }
20347
- const maybeLibDir = path20.dirname(nodeModulesDir);
20348
- if (path20.basename(maybeLibDir) === "lib") {
20349
- return path20.dirname(maybeLibDir);
20878
+ const maybeLibDir = path21.dirname(nodeModulesDir);
20879
+ if (path21.basename(maybeLibDir) === "lib") {
20880
+ return path21.dirname(maybeLibDir);
20350
20881
  }
20351
20882
  return maybeLibDir;
20352
20883
  }
@@ -20382,7 +20913,7 @@ function getNpmExecOptions(platform10 = process.platform) {
20382
20913
  }
20383
20914
  function execNpmCommandSync(args, options = {}, surface) {
20384
20915
  const execOptions = surface?.execOptions || getNpmExecOptions();
20385
- return execFileSync2(
20916
+ return execFileSync3(
20386
20917
  surface?.npmExecutable || "npm",
20387
20918
  [...surface?.npmArgsPrefix || [], ...args],
20388
20919
  {
@@ -20395,7 +20926,7 @@ function execNpmCommandSync(args, options = {}, surface) {
20395
20926
  function killPid(pid) {
20396
20927
  try {
20397
20928
  if (process.platform === "win32") {
20398
- execFileSync2("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
20929
+ execFileSync3("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
20399
20930
  } else {
20400
20931
  process.kill(pid, "SIGTERM");
20401
20932
  }
@@ -20407,7 +20938,7 @@ function killPid(pid) {
20407
20938
  function getWindowsProcessCommandLine(pid) {
20408
20939
  const pidFilter = `ProcessId=${pid}`;
20409
20940
  try {
20410
- const psOut = execFileSync2("powershell.exe", [
20941
+ const psOut = execFileSync3("powershell.exe", [
20411
20942
  "-NoProfile",
20412
20943
  "-NonInteractive",
20413
20944
  "-ExecutionPolicy",
@@ -20419,7 +20950,7 @@ function getWindowsProcessCommandLine(pid) {
20419
20950
  } catch {
20420
20951
  }
20421
20952
  try {
20422
- const wmicOut = execFileSync2("wmic", [
20953
+ const wmicOut = execFileSync3("wmic", [
20423
20954
  "process",
20424
20955
  "where",
20425
20956
  pidFilter,
@@ -20435,7 +20966,7 @@ function getProcessCommandLine(pid) {
20435
20966
  if (!Number.isFinite(pid) || pid <= 0) return null;
20436
20967
  if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
20437
20968
  try {
20438
- const text = execFileSync2("ps", ["-o", "command=", "-p", String(pid)], {
20969
+ const text = execFileSync3("ps", ["-o", "command=", "-p", String(pid)], {
20439
20970
  encoding: "utf8",
20440
20971
  timeout: 3e3,
20441
20972
  stdio: ["ignore", "pipe", "ignore"]
@@ -20461,7 +20992,7 @@ async function waitForPidExit(pid, timeoutMs) {
20461
20992
  }
20462
20993
  }
20463
20994
  function stopSessionHostProcesses(appName) {
20464
- const pidFile = path20.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
20995
+ const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
20465
20996
  try {
20466
20997
  if (fs9.existsSync(pidFile)) {
20467
20998
  const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
@@ -20478,7 +21009,7 @@ function stopSessionHostProcesses(appName) {
20478
21009
  }
20479
21010
  }
20480
21011
  function removeDaemonPidFile() {
20481
- const pidFile = path20.join(os18.homedir(), ".adhdev", "daemon.pid");
21012
+ const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
20482
21013
  try {
20483
21014
  fs9.unlinkSync(pidFile);
20484
21015
  } catch {
@@ -20489,7 +21020,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
20489
21020
  const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
20490
21021
  if (!npmRoot) return;
20491
21022
  const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
20492
- const binDir = process.platform === "win32" ? npmPrefix : path20.join(npmPrefix, "bin");
21023
+ const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
20493
21024
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
20494
21025
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
20495
21026
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -20497,25 +21028,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
20497
21028
  }
20498
21029
  if (pkgName.startsWith("@")) {
20499
21030
  const [scope, name] = pkgName.split("/");
20500
- const scopeDir = path20.join(npmRoot, scope);
21031
+ const scopeDir = path21.join(npmRoot, scope);
20501
21032
  if (!fs9.existsSync(scopeDir)) return;
20502
21033
  for (const entry of fs9.readdirSync(scopeDir)) {
20503
21034
  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)}`);
21035
+ fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
21036
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
20506
21037
  }
20507
21038
  } else {
20508
21039
  for (const entry of fs9.readdirSync(npmRoot)) {
20509
21040
  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)}`);
21041
+ fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
21042
+ appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
20512
21043
  }
20513
21044
  }
20514
21045
  if (fs9.existsSync(binDir)) {
20515
21046
  for (const entry of fs9.readdirSync(binDir)) {
20516
21047
  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)}`);
21048
+ fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
21049
+ appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
20519
21050
  }
20520
21051
  }
20521
21052
  }
@@ -20551,7 +21082,7 @@ async function runDaemonUpgradeHelper(payload) {
20551
21082
  cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
20552
21083
  const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
20553
21084
  appendUpgradeLog(`Installing ${spec}`);
20554
- const installOutput = execFileSync2(
21085
+ const installOutput = execFileSync3(
20555
21086
  installCommand.command,
20556
21087
  installCommand.args,
20557
21088
  {
@@ -20616,6 +21147,56 @@ function normalizeReleaseChannel(value) {
20616
21147
  function resolveUpgradeChannel(args) {
20617
21148
  return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
20618
21149
  }
21150
+ function readProviderPriorityFromPolicy(policy) {
21151
+ const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
21152
+ const raw = record.providerPriority;
21153
+ if (!Array.isArray(raw)) return [];
21154
+ const seen = /* @__PURE__ */ new Set();
21155
+ return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
21156
+ if (seen.has(type)) return false;
21157
+ seen.add(type);
21158
+ return true;
21159
+ });
21160
+ }
21161
+ async function resolveProviderTypeFromPriority(args) {
21162
+ if (!args.providerPriority.length) {
21163
+ return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
21164
+ }
21165
+ const failed = [];
21166
+ for (const requestedType of args.providerPriority) {
21167
+ const normalizedType = args.providerLoader.resolveAlias(requestedType);
21168
+ if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
21169
+ failed.push(`${requestedType}: disabled`);
21170
+ continue;
21171
+ }
21172
+ const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
21173
+ args.providerLoader.setCliDetectionResults([{
21174
+ id: normalizedType,
21175
+ installed: !!detected,
21176
+ path: detected?.path
21177
+ }], false);
21178
+ args.onStatusChange?.();
21179
+ if (detected) return { providerType: normalizedType };
21180
+ failed.push(`${requestedType}: not detected`);
21181
+ }
21182
+ return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
21183
+ }
21184
+ function loadYamlModule() {
21185
+ return yaml;
21186
+ }
21187
+ function getMcpServersKey(format) {
21188
+ return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
21189
+ }
21190
+ function parseMeshCoordinatorMcpConfig(text, format) {
21191
+ if (!text.trim()) return {};
21192
+ if (format === "claude_mcp_json") return JSON.parse(text);
21193
+ const parsed = loadYamlModule().load(text);
21194
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
21195
+ }
21196
+ function serializeMeshCoordinatorMcpConfig(config, format) {
21197
+ if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
21198
+ return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
21199
+ }
20619
21200
  var CHAT_COMMANDS = [
20620
21201
  "send_chat",
20621
21202
  "new_chat",
@@ -20714,6 +21295,154 @@ var DaemonCommandRouter = class {
20714
21295
  constructor(deps) {
20715
21296
  this.deps = deps;
20716
21297
  }
21298
+ getCachedInlineMesh(meshId, inlineMesh) {
21299
+ if (inlineMesh && typeof inlineMesh === "object") {
21300
+ this.inlineMeshCache.set(meshId, inlineMesh);
21301
+ return inlineMesh;
21302
+ }
21303
+ return this.inlineMeshCache.get(meshId);
21304
+ }
21305
+ async getMeshForCommand(meshId, inlineMesh) {
21306
+ try {
21307
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21308
+ const mesh = getMesh3(meshId);
21309
+ if (mesh) return { mesh, inline: false };
21310
+ } catch {
21311
+ }
21312
+ const cached = this.getCachedInlineMesh(meshId, inlineMesh);
21313
+ return cached ? { mesh: cached, inline: true } : null;
21314
+ }
21315
+ updateInlineMeshNode(meshId, mesh, node) {
21316
+ if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
21317
+ const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
21318
+ if (idx >= 0) mesh.nodes[idx] = node;
21319
+ else mesh.nodes.push(node);
21320
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21321
+ this.inlineMeshCache.set(meshId, mesh);
21322
+ }
21323
+ removeInlineMeshNode(meshId, mesh, nodeId) {
21324
+ if (!mesh || !Array.isArray(mesh.nodes)) return false;
21325
+ const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
21326
+ if (idx === -1) return false;
21327
+ mesh.nodes.splice(idx, 1);
21328
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
21329
+ this.inlineMeshCache.set(meshId, mesh);
21330
+ return true;
21331
+ }
21332
+ normalizeMeshSessionCleanupMode(value) {
21333
+ return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
21334
+ }
21335
+ sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
21336
+ const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
21337
+ if (!sessionId) return false;
21338
+ if (sessionIds?.size) return sessionIds.has(sessionId);
21339
+ const workspace = typeof node?.workspace === "string" ? node.workspace : "";
21340
+ if (workspace && record?.workspace === workspace) return true;
21341
+ if (record?.meta?.meshNodeId === nodeId) return true;
21342
+ return false;
21343
+ }
21344
+ isCompletedHostedSession(record) {
21345
+ return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
21346
+ }
21347
+ async cleanupMeshSessions(args) {
21348
+ if (args.mode === "preserve") {
21349
+ return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
21350
+ }
21351
+ if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
21352
+ const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
21353
+ const sessions = await this.deps.sessionHostControl.listSessions();
21354
+ const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
21355
+ const hasExplicitSessionIds = !!requestedSessionIds?.size;
21356
+ const stoppedSessionIds = [];
21357
+ const deletedSessionIds = [];
21358
+ const skippedSessionIds = [];
21359
+ const skippedLiveSessionIds = [];
21360
+ const deleteUnsupportedSessionIds = [];
21361
+ const recordsRemainSessionIds = [];
21362
+ const errors = [];
21363
+ const matchedBySurfaceKind = {
21364
+ live_runtime: 0,
21365
+ recovery_snapshot: 0,
21366
+ inactive_record: 0
21367
+ };
21368
+ for (const record of matched) {
21369
+ const surfaceKind = getSessionHostSurfaceKind(record);
21370
+ matchedBySurfaceKind[surfaceKind] += 1;
21371
+ }
21372
+ for (const record of matched) {
21373
+ const sessionId = String(record.sessionId);
21374
+ const completed = this.isCompletedHostedSession(record);
21375
+ const surfaceKind = getSessionHostSurfaceKind(record);
21376
+ const liveRuntime = surfaceKind === "live_runtime";
21377
+ if (!hasExplicitSessionIds && liveRuntime) {
21378
+ skippedSessionIds.push(sessionId);
21379
+ skippedLiveSessionIds.push(sessionId);
21380
+ continue;
21381
+ }
21382
+ try {
21383
+ if (args.mode === "stop") {
21384
+ if (!completed) {
21385
+ if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
21386
+ stoppedSessionIds.push(sessionId);
21387
+ } else {
21388
+ skippedSessionIds.push(sessionId);
21389
+ }
21390
+ continue;
21391
+ }
21392
+ if (args.mode === "delete_stopped") {
21393
+ if (completed) {
21394
+ if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
21395
+ deletedSessionIds.push(sessionId);
21396
+ } else {
21397
+ skippedSessionIds.push(sessionId);
21398
+ }
21399
+ continue;
21400
+ }
21401
+ if (args.mode === "stop_and_delete") {
21402
+ if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
21403
+ deletedSessionIds.push(sessionId);
21404
+ continue;
21405
+ }
21406
+ } catch (e) {
21407
+ const message = e?.message || String(e);
21408
+ if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
21409
+ deleteUnsupportedSessionIds.push(sessionId);
21410
+ recordsRemainSessionIds.push(sessionId);
21411
+ if (args.mode === "stop_and_delete" && !completed) {
21412
+ try {
21413
+ await this.deps.sessionHostControl.stopSession(sessionId);
21414
+ stoppedSessionIds.push(sessionId);
21415
+ } catch (stopError) {
21416
+ errors.push({ sessionId, error: stopError?.message || String(stopError) });
21417
+ continue;
21418
+ }
21419
+ }
21420
+ skippedSessionIds.push(sessionId);
21421
+ continue;
21422
+ }
21423
+ errors.push({ sessionId, error: message });
21424
+ }
21425
+ }
21426
+ const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
21427
+ return {
21428
+ success: errors.length === 0,
21429
+ mode: args.mode,
21430
+ dryRun: args.dryRun === true,
21431
+ matchedCount: matched.length,
21432
+ matchedBySurfaceKind,
21433
+ stoppedSessionIds,
21434
+ deletedSessionIds,
21435
+ skippedSessionIds,
21436
+ skippedLiveSessionIds,
21437
+ ...deleteUnsupported ? {
21438
+ deleteUnsupported: true,
21439
+ effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
21440
+ deleteUnsupportedSessionIds,
21441
+ recordsRemainSessionIds
21442
+ } : {},
21443
+ ...errors.length ? { errors } : {}
21444
+ };
21445
+ }
20717
21446
  async traceSessionHostAction(action, args, run, summarizeResult) {
20718
21447
  const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
20719
21448
  const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
@@ -20833,6 +21562,9 @@ var DaemonCommandRouter = class {
20833
21562
  async executeDaemonCommand(cmd, args) {
20834
21563
  switch (cmd) {
20835
21564
  // ─── CLI / ACP commands ───
21565
+ case "mesh_forward_event": {
21566
+ return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
21567
+ }
20836
21568
  case "launch_cli":
20837
21569
  case "stop_cli":
20838
21570
  case "set_cli_view_mode":
@@ -21377,7 +22109,26 @@ var DaemonCommandRouter = class {
21377
22109
  if (!name) return { success: false, error: "name required" };
21378
22110
  try {
21379
22111
  const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21380
- const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
22112
+ const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
22113
+ return { success: true, mesh };
22114
+ } catch (e) {
22115
+ return { success: false, error: e.message };
22116
+ }
22117
+ }
22118
+ case "update_mesh": {
22119
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22120
+ if (!meshId) return { success: false, error: "meshId required" };
22121
+ try {
22122
+ const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22123
+ const patch = {};
22124
+ if (typeof args?.name === "string") patch.name = args.name;
22125
+ if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
22126
+ if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
22127
+ if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
22128
+ if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
22129
+ const mesh = updateMesh2(meshId, patch);
22130
+ if (!mesh) return { success: false, error: "Mesh not found" };
22131
+ this.inlineMeshCache.set(meshId, mesh);
21381
22132
  return { success: true, mesh };
21382
22133
  } catch (e) {
21383
22134
  return { success: false, error: e.message };
@@ -21401,21 +22152,164 @@ var DaemonCommandRouter = class {
21401
22152
  if (!workspace) return { success: false, error: "workspace required" };
21402
22153
  try {
21403
22154
  const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21404
- const node = addNode3(meshId, { workspace });
22155
+ const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
22156
+ const readOnly = args?.readOnly === true;
22157
+ const policy = {
22158
+ ...readOnly ? { readOnly: true } : {},
22159
+ ...providerPriority.length ? { providerPriority } : {}
22160
+ };
22161
+ const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
21405
22162
  if (!node) return { success: false, error: "Mesh not found" };
21406
22163
  return { success: true, node };
21407
22164
  } catch (e) {
21408
22165
  return { success: false, error: e.message };
21409
22166
  }
21410
22167
  }
22168
+ case "update_mesh_node": {
22169
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22170
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
22171
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
22172
+ try {
22173
+ const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22174
+ const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
22175
+ if (Array.isArray(args?.providerPriority)) {
22176
+ const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
22177
+ delete policy.provider_priority;
22178
+ if (providerPriority.length) {
22179
+ policy.providerPriority = providerPriority;
22180
+ } else {
22181
+ delete policy.providerPriority;
22182
+ }
22183
+ }
22184
+ const node = updateNode2(meshId, nodeId, { policy });
22185
+ if (!node) return { success: false, error: "Mesh node not found" };
22186
+ return { success: true, node };
22187
+ } catch (e) {
22188
+ return { success: false, error: e.message };
22189
+ }
22190
+ }
22191
+ case "cleanup_mesh_sessions": {
22192
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22193
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
22194
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
22195
+ try {
22196
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22197
+ const mesh = meshRecord?.mesh;
22198
+ if (!mesh) return { success: false, error: "Mesh not found" };
22199
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
22200
+ if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
22201
+ const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
22202
+ const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
22203
+ const result = await this.cleanupMeshSessions({
22204
+ meshId,
22205
+ nodeId,
22206
+ node,
22207
+ mode,
22208
+ sessionIds,
22209
+ dryRun: args?.dryRun === true
22210
+ });
22211
+ return result;
22212
+ } catch (e) {
22213
+ return { success: false, error: e.message };
22214
+ }
22215
+ }
21411
22216
  case "remove_mesh_node": {
21412
22217
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21413
22218
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
21414
22219
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
21415
22220
  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 };
22221
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22222
+ const mesh = meshRecord?.mesh;
22223
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
22224
+ const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
22225
+ args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
22226
+ );
22227
+ let sessionCleanup;
22228
+ if (node && sessionCleanupMode !== "preserve") {
22229
+ sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
22230
+ if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
22231
+ }
22232
+ if (node?.isLocalWorktree && node.workspace) {
22233
+ try {
22234
+ const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
22235
+ const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
22236
+ if (repoRoot) {
22237
+ const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22238
+ await removeWorktree2(repoRoot, node.workspace);
22239
+ }
22240
+ } catch (e) {
22241
+ LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
22242
+ }
22243
+ }
22244
+ let removed = false;
22245
+ if (meshRecord?.inline) {
22246
+ removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
22247
+ } else {
22248
+ const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22249
+ removed = removeNode3(meshId, nodeId);
22250
+ }
22251
+ return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
22252
+ } catch (e) {
22253
+ return { success: false, error: e.message };
22254
+ }
22255
+ }
22256
+ case "clone_mesh_node": {
22257
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
22258
+ const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
22259
+ const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
22260
+ const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
22261
+ if (!meshId) return { success: false, error: "meshId required" };
22262
+ if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
22263
+ if (!branch) return { success: false, error: "branch required" };
22264
+ try {
22265
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
22266
+ const mesh = meshRecord?.mesh;
22267
+ if (!mesh) return { success: false, error: "Mesh not found" };
22268
+ const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
22269
+ if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
22270
+ const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
22271
+ const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
22272
+ const result = await createWorktree2({
22273
+ repoRoot,
22274
+ branch,
22275
+ baseBranch,
22276
+ meshName: mesh.name
22277
+ });
22278
+ let node;
22279
+ if (meshRecord.inline) {
22280
+ const { randomUUID: randomUUID8 } = await import("crypto");
22281
+ node = {
22282
+ id: `node_${randomUUID8().replace(/-/g, "")}`,
22283
+ workspace: result.worktreePath,
22284
+ repoRoot: result.worktreePath,
22285
+ daemonId: sourceNode.daemonId,
22286
+ userOverrides: { ...sourceNode.userOverrides || {} },
22287
+ policy: { ...sourceNode.policy || {} },
22288
+ isLocalWorktree: true,
22289
+ worktreeBranch: result.branch,
22290
+ clonedFromNodeId: sourceNodeId
22291
+ };
22292
+ this.updateInlineMeshNode(meshId, mesh, node);
22293
+ } else {
22294
+ const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
22295
+ node = addNode3(meshId, {
22296
+ workspace: result.worktreePath,
22297
+ repoRoot: result.worktreePath,
22298
+ daemonId: sourceNode.daemonId,
22299
+ userOverrides: { ...sourceNode.userOverrides || {} },
22300
+ isLocalWorktree: true,
22301
+ worktreeBranch: result.branch,
22302
+ clonedFromNodeId: sourceNodeId,
22303
+ policy: { ...sourceNode.policy || {} }
22304
+ });
22305
+ if (!node) return { success: false, error: "Failed to register worktree node" };
22306
+ }
22307
+ return {
22308
+ success: true,
22309
+ node,
22310
+ worktreePath: result.worktreePath,
22311
+ branch: result.branch
22312
+ };
21419
22313
  } catch (e) {
21420
22314
  return { success: false, error: e.message };
21421
22315
  }
@@ -21423,7 +22317,7 @@ var DaemonCommandRouter = class {
21423
22317
  // ─── Mesh Coordinator Launch ───
21424
22318
  case "launch_mesh_coordinator": {
21425
22319
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21426
- const cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "claude-cli";
22320
+ let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
21427
22321
  if (!meshId) return { success: false, error: "meshId required" };
21428
22322
  try {
21429
22323
  const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
@@ -21451,9 +22345,29 @@ var DaemonCommandRouter = class {
21451
22345
  }
21452
22346
  const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
21453
22347
  if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
22348
+ if (!cliType) {
22349
+ const resolved = await resolveProviderTypeFromPriority({
22350
+ nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
22351
+ providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
22352
+ providerLoader: this.deps.providerLoader,
22353
+ onStatusChange: this.deps.onStatusChange
22354
+ });
22355
+ if (!resolved.providerType) {
22356
+ return {
22357
+ success: false,
22358
+ code: "mesh_coordinator_provider_priority_unusable",
22359
+ error: resolved.error || "No usable provider found from node providerPriority",
22360
+ meshId,
22361
+ cliType,
22362
+ workspace
22363
+ };
22364
+ }
22365
+ cliType = resolved.providerType;
22366
+ }
21454
22367
  const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
21455
22368
  const coordinatorSetup = resolveMeshCoordinatorSetup({
21456
22369
  provider: providerMeta,
22370
+ cliType,
21457
22371
  meshId,
21458
22372
  workspace
21459
22373
  });
@@ -21478,7 +22392,8 @@ var DaemonCommandRouter = class {
21478
22392
  meshCoordinatorSetup: coordinatorSetup
21479
22393
  };
21480
22394
  }
21481
- if (coordinatorSetup.configFormat !== "claude_mcp_json") {
22395
+ const configFormat = coordinatorSetup.configFormat;
22396
+ if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
21482
22397
  return {
21483
22398
  success: false,
21484
22399
  code: "mesh_coordinator_unsupported",
@@ -21488,44 +22403,93 @@ var DaemonCommandRouter = class {
21488
22403
  workspace
21489
22404
  };
21490
22405
  }
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
- }
22406
+ let systemPrompt = "";
22407
+ try {
22408
+ systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
22409
+ } catch (error) {
22410
+ const message = error?.message || String(error);
22411
+ LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
22412
+ return {
22413
+ success: false,
22414
+ code: "mesh_coordinator_prompt_failed",
22415
+ error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
22416
+ meshId,
22417
+ cliType,
22418
+ workspace
22419
+ };
21501
22420
  }
22421
+ const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
22422
+ const { dirname: dirname9 } = await import("path");
22423
+ const mcpConfigPath = coordinatorSetup.configPath;
22424
+ const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
22425
+ const returnManualFallback = (message) => ({
22426
+ success: false,
22427
+ code: "mesh_coordinator_manual_mcp_setup_required",
22428
+ error: message,
22429
+ meshId,
22430
+ cliType,
22431
+ workspace,
22432
+ meshCoordinatorSetup: hermesManualFallback
22433
+ });
21502
22434
  const mcpServerEntry = {
21503
22435
  command: coordinatorSetup.mcpServer.command,
21504
22436
  args: coordinatorSetup.mcpServer.args
21505
22437
  };
21506
22438
  if (args?.inlineMesh) {
21507
22439
  mcpServerEntry.env = {
21508
- ADHDEV_INLINE_MESH: JSON.stringify(mesh)
22440
+ ADHDEV_INLINE_MESH: JSON.stringify(mesh),
22441
+ ADHDEV_MCP_TRANSPORT: "ipc"
21509
22442
  };
21510
22443
  }
22444
+ try {
22445
+ mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
22446
+ } catch (error) {
22447
+ const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
22448
+ LOG.error("MeshCoordinator", message);
22449
+ if (hermesManualFallback) return returnManualFallback(message);
22450
+ return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
22451
+ }
22452
+ const hadExistingMcpConfig = existsSync23(mcpConfigPath);
22453
+ let existingMcpConfig = {};
22454
+ if (hadExistingMcpConfig) {
22455
+ try {
22456
+ existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
22457
+ copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
22458
+ } catch (error) {
22459
+ LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
22460
+ return {
22461
+ success: false,
22462
+ code: "mesh_coordinator_config_parse_failed",
22463
+ error: `Failed to parse existing MCP config at ${mcpConfigPath}`
22464
+ };
22465
+ }
22466
+ }
22467
+ const mcpServersKey = getMcpServersKey(configFormat);
22468
+ const existingServers = existingMcpConfig[mcpServersKey];
21511
22469
  const mcpConfig = {
21512
22470
  ...existingMcpConfig,
21513
- mcpServers: {
21514
- ...existingMcpConfig.mcpServers || {},
22471
+ [mcpServersKey]: {
22472
+ ...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
21515
22473
  [coordinatorSetup.serverName]: mcpServerEntry
21516
22474
  }
21517
22475
  };
21518
- writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
21519
- LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
21520
- let systemPrompt = "";
21521
22476
  try {
21522
- systemPrompt = buildCoordinatorSystemPrompt2({ mesh });
21523
- } catch {
21524
- systemPrompt = `You are a Repo Mesh Coordinator for "${mesh.name}". Use the adhdev-mesh MCP tools (mesh_status, mesh_list_nodes, mesh_send_task, mesh_read_chat, mesh_launch_session, etc.) to orchestrate work across ${mesh.nodes.length} node(s).`;
22477
+ writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
22478
+ } catch (error) {
22479
+ const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
22480
+ LOG.error("MeshCoordinator", message);
22481
+ if (hermesManualFallback) return returnManualFallback(message);
22482
+ return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
21525
22483
  }
22484
+ LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
21526
22485
  const cliArgs = [];
22486
+ const launchEnv = {};
21527
22487
  if (systemPrompt) {
21528
- cliArgs.push("--append-system-prompt", systemPrompt);
22488
+ if (configFormat === "hermes_config_yaml") {
22489
+ launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
22490
+ } else {
22491
+ cliArgs.push("--append-system-prompt", systemPrompt);
22492
+ }
21529
22493
  }
21530
22494
  if (cliType === "claude-cli") {
21531
22495
  cliArgs.push("--mcp-config", coordinatorSetup.configPath);
@@ -21534,6 +22498,7 @@ var DaemonCommandRouter = class {
21534
22498
  cliType,
21535
22499
  dir: workspace,
21536
22500
  cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
22501
+ env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
21537
22502
  settings: {
21538
22503
  meshCoordinatorFor: meshId
21539
22504
  }
@@ -21713,6 +22678,12 @@ var DaemonStatusReporter = class {
21713
22678
  if (providerType) {
21714
22679
  payload.providerType = providerType;
21715
22680
  }
22681
+ if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
22682
+ payload.providerSessionId = event.providerSessionId.trim();
22683
+ }
22684
+ if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
22685
+ payload.workspaceName = event.workspaceName.trim();
22686
+ }
21716
22687
  if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
21717
22688
  payload.duration = event.duration;
21718
22689
  }
@@ -22960,7 +23931,10 @@ var ProviderInstanceManager = class {
22960
23931
  this.instances.get(id).dispose();
22961
23932
  }
22962
23933
  this.instances.set(id, instance);
22963
- await instance.init(context);
23934
+ await instance.init({
23935
+ ...context,
23936
+ emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
23937
+ });
22964
23938
  }
22965
23939
  /**
22966
23940
  * Instance remove
@@ -23122,6 +24096,17 @@ var ProviderInstanceManager = class {
23122
24096
  onEvent(listener) {
23123
24097
  this.eventListeners.push(listener);
23124
24098
  }
24099
+ emitProviderEvent(providerType, instanceId, event) {
24100
+ const payload = {
24101
+ ...event,
24102
+ providerType,
24103
+ instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
24104
+ targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
24105
+ };
24106
+ for (const listener of this.eventListeners) {
24107
+ listener(payload);
24108
+ }
24109
+ }
23125
24110
  emitPendingEvents(providerType, state, extra = {}) {
23126
24111
  for (const event of state.pendingEvents) {
23127
24112
  for (const listener of this.eventListeners) {
@@ -23194,11 +24179,11 @@ var ProviderInstanceManager = class {
23194
24179
 
23195
24180
  // src/providers/version-archive.ts
23196
24181
  import * as fs11 from "fs";
23197
- import * as path21 from "path";
23198
- import * as os19 from "os";
24182
+ import * as path22 from "path";
24183
+ import * as os20 from "os";
23199
24184
  import { execSync as execSync5 } from "child_process";
23200
24185
  import { platform as platform8 } from "os";
23201
- var ARCHIVE_PATH = path21.join(os19.homedir(), ".adhdev", "version-history.json");
24186
+ var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
23202
24187
  var MAX_ENTRIES_PER_PROVIDER = 20;
23203
24188
  var VersionArchive = class {
23204
24189
  history = {};
@@ -23245,7 +24230,7 @@ var VersionArchive = class {
23245
24230
  }
23246
24231
  save() {
23247
24232
  try {
23248
- fs11.mkdirSync(path21.dirname(ARCHIVE_PATH), { recursive: true });
24233
+ fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
23249
24234
  fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
23250
24235
  } catch {
23251
24236
  }
@@ -23301,8 +24286,8 @@ function getVersion(binary, versionCommand) {
23301
24286
  function checkPathExists2(paths) {
23302
24287
  for (const p of paths) {
23303
24288
  if (p.includes("*")) {
23304
- const home = os19.homedir();
23305
- const resolved = p.replace(/\*/g, home.split(path21.sep).pop() || "");
24289
+ const home = os20.homedir();
24290
+ const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
23306
24291
  if (fs11.existsSync(resolved)) return resolved;
23307
24292
  } else {
23308
24293
  if (fs11.existsSync(p)) return p;
@@ -23312,7 +24297,7 @@ function checkPathExists2(paths) {
23312
24297
  }
23313
24298
  function getMacAppVersion(appPath) {
23314
24299
  if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
23315
- const plistPath = path21.join(appPath, "Contents", "Info.plist");
24300
+ const plistPath = path22.join(appPath, "Contents", "Info.plist");
23316
24301
  if (!fs11.existsSync(plistPath)) return null;
23317
24302
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
23318
24303
  return raw || null;
@@ -23338,7 +24323,7 @@ async function detectAllVersions(loader, archive) {
23338
24323
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
23339
24324
  let resolvedBin = cliBin;
23340
24325
  if (!resolvedBin && appPath && currentOs === "darwin") {
23341
- const bundled = path21.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
24326
+ const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
23342
24327
  if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
23343
24328
  }
23344
24329
  info.installed = !!(appPath || resolvedBin);
@@ -23379,7 +24364,7 @@ async function detectAllVersions(loader, archive) {
23379
24364
  // src/daemon/dev-server.ts
23380
24365
  import * as http2 from "http";
23381
24366
  import * as fs15 from "fs";
23382
- import * as path25 from "path";
24367
+ import * as path26 from "path";
23383
24368
  init_config();
23384
24369
 
23385
24370
  // src/daemon/scaffold-template.ts
@@ -23731,7 +24716,7 @@ init_logger();
23731
24716
  // src/daemon/dev-cdp-handlers.ts
23732
24717
  init_logger();
23733
24718
  import * as fs12 from "fs";
23734
- import * as path22 from "path";
24719
+ import * as path23 from "path";
23735
24720
  async function handleCdpEvaluate(ctx, req, res) {
23736
24721
  const body = await ctx.readBody(req);
23737
24722
  const { expression, timeout, ideType } = body;
@@ -23909,17 +24894,17 @@ async function handleScriptHints(ctx, type, _req, res) {
23909
24894
  return;
23910
24895
  }
23911
24896
  let scriptsPath = "";
23912
- const directScripts = path22.join(dir, "scripts.js");
24897
+ const directScripts = path23.join(dir, "scripts.js");
23913
24898
  if (fs12.existsSync(directScripts)) {
23914
24899
  scriptsPath = directScripts;
23915
24900
  } else {
23916
- const scriptsDir = path22.join(dir, "scripts");
24901
+ const scriptsDir = path23.join(dir, "scripts");
23917
24902
  if (fs12.existsSync(scriptsDir)) {
23918
24903
  const versions = fs12.readdirSync(scriptsDir).filter((d) => {
23919
- return fs12.statSync(path22.join(scriptsDir, d)).isDirectory();
24904
+ return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
23920
24905
  }).sort().reverse();
23921
24906
  for (const ver of versions) {
23922
- const p = path22.join(scriptsDir, ver, "scripts.js");
24907
+ const p = path23.join(scriptsDir, ver, "scripts.js");
23923
24908
  if (fs12.existsSync(p)) {
23924
24909
  scriptsPath = p;
23925
24910
  break;
@@ -24748,7 +25733,7 @@ async function handleDomContext(ctx, type, req, res) {
24748
25733
 
24749
25734
  // src/daemon/dev-cli-debug.ts
24750
25735
  import * as fs13 from "fs";
24751
- import * as path23 from "path";
25736
+ import * as path24 from "path";
24752
25737
  function slugifyFixtureName(value) {
24753
25738
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
24754
25739
  return normalized || `fixture-${Date.now()}`;
@@ -24758,11 +25743,11 @@ function getCliFixtureDir(ctx, type) {
24758
25743
  if (!providerDir) {
24759
25744
  throw new Error(`Provider directory not found for '${type}'`);
24760
25745
  }
24761
- return path23.join(providerDir, "fixtures");
25746
+ return path24.join(providerDir, "fixtures");
24762
25747
  }
24763
25748
  function readCliFixture(ctx, type, name) {
24764
25749
  const fixtureDir = getCliFixtureDir(ctx, type);
24765
- const filePath = path23.join(fixtureDir, `${name}.json`);
25750
+ const filePath = path24.join(fixtureDir, `${name}.json`);
24766
25751
  if (!fs13.existsSync(filePath)) {
24767
25752
  throw new Error(`Fixture not found: ${filePath}`);
24768
25753
  }
@@ -25529,7 +26514,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
25529
26514
  },
25530
26515
  notes: typeof body?.notes === "string" ? body.notes : void 0
25531
26516
  };
25532
- const filePath = path23.join(fixtureDir, `${name}.json`);
26517
+ const filePath = path24.join(fixtureDir, `${name}.json`);
25533
26518
  fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
25534
26519
  ctx.json(res, 200, {
25535
26520
  saved: true,
@@ -25553,7 +26538,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
25553
26538
  return;
25554
26539
  }
25555
26540
  const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
25556
- const fullPath = path23.join(fixtureDir, file);
26541
+ const fullPath = path24.join(fixtureDir, file);
25557
26542
  try {
25558
26543
  const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
25559
26544
  return {
@@ -25689,8 +26674,8 @@ async function handleCliRaw(ctx, req, res) {
25689
26674
 
25690
26675
  // src/daemon/dev-auto-implement.ts
25691
26676
  import * as fs14 from "fs";
25692
- import * as path24 from "path";
25693
- import * as os20 from "os";
26677
+ import * as path25 from "path";
26678
+ import * as os21 from "os";
25694
26679
  function getAutoImplPid(ctx) {
25695
26680
  const pid = ctx.autoImplProcess?.pid;
25696
26681
  return typeof pid === "number" && pid > 0 ? pid : null;
@@ -25739,22 +26724,22 @@ function getLatestScriptVersionDir(scriptsDir) {
25739
26724
  if (!fs14.existsSync(scriptsDir)) return null;
25740
26725
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
25741
26726
  try {
25742
- return fs14.statSync(path24.join(scriptsDir, d)).isDirectory();
26727
+ return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
25743
26728
  } catch {
25744
26729
  return false;
25745
26730
  }
25746
26731
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
25747
26732
  if (versions.length === 0) return null;
25748
- return path24.join(scriptsDir, versions[0]);
26733
+ return path25.join(scriptsDir, versions[0]);
25749
26734
  }
25750
26735
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
25751
- const canonicalUserDir = path24.resolve(ctx.providerLoader.getUserProviderDir(category, type));
25752
- const desiredDir = requestedDir ? path24.resolve(requestedDir) : canonicalUserDir;
25753
- const upstreamRoot = path24.resolve(ctx.providerLoader.getUpstreamDir());
25754
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path24.sep}`)) {
26736
+ const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
26737
+ const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
26738
+ const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
26739
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
25755
26740
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
25756
26741
  }
25757
- if (path24.basename(desiredDir) !== type) {
26742
+ if (path25.basename(desiredDir) !== type) {
25758
26743
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
25759
26744
  }
25760
26745
  const sourceDir = ctx.findProviderDir(type);
@@ -25762,11 +26747,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
25762
26747
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
25763
26748
  }
25764
26749
  if (!fs14.existsSync(desiredDir)) {
25765
- fs14.mkdirSync(path24.dirname(desiredDir), { recursive: true });
26750
+ fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
25766
26751
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
25767
26752
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
25768
26753
  }
25769
- const providerJson = path24.join(desiredDir, "provider.json");
26754
+ const providerJson = path25.join(desiredDir, "provider.json");
25770
26755
  if (!fs14.existsSync(providerJson)) {
25771
26756
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
25772
26757
  }
@@ -25777,13 +26762,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
25777
26762
  const refDir = ctx.findProviderDir(referenceType);
25778
26763
  if (!refDir || !fs14.existsSync(refDir)) return {};
25779
26764
  const referenceScripts = {};
25780
- const scriptsDir = path24.join(refDir, "scripts");
26765
+ const scriptsDir = path25.join(refDir, "scripts");
25781
26766
  const latestDir = getLatestScriptVersionDir(scriptsDir);
25782
26767
  if (!latestDir) return referenceScripts;
25783
26768
  for (const file of fs14.readdirSync(latestDir)) {
25784
26769
  if (!file.endsWith(".js")) continue;
25785
26770
  try {
25786
- referenceScripts[file] = fs14.readFileSync(path24.join(latestDir, file), "utf-8");
26771
+ referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
25787
26772
  } catch {
25788
26773
  }
25789
26774
  }
@@ -25891,9 +26876,9 @@ async function handleAutoImplement(ctx, type, req, res) {
25891
26876
  });
25892
26877
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
25893
26878
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
25894
- const tmpDir = path24.join(os20.tmpdir(), "adhdev-autoimpl");
26879
+ const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
25895
26880
  if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
25896
- const promptFile = path24.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
26881
+ const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
25897
26882
  fs14.writeFileSync(promptFile, prompt, "utf-8");
25898
26883
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
25899
26884
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -26046,7 +27031,7 @@ async function handleAutoImplement(ctx, type, req, res) {
26046
27031
  const interactiveFlags = ["--yolo", "--interactive", "-i"];
26047
27032
  const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
26048
27033
  let shellCmd;
26049
- const isWin = os20.platform() === "win32";
27034
+ const isWin = os21.platform() === "win32";
26050
27035
  const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
26051
27036
  const promptMode = autoImpl?.promptMode ?? "stdin";
26052
27037
  const extraArgs = autoImpl?.extraArgs ?? [];
@@ -26085,7 +27070,7 @@ async function handleAutoImplement(ctx, type, req, res) {
26085
27070
  try {
26086
27071
  const pty = __require("node-pty");
26087
27072
  ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
26088
- const isWin2 = os20.platform() === "win32";
27073
+ const isWin2 = os21.platform() === "win32";
26089
27074
  child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
26090
27075
  name: "xterm-256color",
26091
27076
  cols: 120,
@@ -26325,7 +27310,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26325
27310
  setMode: "set_mode.js"
26326
27311
  };
26327
27312
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26328
- const scriptsDir = path24.join(providerDir, "scripts");
27313
+ const scriptsDir = path25.join(providerDir, "scripts");
26329
27314
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
26330
27315
  if (latestScriptsDir) {
26331
27316
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26336,7 +27321,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26336
27321
  for (const file of fs14.readdirSync(latestScriptsDir)) {
26337
27322
  if (file.endsWith(".js") && targetFileNames.has(file)) {
26338
27323
  try {
26339
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27324
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26340
27325
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26341
27326
  lines.push("```javascript");
26342
27327
  lines.push(content);
@@ -26353,7 +27338,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26353
27338
  lines.push("");
26354
27339
  for (const file of refFiles) {
26355
27340
  try {
26356
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27341
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26357
27342
  lines.push(`### \`${file}\` \u{1F512}`);
26358
27343
  lines.push("```javascript");
26359
27344
  lines.push(content);
@@ -26394,10 +27379,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
26394
27379
  lines.push("");
26395
27380
  }
26396
27381
  }
26397
- const docsDir = path24.join(providerDir, "../../docs");
27382
+ const docsDir = path25.join(providerDir, "../../docs");
26398
27383
  const loadGuide = (name) => {
26399
27384
  try {
26400
- const p = path24.join(docsDir, name);
27385
+ const p = path25.join(docsDir, name);
26401
27386
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
26402
27387
  } catch {
26403
27388
  }
@@ -26634,7 +27619,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26634
27619
  parseApproval: "parse_approval.js"
26635
27620
  };
26636
27621
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
26637
- const scriptsDir = path24.join(providerDir, "scripts");
27622
+ const scriptsDir = path25.join(providerDir, "scripts");
26638
27623
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
26639
27624
  if (latestScriptsDir) {
26640
27625
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -26646,7 +27631,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26646
27631
  if (!file.endsWith(".js")) continue;
26647
27632
  if (!targetFileNames.has(file)) continue;
26648
27633
  try {
26649
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27634
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26650
27635
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
26651
27636
  lines.push("```javascript");
26652
27637
  lines.push(content);
@@ -26662,7 +27647,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26662
27647
  lines.push("");
26663
27648
  for (const file of refFiles) {
26664
27649
  try {
26665
- const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
27650
+ const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
26666
27651
  lines.push(`### \`${file}\` \u{1F512}`);
26667
27652
  lines.push("```javascript");
26668
27653
  lines.push(content);
@@ -26695,10 +27680,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
26695
27680
  lines.push("");
26696
27681
  }
26697
27682
  }
26698
- const docsDir = path24.join(providerDir, "../../docs");
27683
+ const docsDir = path25.join(providerDir, "../../docs");
26699
27684
  const loadGuide = (name) => {
26700
27685
  try {
26701
- const p = path24.join(docsDir, name);
27686
+ const p = path25.join(docsDir, name);
26702
27687
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
26703
27688
  } catch {
26704
27689
  }
@@ -27145,8 +28130,8 @@ var DevServer = class _DevServer {
27145
28130
  }
27146
28131
  getEndpointList() {
27147
28132
  return this.routes.map((r) => {
27148
- const path26 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
27149
- return `${r.method.padEnd(5)} ${path26}`;
28133
+ const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
28134
+ return `${r.method.padEnd(5)} ${path27}`;
27150
28135
  });
27151
28136
  }
27152
28137
  async start(port = DEV_SERVER_PORT) {
@@ -27434,12 +28419,12 @@ var DevServer = class _DevServer {
27434
28419
  // ─── DevConsole SPA ───
27435
28420
  getConsoleDistDir() {
27436
28421
  const candidates = [
27437
- path25.resolve(__dirname, "../../web-devconsole/dist"),
27438
- path25.resolve(__dirname, "../../../web-devconsole/dist"),
27439
- path25.join(process.cwd(), "packages/web-devconsole/dist")
28422
+ path26.resolve(__dirname, "../../web-devconsole/dist"),
28423
+ path26.resolve(__dirname, "../../../web-devconsole/dist"),
28424
+ path26.join(process.cwd(), "packages/web-devconsole/dist")
27440
28425
  ];
27441
28426
  for (const dir of candidates) {
27442
- if (fs15.existsSync(path25.join(dir, "index.html"))) return dir;
28427
+ if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
27443
28428
  }
27444
28429
  return null;
27445
28430
  }
@@ -27449,7 +28434,7 @@ var DevServer = class _DevServer {
27449
28434
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
27450
28435
  return;
27451
28436
  }
27452
- const htmlPath = path25.join(distDir, "index.html");
28437
+ const htmlPath = path26.join(distDir, "index.html");
27453
28438
  try {
27454
28439
  const html = fs15.readFileSync(htmlPath, "utf-8");
27455
28440
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -27474,15 +28459,15 @@ var DevServer = class _DevServer {
27474
28459
  this.json(res, 404, { error: "Not found" });
27475
28460
  return;
27476
28461
  }
27477
- const safePath = path25.normalize(pathname).replace(/^\.\.\//, "");
27478
- const filePath = path25.join(distDir, safePath);
28462
+ const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
28463
+ const filePath = path26.join(distDir, safePath);
27479
28464
  if (!filePath.startsWith(distDir)) {
27480
28465
  this.json(res, 403, { error: "Forbidden" });
27481
28466
  return;
27482
28467
  }
27483
28468
  try {
27484
28469
  const content = fs15.readFileSync(filePath);
27485
- const ext = path25.extname(filePath);
28470
+ const ext = path26.extname(filePath);
27486
28471
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
27487
28472
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
27488
28473
  res.end(content);
@@ -27595,9 +28580,9 @@ var DevServer = class _DevServer {
27595
28580
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
27596
28581
  if (entry.isDirectory()) {
27597
28582
  files.push({ path: rel, size: 0, type: "dir" });
27598
- scan(path25.join(d, entry.name), rel);
28583
+ scan(path26.join(d, entry.name), rel);
27599
28584
  } else {
27600
- const stat2 = fs15.statSync(path25.join(d, entry.name));
28585
+ const stat2 = fs15.statSync(path26.join(d, entry.name));
27601
28586
  files.push({ path: rel, size: stat2.size, type: "file" });
27602
28587
  }
27603
28588
  }
@@ -27620,7 +28605,7 @@ var DevServer = class _DevServer {
27620
28605
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
27621
28606
  return;
27622
28607
  }
27623
- const fullPath = path25.resolve(dir, path25.normalize(filePath));
28608
+ const fullPath = path26.resolve(dir, path26.normalize(filePath));
27624
28609
  if (!fullPath.startsWith(dir)) {
27625
28610
  this.json(res, 403, { error: "Forbidden" });
27626
28611
  return;
@@ -27645,14 +28630,14 @@ var DevServer = class _DevServer {
27645
28630
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
27646
28631
  return;
27647
28632
  }
27648
- const fullPath = path25.resolve(dir, path25.normalize(filePath));
28633
+ const fullPath = path26.resolve(dir, path26.normalize(filePath));
27649
28634
  if (!fullPath.startsWith(dir)) {
27650
28635
  this.json(res, 403, { error: "Forbidden" });
27651
28636
  return;
27652
28637
  }
27653
28638
  try {
27654
28639
  if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
27655
- fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
28640
+ fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
27656
28641
  fs15.writeFileSync(fullPath, content, "utf-8");
27657
28642
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
27658
28643
  this.providerLoader.reload();
@@ -27669,7 +28654,7 @@ var DevServer = class _DevServer {
27669
28654
  return;
27670
28655
  }
27671
28656
  for (const name of ["scripts.js", "provider.json"]) {
27672
- const p = path25.join(dir, name);
28657
+ const p = path26.join(dir, name);
27673
28658
  if (fs15.existsSync(p)) {
27674
28659
  const source = fs15.readFileSync(p, "utf-8");
27675
28660
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -27690,8 +28675,8 @@ var DevServer = class _DevServer {
27690
28675
  this.json(res, 404, { error: `Provider not found: ${type}` });
27691
28676
  return;
27692
28677
  }
27693
- const target = fs15.existsSync(path25.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
27694
- const targetPath = path25.join(dir, target);
28678
+ const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
28679
+ const targetPath = path26.join(dir, target);
27695
28680
  try {
27696
28681
  if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
27697
28682
  fs15.writeFileSync(targetPath, source, "utf-8");
@@ -27838,7 +28823,7 @@ var DevServer = class _DevServer {
27838
28823
  }
27839
28824
  let targetDir;
27840
28825
  targetDir = this.providerLoader.getUserProviderDir(category, type);
27841
- const jsonPath = path25.join(targetDir, "provider.json");
28826
+ const jsonPath = path26.join(targetDir, "provider.json");
27842
28827
  if (fs15.existsSync(jsonPath)) {
27843
28828
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
27844
28829
  return;
@@ -27850,8 +28835,8 @@ var DevServer = class _DevServer {
27850
28835
  const createdFiles = ["provider.json"];
27851
28836
  if (result.files) {
27852
28837
  for (const [relPath, content] of Object.entries(result.files)) {
27853
- const fullPath = path25.join(targetDir, relPath);
27854
- fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
28838
+ const fullPath = path26.join(targetDir, relPath);
28839
+ fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
27855
28840
  fs15.writeFileSync(fullPath, content, "utf-8");
27856
28841
  createdFiles.push(relPath);
27857
28842
  }
@@ -27904,22 +28889,22 @@ var DevServer = class _DevServer {
27904
28889
  if (!fs15.existsSync(scriptsDir)) return null;
27905
28890
  const versions = fs15.readdirSync(scriptsDir).filter((d) => {
27906
28891
  try {
27907
- return fs15.statSync(path25.join(scriptsDir, d)).isDirectory();
28892
+ return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
27908
28893
  } catch {
27909
28894
  return false;
27910
28895
  }
27911
28896
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
27912
28897
  if (versions.length === 0) return null;
27913
- return path25.join(scriptsDir, versions[0]);
28898
+ return path26.join(scriptsDir, versions[0]);
27914
28899
  }
27915
28900
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
27916
- const canonicalUserDir = path25.resolve(this.providerLoader.getUserProviderDir(category, type));
27917
- const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
27918
- const upstreamRoot = path25.resolve(this.providerLoader.getUpstreamDir());
27919
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
28901
+ const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
28902
+ const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
28903
+ const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
28904
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
27920
28905
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
27921
28906
  }
27922
- if (path25.basename(desiredDir) !== type) {
28907
+ if (path26.basename(desiredDir) !== type) {
27923
28908
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
27924
28909
  }
27925
28910
  const sourceDir = this.findProviderDir(type);
@@ -27927,11 +28912,11 @@ var DevServer = class _DevServer {
27927
28912
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
27928
28913
  }
27929
28914
  if (!fs15.existsSync(desiredDir)) {
27930
- fs15.mkdirSync(path25.dirname(desiredDir), { recursive: true });
28915
+ fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
27931
28916
  fs15.cpSync(sourceDir, desiredDir, { recursive: true });
27932
28917
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
27933
28918
  }
27934
- const providerJson = path25.join(desiredDir, "provider.json");
28919
+ const providerJson = path26.join(desiredDir, "provider.json");
27935
28920
  if (!fs15.existsSync(providerJson)) {
27936
28921
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
27937
28922
  }
@@ -27967,7 +28952,7 @@ var DevServer = class _DevServer {
27967
28952
  setMode: "set_mode.js"
27968
28953
  };
27969
28954
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
27970
- const scriptsDir = path25.join(providerDir, "scripts");
28955
+ const scriptsDir = path26.join(providerDir, "scripts");
27971
28956
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
27972
28957
  if (latestScriptsDir) {
27973
28958
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -27978,7 +28963,7 @@ var DevServer = class _DevServer {
27978
28963
  for (const file of fs15.readdirSync(latestScriptsDir)) {
27979
28964
  if (file.endsWith(".js") && targetFileNames.has(file)) {
27980
28965
  try {
27981
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
28966
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
27982
28967
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
27983
28968
  lines.push("```javascript");
27984
28969
  lines.push(content);
@@ -27995,7 +28980,7 @@ var DevServer = class _DevServer {
27995
28980
  lines.push("");
27996
28981
  for (const file of refFiles) {
27997
28982
  try {
27998
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
28983
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
27999
28984
  lines.push(`### \`${file}\` \u{1F512}`);
28000
28985
  lines.push("```javascript");
28001
28986
  lines.push(content);
@@ -28036,10 +29021,10 @@ var DevServer = class _DevServer {
28036
29021
  lines.push("");
28037
29022
  }
28038
29023
  }
28039
- const docsDir = path25.join(providerDir, "../../docs");
29024
+ const docsDir = path26.join(providerDir, "../../docs");
28040
29025
  const loadGuide = (name) => {
28041
29026
  try {
28042
- const p = path25.join(docsDir, name);
29027
+ const p = path26.join(docsDir, name);
28043
29028
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
28044
29029
  } catch {
28045
29030
  }
@@ -28213,7 +29198,7 @@ var DevServer = class _DevServer {
28213
29198
  parseApproval: "parse_approval.js"
28214
29199
  };
28215
29200
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
28216
- const scriptsDir = path25.join(providerDir, "scripts");
29201
+ const scriptsDir = path26.join(providerDir, "scripts");
28217
29202
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
28218
29203
  if (latestScriptsDir) {
28219
29204
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -28225,7 +29210,7 @@ var DevServer = class _DevServer {
28225
29210
  if (!file.endsWith(".js")) continue;
28226
29211
  if (!targetFileNames.has(file)) continue;
28227
29212
  try {
28228
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29213
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28229
29214
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
28230
29215
  lines.push("```javascript");
28231
29216
  lines.push(content);
@@ -28241,7 +29226,7 @@ var DevServer = class _DevServer {
28241
29226
  lines.push("");
28242
29227
  for (const file of refFiles) {
28243
29228
  try {
28244
- const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
29229
+ const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
28245
29230
  lines.push(`### \`${file}\` \u{1F512}`);
28246
29231
  lines.push("```javascript");
28247
29232
  lines.push(content);
@@ -28274,10 +29259,10 @@ var DevServer = class _DevServer {
28274
29259
  lines.push("");
28275
29260
  }
28276
29261
  }
28277
- const docsDir = path25.join(providerDir, "../../docs");
29262
+ const docsDir = path26.join(providerDir, "../../docs");
28278
29263
  const loadGuide = (name) => {
28279
29264
  try {
28280
- const p = path25.join(docsDir, name);
29265
+ const p = path26.join(docsDir, name);
28281
29266
  if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
28282
29267
  } catch {
28283
29268
  }
@@ -29282,48 +30267,6 @@ var SessionRegistry = class {
29282
30267
  // src/boot/daemon-lifecycle.ts
29283
30268
  init_logger();
29284
30269
  init_config();
29285
-
29286
- // src/mesh/mesh-events.ts
29287
- init_mesh_config();
29288
- init_logger();
29289
- function setupMeshEventForwarding(components) {
29290
- components.instanceManager.onEvent((event) => {
29291
- if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
29292
- const instanceId = event.instanceId;
29293
- if (!instanceId) return;
29294
- const sourceInstance = components.instanceManager.getInstance(instanceId);
29295
- if (!sourceInstance || sourceInstance.category !== "cli") return;
29296
- const state = sourceInstance.getState();
29297
- const workspace = state.workspace;
29298
- if (!workspace) return;
29299
- const mesh = getMeshByRepo(workspace);
29300
- if (!mesh) return;
29301
- const allInstances = components.instanceManager.getByCategory("cli");
29302
- const coordinatorInstances = allInstances.filter((inst) => {
29303
- const instState = inst.getState();
29304
- if (instState.settings?.meshCoordinatorFor !== mesh.id) return false;
29305
- if (instState.instanceId === instanceId) return false;
29306
- return true;
29307
- });
29308
- if (coordinatorInstances.length === 0) return;
29309
- const targetNode = mesh.nodes.find((n) => n.workspace === workspace);
29310
- const nodeLabel = targetNode ? `Node '${targetNode.id}'` : `Agent at ${workspace}`;
29311
- let messageText = "";
29312
- if (event.event === "agent:generating_completed") {
29313
- messageText = `[System] ${nodeLabel} has completed its task and is now idle. You may use mesh_read_chat to review its progress.`;
29314
- } else if (event.event === "agent:waiting_approval") {
29315
- messageText = `[System] ${nodeLabel} is waiting for approval to proceed. You may use mesh_read_chat and mesh_approve to handle it.`;
29316
- }
29317
- if (!messageText) return;
29318
- for (const coord of coordinatorInstances) {
29319
- const coordState = coord.getState();
29320
- LOG.info("MeshEvents", `Forwarding event from ${workspace} to coordinator ${coordState.instanceId}`);
29321
- coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
29322
- }
29323
- });
29324
- }
29325
-
29326
- // src/boot/daemon-lifecycle.ts
29327
30270
  async function initDaemonComponents(config) {
29328
30271
  installGlobalInterceptor();
29329
30272
  const appConfig = loadConfig();
@@ -29629,6 +30572,7 @@ export {
29629
30572
  createGitWorkspaceMonitor,
29630
30573
  createInteractionId,
29631
30574
  createMesh,
30575
+ createWorktree,
29632
30576
  deleteMesh,
29633
30577
  detectAllVersions,
29634
30578
  detectCLIs,
@@ -29681,6 +30625,7 @@ export {
29681
30625
  launchWithCdp,
29682
30626
  listHostedCliRuntimes,
29683
30627
  listMeshes,
30628
+ listWorktrees,
29684
30629
  loadConfig,
29685
30630
  loadState,
29686
30631
  logCommand,
@@ -29700,6 +30645,7 @@ export {
29700
30645
  normalizeSessionModalFields,
29701
30646
  parsePorcelainV2Status,
29702
30647
  parseProviderSourceConfigUpdate,
30648
+ parseWorktreeListOutput,
29703
30649
  partitionSessionHostDiagnosticsSessions,
29704
30650
  partitionSessionHostRecords,
29705
30651
  prepareSessionChatTailUpdate,
@@ -29709,6 +30655,7 @@ export {
29709
30655
  recordDebugTrace,
29710
30656
  registerExtensionProviders,
29711
30657
  removeNode,
30658
+ removeWorktree,
29712
30659
  resetConfig,
29713
30660
  resetDebugRuntimeConfig,
29714
30661
  resetState,
@@ -29718,6 +30665,7 @@ export {
29718
30665
  resolveGitRepository,
29719
30666
  resolveSessionHostAppName,
29720
30667
  resolveSessionHostAppNameResolution,
30668
+ resolveWorktreePath,
29721
30669
  runAsyncBatch,
29722
30670
  runGit,
29723
30671
  saveConfig,