@adhdev/daemon-core 0.9.66 → 0.9.68

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.
package/dist/index.mjs CHANGED
@@ -25,6 +25,22 @@ var __copyProps = (to, from, except, desc) => {
25
25
  };
26
26
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
27
 
28
+ // src/repo-mesh-types.ts
29
+ var DEFAULT_MESH_POLICY;
30
+ var init_repo_mesh_types = __esm({
31
+ "src/repo-mesh-types.ts"() {
32
+ "use strict";
33
+ DEFAULT_MESH_POLICY = {
34
+ requirePreTaskCheckpoint: false,
35
+ requirePostTaskCheckpoint: true,
36
+ requireApprovalForPush: true,
37
+ requireApprovalForDestructiveGit: true,
38
+ dirtyWorkspaceBehavior: "warn",
39
+ maxParallelTasks: 2
40
+ };
41
+ }
42
+ });
43
+
28
44
  // src/config/config.ts
29
45
  var config_exports = {};
30
46
  __export(config_exports, {
@@ -263,6 +279,275 @@ var init_config = __esm({
263
279
  }
264
280
  });
265
281
 
282
+ // src/config/mesh-config.ts
283
+ var mesh_config_exports = {};
284
+ __export(mesh_config_exports, {
285
+ addNode: () => addNode,
286
+ createMesh: () => createMesh,
287
+ deleteMesh: () => deleteMesh,
288
+ getMesh: () => getMesh,
289
+ getMeshByRepo: () => getMeshByRepo,
290
+ listMeshes: () => listMeshes,
291
+ normalizeRepoIdentity: () => normalizeRepoIdentity,
292
+ removeNode: () => removeNode,
293
+ updateMesh: () => updateMesh,
294
+ updateNode: () => updateNode
295
+ });
296
+ import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
297
+ import { join as join3 } from "path";
298
+ import { randomUUID as randomUUID3 } from "crypto";
299
+ function getMeshConfigPath() {
300
+ return join3(getConfigDir(), "meshes.json");
301
+ }
302
+ function loadMeshConfig() {
303
+ const path26 = getMeshConfigPath();
304
+ if (!existsSync3(path26)) return { meshes: [] };
305
+ try {
306
+ const raw = JSON.parse(readFileSync2(path26, "utf-8"));
307
+ if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
308
+ return raw;
309
+ } catch {
310
+ return { meshes: [] };
311
+ }
312
+ }
313
+ function saveMeshConfig(config) {
314
+ const path26 = getMeshConfigPath();
315
+ writeFileSync2(path26, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
316
+ }
317
+ function normalizeRepoIdentity(remoteUrl) {
318
+ let identity = remoteUrl.trim();
319
+ if (identity.startsWith("http://") || identity.startsWith("https://")) {
320
+ try {
321
+ const url = new URL(identity);
322
+ const path26 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
323
+ return `${url.hostname}/${path26}`;
324
+ } catch {
325
+ }
326
+ }
327
+ const sshMatch = identity.match(/^(?:ssh:\/\/)?[\w.-]+@([\w.-]+)[:/]([\w.\-/]+?)(?:\.git)?$/);
328
+ if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
329
+ return identity;
330
+ }
331
+ function listMeshes() {
332
+ return loadMeshConfig().meshes;
333
+ }
334
+ function getMesh(meshId) {
335
+ return loadMeshConfig().meshes.find((m) => m.id === meshId);
336
+ }
337
+ function getMeshByRepo(repoIdentity) {
338
+ return loadMeshConfig().meshes.find((m) => m.repoIdentity === repoIdentity);
339
+ }
340
+ function createMesh(opts) {
341
+ const config = loadMeshConfig();
342
+ if (config.meshes.length >= 20) {
343
+ throw new Error("Maximum 20 meshes allowed");
344
+ }
345
+ const repoIdentity = opts.repoIdentity || (opts.repoRemoteUrl ? normalizeRepoIdentity(opts.repoRemoteUrl) : "");
346
+ if (!repoIdentity) throw new Error("Either repoRemoteUrl or repoIdentity is required");
347
+ const now = (/* @__PURE__ */ new Date()).toISOString();
348
+ const mesh = {
349
+ id: `mesh_${randomUUID3().replace(/-/g, "")}`,
350
+ name: opts.name.trim().slice(0, 100),
351
+ repoIdentity,
352
+ repoRemoteUrl: opts.repoRemoteUrl,
353
+ defaultBranch: opts.defaultBranch,
354
+ policy: { ...DEFAULT_MESH_POLICY, ...opts.policy },
355
+ coordinator: opts.coordinator || {},
356
+ nodes: [],
357
+ createdAt: now,
358
+ updatedAt: now
359
+ };
360
+ config.meshes.push(mesh);
361
+ saveMeshConfig(config);
362
+ return mesh;
363
+ }
364
+ function updateMesh(meshId, opts) {
365
+ const config = loadMeshConfig();
366
+ const mesh = config.meshes.find((m) => m.id === meshId);
367
+ if (!mesh) return void 0;
368
+ if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
369
+ if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
370
+ if (opts.policy) mesh.policy = { ...mesh.policy, ...opts.policy };
371
+ if (opts.coordinator) mesh.coordinator = opts.coordinator;
372
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
373
+ saveMeshConfig(config);
374
+ return mesh;
375
+ }
376
+ function deleteMesh(meshId) {
377
+ const config = loadMeshConfig();
378
+ const idx = config.meshes.findIndex((m) => m.id === meshId);
379
+ if (idx === -1) return false;
380
+ config.meshes.splice(idx, 1);
381
+ saveMeshConfig(config);
382
+ return true;
383
+ }
384
+ function addNode(meshId, opts) {
385
+ const config = loadMeshConfig();
386
+ const mesh = config.meshes.find((m) => m.id === meshId);
387
+ if (!mesh) return void 0;
388
+ if (mesh.nodes.length >= 10) {
389
+ throw new Error("Maximum 10 nodes per mesh");
390
+ }
391
+ if (mesh.nodes.some((n) => n.workspace === opts.workspace)) {
392
+ throw new Error("This workspace is already in the mesh");
393
+ }
394
+ const node = {
395
+ id: `node_${randomUUID3().replace(/-/g, "")}`,
396
+ workspace: opts.workspace.trim(),
397
+ repoRoot: opts.repoRoot,
398
+ userOverrides: opts.userOverrides || {},
399
+ policy: opts.policy || {},
400
+ isLocalWorktree: opts.isLocalWorktree
401
+ };
402
+ mesh.nodes.push(node);
403
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
404
+ saveMeshConfig(config);
405
+ return node;
406
+ }
407
+ function removeNode(meshId, nodeId) {
408
+ const config = loadMeshConfig();
409
+ const mesh = config.meshes.find((m) => m.id === meshId);
410
+ if (!mesh) return false;
411
+ const idx = mesh.nodes.findIndex((n) => n.id === nodeId);
412
+ if (idx === -1) return false;
413
+ mesh.nodes.splice(idx, 1);
414
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
415
+ saveMeshConfig(config);
416
+ return true;
417
+ }
418
+ function updateNode(meshId, nodeId, opts) {
419
+ const config = loadMeshConfig();
420
+ const mesh = config.meshes.find((m) => m.id === meshId);
421
+ if (!mesh) return void 0;
422
+ const node = mesh.nodes.find((n) => n.id === nodeId);
423
+ if (!node) return void 0;
424
+ if (opts.userOverrides) node.userOverrides = { ...node.userOverrides, ...opts.userOverrides };
425
+ if (opts.policy) node.policy = { ...node.policy, ...opts.policy };
426
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
427
+ saveMeshConfig(config);
428
+ return node;
429
+ }
430
+ var init_mesh_config = __esm({
431
+ "src/config/mesh-config.ts"() {
432
+ "use strict";
433
+ init_config();
434
+ init_repo_mesh_types();
435
+ }
436
+ });
437
+
438
+ // src/mesh/coordinator-prompt.ts
439
+ var coordinator_prompt_exports = {};
440
+ __export(coordinator_prompt_exports, {
441
+ buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
442
+ });
443
+ function buildCoordinatorSystemPrompt(ctx) {
444
+ const { mesh, status, userInstruction } = ctx;
445
+ const sections = [];
446
+ 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.
447
+
448
+ Your mesh: **${mesh.name}**
449
+ Repository: \`${mesh.repoIdentity}\`${mesh.defaultBranch ? `
450
+ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
451
+ if (status?.nodes?.length) {
452
+ sections.push(buildNodeStatusSection(status.nodes));
453
+ } else if (mesh.nodes.length) {
454
+ sections.push(buildNodeConfigSection(mesh));
455
+ } else {
456
+ sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
457
+ }
458
+ sections.push(buildPolicySection(mesh.policy));
459
+ sections.push(TOOLS_SECTION);
460
+ sections.push(WORKFLOW_SECTION);
461
+ sections.push(RULES_SECTION);
462
+ if (userInstruction) {
463
+ sections.push(`## Additional Context
464
+ ${userInstruction}`);
465
+ }
466
+ if (mesh.coordinator.systemPromptSuffix) {
467
+ sections.push(mesh.coordinator.systemPromptSuffix);
468
+ }
469
+ return sections.join("\n\n");
470
+ }
471
+ function buildNodeStatusSection(nodes) {
472
+ const lines = ["## Current Node Status", ""];
473
+ for (const n of nodes) {
474
+ const healthIcon = n.health === "online" ? "\u{1F7E2}" : n.health === "dirty" ? "\u{1F7E1}" : n.health === "offline" ? "\u26AB" : "\u{1F534}";
475
+ const sessions = n.activeSessions.length > 0 ? `sessions: ${n.activeSessions.join(", ")}` : "no active sessions";
476
+ const branch = n.git?.branch ? `branch: \`${n.git.branch}\`` : "";
477
+ lines.push(`- ${healthIcon} **${n.machineLabel}** (${n.nodeId})`);
478
+ lines.push(` workspace: \`${n.workspace}\` | ${branch} | ${sessions}`);
479
+ if (n.error) lines.push(` \u26A0\uFE0F ${n.error}`);
480
+ }
481
+ return lines.join("\n");
482
+ }
483
+ function buildNodeConfigSection(mesh) {
484
+ const lines = ["## Configured Nodes", ""];
485
+ for (const n of mesh.nodes) {
486
+ const labels = [];
487
+ if (n.isLocalWorktree) labels.push("worktree");
488
+ if (n.policy.readOnly) labels.push("read-only");
489
+ const suffix = labels.length ? ` [${labels.join(", ")}]` : "";
490
+ lines.push(`- **${n.workspace}** (${n.id})${suffix}`);
491
+ }
492
+ lines.push("", "_Use `mesh_status` to probe live health before delegating work._");
493
+ return lines.join("\n");
494
+ }
495
+ function buildPolicySection(policy) {
496
+ const rules = [];
497
+ if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
498
+ if (policy.requirePostTaskCheckpoint) rules.push("- Create a git checkpoint **after** each task completes");
499
+ if (policy.requireApprovalForPush) rules.push("- **Ask for user approval** before pushing to remote");
500
+ if (policy.requireApprovalForDestructiveGit) rules.push("- **Ask for user approval** before destructive git operations (force push, reset, etc.)");
501
+ const dirtyBehavior = {
502
+ block: "- **Do not** send tasks to nodes with dirty workspaces",
503
+ warn: "- Warn the user if a node has uncommitted changes before sending a task",
504
+ checkpoint_then_continue: "- Auto-checkpoint dirty nodes before sending tasks"
505
+ }[policy.dirtyWorkspaceBehavior] || "";
506
+ if (dirtyBehavior) rules.push(dirtyBehavior);
507
+ rules.push(`- Maximum **${policy.maxParallelTasks}** tasks running in parallel`);
508
+ return `## Policy
509
+ ${rules.join("\n")}`;
510
+ }
511
+ var TOOLS_SECTION, WORKFLOW_SECTION, RULES_SECTION;
512
+ var init_coordinator_prompt = __esm({
513
+ "src/mesh/coordinator-prompt.ts"() {
514
+ "use strict";
515
+ TOOLS_SECTION = `## Available Tools
516
+
517
+ | Tool | Purpose |
518
+ |------|---------|
519
+ | \`mesh_status\` | Check all nodes' health, git state, and active sessions |
520
+ | \`mesh_list_nodes\` | List nodes with workspace paths |
521
+ | \`mesh_launch_session\` | Start a new agent session on a node |
522
+ | \`mesh_send_task\` | Send a task (natural language) to a running agent |
523
+ | \`mesh_read_chat\` | Read an agent's recent messages to check progress |
524
+ | \`mesh_git_status\` | Check git status on a specific node |
525
+ | \`mesh_checkpoint\` | Create a git checkpoint on a node |
526
+ | \`mesh_approve\` | Approve/reject a pending agent action |`;
527
+ WORKFLOW_SECTION = `## Orchestration Workflow
528
+
529
+ 1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
530
+ 2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
531
+ 3. **Delegate** \u2014 For each task:
532
+ a. Pick the best node (consider: health, dirty state, current workload).
533
+ b. If no session exists, call \`mesh_launch_session\` to start one.
534
+ c. Call \`mesh_send_task\` with a clear, self-contained natural-language instruction.
535
+ 4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
536
+ 5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
537
+ 6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
538
+ 7. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
539
+ RULES_SECTION = `## Rules
540
+
541
+ - **Be conversational.** Delegate work the way a tech lead would \u2014 clear, specific instructions in natural language.
542
+ - **Don't inspect code.** Trust the agent's output. Verify via git diff/status, not by reading source files.
543
+ - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
544
+ - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
545
+ - **Keep the user informed.** Report progress after each delegation round.
546
+ - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
547
+ - **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
548
+ }
549
+ });
550
+
266
551
  // src/logging/logger.ts
267
552
  import * as fs2 from "fs";
268
553
  import * as path9 from "path";
@@ -3320,6 +3605,9 @@ var init_provider_cli_adapter = __esm({
3320
3605
  }
3321
3606
  });
3322
3607
 
3608
+ // src/index.ts
3609
+ init_repo_mesh_types();
3610
+
3323
3611
  // src/git/git-executor.ts
3324
3612
  import { execFile } from "child_process";
3325
3613
  import { constants } from "fs";
@@ -5117,10 +5405,70 @@ function getSavedProviderSessions(state, filters) {
5117
5405
  })).sort((a, b) => b.lastUsedAt - a.lastUsedAt);
5118
5406
  }
5119
5407
 
5408
+ // src/index.ts
5409
+ init_mesh_config();
5410
+ init_coordinator_prompt();
5411
+
5412
+ // src/mesh/mesh-sync.ts
5413
+ init_mesh_config();
5414
+ async function syncMeshes(transport) {
5415
+ const result = { pushed: 0, pulled: 0, deleted: 0, errors: [] };
5416
+ let remoteMeshes;
5417
+ try {
5418
+ const res = await transport.listRemoteMeshes();
5419
+ remoteMeshes = res.meshes;
5420
+ } catch (e) {
5421
+ result.errors.push(`Failed to list remote meshes: ${e.message}`);
5422
+ return result;
5423
+ }
5424
+ const localMeshes = listMeshes();
5425
+ const remoteByIdentity = new Map(remoteMeshes.map((m) => [m.repo_identity, m]));
5426
+ const localByIdentity = new Map(localMeshes.map((m) => [m.repoIdentity, m]));
5427
+ for (const local of localMeshes) {
5428
+ if (!remoteByIdentity.has(local.repoIdentity)) {
5429
+ try {
5430
+ await transport.createRemoteMesh({
5431
+ name: local.name,
5432
+ repo_identity: local.repoIdentity,
5433
+ repo_remote_url: local.repoRemoteUrl,
5434
+ default_branch: local.defaultBranch,
5435
+ policy: JSON.stringify(local.policy)
5436
+ });
5437
+ result.pushed++;
5438
+ } catch (e) {
5439
+ result.errors.push(`Push failed for "${local.name}": ${e.message}`);
5440
+ }
5441
+ }
5442
+ }
5443
+ for (const remote of remoteMeshes) {
5444
+ if (!localByIdentity.has(remote.repo_identity)) {
5445
+ try {
5446
+ let policy;
5447
+ try {
5448
+ policy = JSON.parse(remote.policy);
5449
+ } catch {
5450
+ policy = void 0;
5451
+ }
5452
+ createMesh({
5453
+ name: remote.name,
5454
+ repoIdentity: remote.repo_identity,
5455
+ repoRemoteUrl: remote.repo_remote_url || void 0,
5456
+ defaultBranch: remote.default_branch || void 0,
5457
+ policy
5458
+ });
5459
+ result.pulled++;
5460
+ } catch (e) {
5461
+ result.errors.push(`Pull failed for "${remote.name}": ${e.message}`);
5462
+ }
5463
+ }
5464
+ }
5465
+ return result;
5466
+ }
5467
+
5120
5468
  // src/config/state-store.ts
5121
5469
  init_config();
5122
- import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
5123
- import { join as join3 } from "path";
5470
+ import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
5471
+ import { join as join4 } from "path";
5124
5472
  var DEFAULT_STATE = {
5125
5473
  recentActivity: [],
5126
5474
  savedProviderSessions: [],
@@ -5133,7 +5481,7 @@ function isPlainObject2(value) {
5133
5481
  return !!value && typeof value === "object" && !Array.isArray(value);
5134
5482
  }
5135
5483
  function getStatePath() {
5136
- return join3(getConfigDir(), "state.json");
5484
+ return join4(getConfigDir(), "state.json");
5137
5485
  }
5138
5486
  function normalizeState(raw) {
5139
5487
  const parsed = isPlainObject2(raw) ? raw : {};
@@ -5169,11 +5517,11 @@ function normalizeState(raw) {
5169
5517
  }
5170
5518
  function loadState() {
5171
5519
  const statePath = getStatePath();
5172
- if (!existsSync3(statePath)) {
5520
+ if (!existsSync4(statePath)) {
5173
5521
  return { ...DEFAULT_STATE };
5174
5522
  }
5175
5523
  try {
5176
- const raw = readFileSync2(statePath, "utf-8");
5524
+ const raw = readFileSync3(statePath, "utf-8");
5177
5525
  return normalizeState(JSON.parse(raw));
5178
5526
  } catch {
5179
5527
  return { ...DEFAULT_STATE };
@@ -5182,7 +5530,7 @@ function loadState() {
5182
5530
  function saveState(state) {
5183
5531
  const statePath = getStatePath();
5184
5532
  const normalized = normalizeState(state);
5185
- writeFileSync2(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
5533
+ writeFileSync3(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
5186
5534
  }
5187
5535
  function resetState() {
5188
5536
  saveState({ ...DEFAULT_STATE });
@@ -5190,7 +5538,7 @@ function resetState() {
5190
5538
 
5191
5539
  // src/detection/ide-detector.ts
5192
5540
  import { execSync } from "child_process";
5193
- import { existsSync as existsSync4 } from "fs";
5541
+ import { existsSync as existsSync5 } from "fs";
5194
5542
  import { platform, homedir as homedir3 } from "os";
5195
5543
  import * as path7 from "path";
5196
5544
  var BUILTIN_IDE_DEFINITIONS = [];
@@ -5214,7 +5562,7 @@ function findCliCommand(command) {
5214
5562
  if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5215
5563
  const candidate = trimmed.startsWith("~") ? path7.join(homedir3(), trimmed.slice(1)) : trimmed;
5216
5564
  const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
5217
- return existsSync4(resolved) ? resolved : null;
5565
+ return existsSync5(resolved) ? resolved : null;
5218
5566
  }
5219
5567
  try {
5220
5568
  const result = execSync(
@@ -5245,9 +5593,9 @@ function checkPathExists(paths) {
5245
5593
  if (normalized.includes("*")) {
5246
5594
  const username = home.split(/[\\/]/).pop() || "";
5247
5595
  const resolved = normalized.replace("*", username);
5248
- if (existsSync4(resolved)) return resolved;
5596
+ if (existsSync5(resolved)) return resolved;
5249
5597
  } else {
5250
- if (existsSync4(normalized)) return normalized;
5598
+ if (existsSync5(normalized)) return normalized;
5251
5599
  }
5252
5600
  }
5253
5601
  return null;
@@ -5261,7 +5609,7 @@ async function detectIDEs(providerLoader) {
5261
5609
  let resolvedCli = cliPath;
5262
5610
  if (!resolvedCli && appPath && os21 === "darwin") {
5263
5611
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
5264
- if (existsSync4(bundledCli)) resolvedCli = bundledCli;
5612
+ if (existsSync5(bundledCli)) resolvedCli = bundledCli;
5265
5613
  }
5266
5614
  if (!resolvedCli && appPath && os21 === "win32") {
5267
5615
  const { dirname: dirname7 } = await import("path");
@@ -5274,7 +5622,7 @@ async function detectIDEs(providerLoader) {
5274
5622
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
5275
5623
  ];
5276
5624
  for (const c of candidates) {
5277
- if (existsSync4(c)) {
5625
+ if (existsSync5(c)) {
5278
5626
  resolvedCli = c;
5279
5627
  break;
5280
5628
  }
@@ -5300,7 +5648,7 @@ async function detectIDEs(providerLoader) {
5300
5648
  import { exec } from "child_process";
5301
5649
  import * as os2 from "os";
5302
5650
  import * as path8 from "path";
5303
- import { existsSync as existsSync5 } from "fs";
5651
+ import { existsSync as existsSync6 } from "fs";
5304
5652
  function parseVersion(raw) {
5305
5653
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
5306
5654
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
@@ -5324,7 +5672,7 @@ function resolveCommandPath(command) {
5324
5672
  if (isExplicitCommandPath(trimmed)) {
5325
5673
  const expanded = expandHome(trimmed);
5326
5674
  const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
5327
- return existsSync5(candidate) ? candidate : null;
5675
+ return existsSync6(candidate) ? candidate : null;
5328
5676
  }
5329
5677
  return null;
5330
5678
  }
@@ -10952,7 +11300,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
10952
11300
  import * as fs4 from "fs";
10953
11301
  import * as os6 from "os";
10954
11302
  import * as path11 from "path";
10955
- import { randomUUID as randomUUID4 } from "crypto";
11303
+ import { randomUUID as randomUUID5 } from "crypto";
10956
11304
 
10957
11305
  // src/providers/provider-input-support.ts
10958
11306
  var VALID_INPUT_MEDIA_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "video", "resource"]);
@@ -11469,7 +11817,7 @@ function safeBundleIdSegment(value, fallback) {
11469
11817
  function createChatDebugBundleId(targetSessionId) {
11470
11818
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.]/g, "").replace("T", "T").replace("Z", "Z");
11471
11819
  const sessionSegment = safeBundleIdSegment(targetSessionId, "unknown-session");
11472
- return `chat-debug-${timestamp}-${sessionSegment}-${randomUUID4().slice(0, 8)}`;
11820
+ return `chat-debug-${timestamp}-${sessionSegment}-${randomUUID5().slice(0, 8)}`;
11473
11821
  }
11474
11822
  function buildChatDebugBundleSummary(bundle) {
11475
11823
  const target = bundle.target && typeof bundle.target === "object" ? bundle.target : {};
@@ -14063,7 +14411,7 @@ init_provider_cli_adapter();
14063
14411
  import * as os13 from "os";
14064
14412
  import * as path16 from "path";
14065
14413
  import * as crypto4 from "crypto";
14066
- import { existsSync as existsSync10 } from "fs";
14414
+ import { existsSync as existsSync11 } from "fs";
14067
14415
  import { execFileSync } from "child_process";
14068
14416
  import chalk from "chalk";
14069
14417
  init_config();
@@ -16205,7 +16553,7 @@ function commandExists(command) {
16205
16553
  const trimmed = command.trim();
16206
16554
  if (!trimmed) return false;
16207
16555
  if (isExplicitCommand(trimmed)) {
16208
- return existsSync10(expandExecutable(trimmed));
16556
+ return existsSync11(expandExecutable(trimmed));
16209
16557
  }
16210
16558
  try {
16211
16559
  execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -20718,6 +21066,142 @@ var DaemonCommandRouter = class {
20718
21066
  updateConfig({ machineNickname: nickname || null });
20719
21067
  return { success: true };
20720
21068
  }
21069
+ // ─── Mesh CRUD (local meshes.json) ───
21070
+ case "list_meshes": {
21071
+ try {
21072
+ const { listMeshes: listMeshes2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21073
+ return { success: true, meshes: listMeshes2() };
21074
+ } catch (e) {
21075
+ return { success: false, error: e.message };
21076
+ }
21077
+ }
21078
+ case "get_mesh": {
21079
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21080
+ if (!meshId) return { success: false, error: "meshId required" };
21081
+ try {
21082
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21083
+ const mesh = getMesh3(meshId);
21084
+ if (!mesh) return { success: false, error: "Mesh not found" };
21085
+ return { success: true, mesh };
21086
+ } catch (e) {
21087
+ return { success: false, error: e.message };
21088
+ }
21089
+ }
21090
+ case "create_mesh": {
21091
+ const name = typeof args?.name === "string" ? args.name.trim() : "";
21092
+ const repoIdentity = typeof args?.repoIdentity === "string" ? args.repoIdentity.trim() : "";
21093
+ const repoRemoteUrl = typeof args?.repoRemoteUrl === "string" ? args.repoRemoteUrl.trim() : void 0;
21094
+ const defaultBranch = typeof args?.defaultBranch === "string" ? args.defaultBranch.trim() : void 0;
21095
+ if (!name) return { success: false, error: "name required" };
21096
+ try {
21097
+ const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21098
+ const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
21099
+ return { success: true, mesh };
21100
+ } catch (e) {
21101
+ return { success: false, error: e.message };
21102
+ }
21103
+ }
21104
+ case "delete_mesh": {
21105
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21106
+ if (!meshId) return { success: false, error: "meshId required" };
21107
+ try {
21108
+ const { deleteMesh: deleteMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21109
+ const deleted = deleteMesh3(meshId);
21110
+ return { success: true, deleted };
21111
+ } catch (e) {
21112
+ return { success: false, error: e.message };
21113
+ }
21114
+ }
21115
+ case "add_mesh_node": {
21116
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21117
+ const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
21118
+ if (!meshId) return { success: false, error: "meshId required" };
21119
+ if (!workspace) return { success: false, error: "workspace required" };
21120
+ try {
21121
+ const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21122
+ const node = addNode3(meshId, { workspace });
21123
+ if (!node) return { success: false, error: "Mesh not found" };
21124
+ return { success: true, node };
21125
+ } catch (e) {
21126
+ return { success: false, error: e.message };
21127
+ }
21128
+ }
21129
+ case "remove_mesh_node": {
21130
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21131
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
21132
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
21133
+ try {
21134
+ const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21135
+ const removed = removeNode3(meshId, nodeId);
21136
+ return { success: true, removed };
21137
+ } catch (e) {
21138
+ return { success: false, error: e.message };
21139
+ }
21140
+ }
21141
+ // ─── Mesh Coordinator Launch ───
21142
+ case "launch_mesh_coordinator": {
21143
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21144
+ const cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "claude-cli";
21145
+ if (!meshId) return { success: false, error: "meshId required" };
21146
+ try {
21147
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21148
+ const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
21149
+ const mesh = getMesh3(meshId);
21150
+ if (!mesh) return { success: false, error: "Mesh not found" };
21151
+ if (mesh.nodes.length === 0) return { success: false, error: "No nodes in mesh" };
21152
+ const workspace = mesh.nodes[0].workspace;
21153
+ const { existsSync: existsSync21, readFileSync: readFileSync15, writeFileSync: writeFileSync12, copyFileSync: copyFileSync3 } = await import("fs");
21154
+ const { join: join23 } = await import("path");
21155
+ const mcpConfigPath = join23(workspace, ".mcp.json");
21156
+ const hadExistingMcpConfig = existsSync21(mcpConfigPath);
21157
+ let existingMcpConfig = {};
21158
+ if (hadExistingMcpConfig) {
21159
+ try {
21160
+ existingMcpConfig = JSON.parse(readFileSync15(mcpConfigPath, "utf-8"));
21161
+ copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
21162
+ } catch {
21163
+ }
21164
+ }
21165
+ const mcpConfig = {
21166
+ ...existingMcpConfig,
21167
+ mcpServers: {
21168
+ ...existingMcpConfig.mcpServers || {},
21169
+ "adhdev-mesh": {
21170
+ command: "adhdev-mcp",
21171
+ args: ["--repo-mesh", meshId]
21172
+ }
21173
+ }
21174
+ };
21175
+ writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
21176
+ LOG.info("MeshCoordinator", `Wrote .mcp.json to ${workspace} with adhdev-mesh server`);
21177
+ let systemPrompt = "";
21178
+ try {
21179
+ systemPrompt = buildCoordinatorSystemPrompt2({ mesh });
21180
+ } catch {
21181
+ 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).`;
21182
+ }
21183
+ const launchResult = await this.deps.cliManager.handleCliCommand("launch_cli", {
21184
+ cliType,
21185
+ dir: workspace,
21186
+ initialPrompt: systemPrompt
21187
+ });
21188
+ if (!launchResult?.success) {
21189
+ return { success: false, error: launchResult?.error || "Failed to launch CLI session" };
21190
+ }
21191
+ LOG.info("MeshCoordinator", `Launched ${cliType} coordinator for mesh ${meshId} in ${workspace}`);
21192
+ return {
21193
+ success: true,
21194
+ meshId,
21195
+ cliType,
21196
+ workspace,
21197
+ sessionId: launchResult.sessionId || launchResult.id,
21198
+ mcpConfigWritten: true
21199
+ };
21200
+ } catch (e) {
21201
+ LOG.error("MeshCoordinator", `Failed: ${e.message}`);
21202
+ return { success: false, error: e.message };
21203
+ }
21204
+ }
20721
21205
  default:
20722
21206
  break;
20723
21207
  }
@@ -28683,6 +29167,7 @@ export {
28683
29167
  DEFAULT_DAEMON_PORT,
28684
29168
  DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
28685
29169
  DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
29170
+ DEFAULT_MESH_POLICY,
28686
29171
  DEFAULT_SESSION_HOST_APP_NAME,
28687
29172
  DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
28688
29173
  DEFAULT_SESSION_HOST_READY_TIMEOUT_MS,
@@ -28716,11 +29201,13 @@ export {
28716
29201
  SessionHostPtyTransportFactory,
28717
29202
  TurnSnapshotTracker,
28718
29203
  VersionArchive,
29204
+ addNode,
28719
29205
  appendRecentActivity,
28720
29206
  buildAssistantChatMessage,
28721
29207
  buildChatMessage,
28722
29208
  buildChatMessageSignature,
28723
29209
  buildChatTailDeliverySignature,
29210
+ buildCoordinatorSystemPrompt,
28724
29211
  buildMachineInfo,
28725
29212
  buildPinnedGlobalInstallCommand,
28726
29213
  buildRuntimeSystemChatMessage,
@@ -28743,6 +29230,8 @@ export {
28743
29230
  createGitSnapshotStore,
28744
29231
  createGitWorkspaceMonitor,
28745
29232
  createInteractionId,
29233
+ createMesh,
29234
+ deleteMesh,
28746
29235
  detectAllVersions,
28747
29236
  detectCLIs,
28748
29237
  detectIDEs,
@@ -28761,6 +29250,8 @@ export {
28761
29250
  getGitRepoStatus,
28762
29251
  getHostMemorySnapshot,
28763
29252
  getLogLevel,
29253
+ getMesh,
29254
+ getMeshByRepo,
28764
29255
  getNpmExecOptions,
28765
29256
  getRecentActivity,
28766
29257
  getRecentCommands,
@@ -28791,6 +29282,7 @@ export {
28791
29282
  launchIDE,
28792
29283
  launchWithCdp,
28793
29284
  listHostedCliRuntimes,
29285
+ listMeshes,
28794
29286
  loadConfig,
28795
29287
  loadState,
28796
29288
  logCommand,
@@ -28806,6 +29298,7 @@ export {
28806
29298
  normalizeInputEnvelope,
28807
29299
  normalizeManagedStatus,
28808
29300
  normalizeMessageParts,
29301
+ normalizeRepoIdentity,
28809
29302
  normalizeSessionModalFields,
28810
29303
  parsePorcelainV2Status,
28811
29304
  parseProviderSourceConfigUpdate,
@@ -28817,6 +29310,7 @@ export {
28817
29310
  readChatHistory,
28818
29311
  recordDebugTrace,
28819
29312
  registerExtensionProviders,
29313
+ removeNode,
28820
29314
  resetConfig,
28821
29315
  resetDebugRuntimeConfig,
28822
29316
  resetState,
@@ -28839,7 +29333,10 @@ export {
28839
29333
  spawnDetachedDaemonUpgradeHelper,
28840
29334
  startDaemonDevSupport,
28841
29335
  summarizeGitStatus,
29336
+ syncMeshes,
28842
29337
  updateConfig,
29338
+ updateMesh,
29339
+ updateNode,
28843
29340
  upsertSavedProviderSession
28844
29341
  };
28845
29342
  //# sourceMappingURL=index.mjs.map