@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.js CHANGED
@@ -30,6 +30,22 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  ));
31
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
32
 
33
+ // src/repo-mesh-types.ts
34
+ var DEFAULT_MESH_POLICY;
35
+ var init_repo_mesh_types = __esm({
36
+ "src/repo-mesh-types.ts"() {
37
+ "use strict";
38
+ DEFAULT_MESH_POLICY = {
39
+ requirePreTaskCheckpoint: false,
40
+ requirePostTaskCheckpoint: true,
41
+ requireApprovalForPush: true,
42
+ requireApprovalForDestructiveGit: true,
43
+ dirtyWorkspaceBehavior: "warn",
44
+ maxParallelTasks: 2
45
+ };
46
+ }
47
+ });
48
+
33
49
  // src/config/config.ts
34
50
  var config_exports = {};
35
51
  __export(config_exports, {
@@ -268,6 +284,276 @@ var init_config = __esm({
268
284
  }
269
285
  });
270
286
 
287
+ // src/config/mesh-config.ts
288
+ var mesh_config_exports = {};
289
+ __export(mesh_config_exports, {
290
+ addNode: () => addNode,
291
+ createMesh: () => createMesh,
292
+ deleteMesh: () => deleteMesh,
293
+ getMesh: () => getMesh,
294
+ getMeshByRepo: () => getMeshByRepo,
295
+ listMeshes: () => listMeshes,
296
+ normalizeRepoIdentity: () => normalizeRepoIdentity,
297
+ removeNode: () => removeNode,
298
+ updateMesh: () => updateMesh,
299
+ updateNode: () => updateNode
300
+ });
301
+ function getMeshConfigPath() {
302
+ return (0, import_path2.join)(getConfigDir(), "meshes.json");
303
+ }
304
+ function loadMeshConfig() {
305
+ const path26 = getMeshConfigPath();
306
+ if (!(0, import_fs2.existsSync)(path26)) return { meshes: [] };
307
+ try {
308
+ const raw = JSON.parse((0, import_fs2.readFileSync)(path26, "utf-8"));
309
+ if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
310
+ return raw;
311
+ } catch {
312
+ return { meshes: [] };
313
+ }
314
+ }
315
+ function saveMeshConfig(config) {
316
+ const path26 = getMeshConfigPath();
317
+ (0, import_fs2.writeFileSync)(path26, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
318
+ }
319
+ function normalizeRepoIdentity(remoteUrl) {
320
+ let identity = remoteUrl.trim();
321
+ if (identity.startsWith("http://") || identity.startsWith("https://")) {
322
+ try {
323
+ const url = new URL(identity);
324
+ const path26 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
325
+ return `${url.hostname}/${path26}`;
326
+ } catch {
327
+ }
328
+ }
329
+ const sshMatch = identity.match(/^(?:ssh:\/\/)?[\w.-]+@([\w.-]+)[:/]([\w.\-/]+?)(?:\.git)?$/);
330
+ if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
331
+ return identity;
332
+ }
333
+ function listMeshes() {
334
+ return loadMeshConfig().meshes;
335
+ }
336
+ function getMesh(meshId) {
337
+ return loadMeshConfig().meshes.find((m) => m.id === meshId);
338
+ }
339
+ function getMeshByRepo(repoIdentity) {
340
+ return loadMeshConfig().meshes.find((m) => m.repoIdentity === repoIdentity);
341
+ }
342
+ function createMesh(opts) {
343
+ const config = loadMeshConfig();
344
+ if (config.meshes.length >= 20) {
345
+ throw new Error("Maximum 20 meshes allowed");
346
+ }
347
+ const repoIdentity = opts.repoIdentity || (opts.repoRemoteUrl ? normalizeRepoIdentity(opts.repoRemoteUrl) : "");
348
+ if (!repoIdentity) throw new Error("Either repoRemoteUrl or repoIdentity is required");
349
+ const now = (/* @__PURE__ */ new Date()).toISOString();
350
+ const mesh = {
351
+ id: `mesh_${(0, import_crypto3.randomUUID)().replace(/-/g, "")}`,
352
+ name: opts.name.trim().slice(0, 100),
353
+ repoIdentity,
354
+ repoRemoteUrl: opts.repoRemoteUrl,
355
+ defaultBranch: opts.defaultBranch,
356
+ policy: { ...DEFAULT_MESH_POLICY, ...opts.policy },
357
+ coordinator: opts.coordinator || {},
358
+ nodes: [],
359
+ createdAt: now,
360
+ updatedAt: now
361
+ };
362
+ config.meshes.push(mesh);
363
+ saveMeshConfig(config);
364
+ return mesh;
365
+ }
366
+ function updateMesh(meshId, opts) {
367
+ const config = loadMeshConfig();
368
+ const mesh = config.meshes.find((m) => m.id === meshId);
369
+ if (!mesh) return void 0;
370
+ if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
371
+ if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
372
+ if (opts.policy) mesh.policy = { ...mesh.policy, ...opts.policy };
373
+ if (opts.coordinator) mesh.coordinator = opts.coordinator;
374
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
375
+ saveMeshConfig(config);
376
+ return mesh;
377
+ }
378
+ function deleteMesh(meshId) {
379
+ const config = loadMeshConfig();
380
+ const idx = config.meshes.findIndex((m) => m.id === meshId);
381
+ if (idx === -1) return false;
382
+ config.meshes.splice(idx, 1);
383
+ saveMeshConfig(config);
384
+ return true;
385
+ }
386
+ function addNode(meshId, opts) {
387
+ const config = loadMeshConfig();
388
+ const mesh = config.meshes.find((m) => m.id === meshId);
389
+ if (!mesh) return void 0;
390
+ if (mesh.nodes.length >= 10) {
391
+ throw new Error("Maximum 10 nodes per mesh");
392
+ }
393
+ if (mesh.nodes.some((n) => n.workspace === opts.workspace)) {
394
+ throw new Error("This workspace is already in the mesh");
395
+ }
396
+ const node = {
397
+ id: `node_${(0, import_crypto3.randomUUID)().replace(/-/g, "")}`,
398
+ workspace: opts.workspace.trim(),
399
+ repoRoot: opts.repoRoot,
400
+ userOverrides: opts.userOverrides || {},
401
+ policy: opts.policy || {},
402
+ isLocalWorktree: opts.isLocalWorktree
403
+ };
404
+ mesh.nodes.push(node);
405
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
406
+ saveMeshConfig(config);
407
+ return node;
408
+ }
409
+ function removeNode(meshId, nodeId) {
410
+ const config = loadMeshConfig();
411
+ const mesh = config.meshes.find((m) => m.id === meshId);
412
+ if (!mesh) return false;
413
+ const idx = mesh.nodes.findIndex((n) => n.id === nodeId);
414
+ if (idx === -1) return false;
415
+ mesh.nodes.splice(idx, 1);
416
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
417
+ saveMeshConfig(config);
418
+ return true;
419
+ }
420
+ function updateNode(meshId, nodeId, opts) {
421
+ const config = loadMeshConfig();
422
+ const mesh = config.meshes.find((m) => m.id === meshId);
423
+ if (!mesh) return void 0;
424
+ const node = mesh.nodes.find((n) => n.id === nodeId);
425
+ if (!node) return void 0;
426
+ if (opts.userOverrides) node.userOverrides = { ...node.userOverrides, ...opts.userOverrides };
427
+ if (opts.policy) node.policy = { ...node.policy, ...opts.policy };
428
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
429
+ saveMeshConfig(config);
430
+ return node;
431
+ }
432
+ var import_fs2, import_path2, import_crypto3;
433
+ var init_mesh_config = __esm({
434
+ "src/config/mesh-config.ts"() {
435
+ "use strict";
436
+ import_fs2 = require("fs");
437
+ import_path2 = require("path");
438
+ import_crypto3 = require("crypto");
439
+ init_config();
440
+ init_repo_mesh_types();
441
+ }
442
+ });
443
+
444
+ // src/mesh/coordinator-prompt.ts
445
+ var coordinator_prompt_exports = {};
446
+ __export(coordinator_prompt_exports, {
447
+ buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
448
+ });
449
+ function buildCoordinatorSystemPrompt(ctx) {
450
+ const { mesh, status, userInstruction } = ctx;
451
+ const sections = [];
452
+ 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.
453
+
454
+ Your mesh: **${mesh.name}**
455
+ Repository: \`${mesh.repoIdentity}\`${mesh.defaultBranch ? `
456
+ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
457
+ if (status?.nodes?.length) {
458
+ sections.push(buildNodeStatusSection(status.nodes));
459
+ } else if (mesh.nodes.length) {
460
+ sections.push(buildNodeConfigSection(mesh));
461
+ } else {
462
+ sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
463
+ }
464
+ sections.push(buildPolicySection(mesh.policy));
465
+ sections.push(TOOLS_SECTION);
466
+ sections.push(WORKFLOW_SECTION);
467
+ sections.push(RULES_SECTION);
468
+ if (userInstruction) {
469
+ sections.push(`## Additional Context
470
+ ${userInstruction}`);
471
+ }
472
+ if (mesh.coordinator.systemPromptSuffix) {
473
+ sections.push(mesh.coordinator.systemPromptSuffix);
474
+ }
475
+ return sections.join("\n\n");
476
+ }
477
+ function buildNodeStatusSection(nodes) {
478
+ const lines = ["## Current Node Status", ""];
479
+ for (const n of nodes) {
480
+ const healthIcon = n.health === "online" ? "\u{1F7E2}" : n.health === "dirty" ? "\u{1F7E1}" : n.health === "offline" ? "\u26AB" : "\u{1F534}";
481
+ const sessions = n.activeSessions.length > 0 ? `sessions: ${n.activeSessions.join(", ")}` : "no active sessions";
482
+ const branch = n.git?.branch ? `branch: \`${n.git.branch}\`` : "";
483
+ lines.push(`- ${healthIcon} **${n.machineLabel}** (${n.nodeId})`);
484
+ lines.push(` workspace: \`${n.workspace}\` | ${branch} | ${sessions}`);
485
+ if (n.error) lines.push(` \u26A0\uFE0F ${n.error}`);
486
+ }
487
+ return lines.join("\n");
488
+ }
489
+ function buildNodeConfigSection(mesh) {
490
+ const lines = ["## Configured Nodes", ""];
491
+ for (const n of mesh.nodes) {
492
+ const labels = [];
493
+ if (n.isLocalWorktree) labels.push("worktree");
494
+ if (n.policy.readOnly) labels.push("read-only");
495
+ const suffix = labels.length ? ` [${labels.join(", ")}]` : "";
496
+ lines.push(`- **${n.workspace}** (${n.id})${suffix}`);
497
+ }
498
+ lines.push("", "_Use `mesh_status` to probe live health before delegating work._");
499
+ return lines.join("\n");
500
+ }
501
+ function buildPolicySection(policy) {
502
+ const rules = [];
503
+ if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
504
+ if (policy.requirePostTaskCheckpoint) rules.push("- Create a git checkpoint **after** each task completes");
505
+ if (policy.requireApprovalForPush) rules.push("- **Ask for user approval** before pushing to remote");
506
+ if (policy.requireApprovalForDestructiveGit) rules.push("- **Ask for user approval** before destructive git operations (force push, reset, etc.)");
507
+ const dirtyBehavior = {
508
+ block: "- **Do not** send tasks to nodes with dirty workspaces",
509
+ warn: "- Warn the user if a node has uncommitted changes before sending a task",
510
+ checkpoint_then_continue: "- Auto-checkpoint dirty nodes before sending tasks"
511
+ }[policy.dirtyWorkspaceBehavior] || "";
512
+ if (dirtyBehavior) rules.push(dirtyBehavior);
513
+ rules.push(`- Maximum **${policy.maxParallelTasks}** tasks running in parallel`);
514
+ return `## Policy
515
+ ${rules.join("\n")}`;
516
+ }
517
+ var TOOLS_SECTION, WORKFLOW_SECTION, RULES_SECTION;
518
+ var init_coordinator_prompt = __esm({
519
+ "src/mesh/coordinator-prompt.ts"() {
520
+ "use strict";
521
+ TOOLS_SECTION = `## Available Tools
522
+
523
+ | Tool | Purpose |
524
+ |------|---------|
525
+ | \`mesh_status\` | Check all nodes' health, git state, and active sessions |
526
+ | \`mesh_list_nodes\` | List nodes with workspace paths |
527
+ | \`mesh_launch_session\` | Start a new agent session on a node |
528
+ | \`mesh_send_task\` | Send a task (natural language) to a running agent |
529
+ | \`mesh_read_chat\` | Read an agent's recent messages to check progress |
530
+ | \`mesh_git_status\` | Check git status on a specific node |
531
+ | \`mesh_checkpoint\` | Create a git checkpoint on a node |
532
+ | \`mesh_approve\` | Approve/reject a pending agent action |`;
533
+ WORKFLOW_SECTION = `## Orchestration Workflow
534
+
535
+ 1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
536
+ 2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
537
+ 3. **Delegate** \u2014 For each task:
538
+ a. Pick the best node (consider: health, dirty state, current workload).
539
+ b. If no session exists, call \`mesh_launch_session\` to start one.
540
+ c. Call \`mesh_send_task\` with a clear, self-contained natural-language instruction.
541
+ 4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
542
+ 5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
543
+ 6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
544
+ 7. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
545
+ RULES_SECTION = `## Rules
546
+
547
+ - **Be conversational.** Delegate work the way a tech lead would \u2014 clear, specific instructions in natural language.
548
+ - **Don't inspect code.** Trust the agent's output. Verify via git diff/status, not by reading source files.
549
+ - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
550
+ - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
551
+ - **Keep the user informed.** Report progress after each delegation round.
552
+ - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
553
+ - **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
554
+ }
555
+ });
556
+
271
557
  // src/logging/logger.ts
272
558
  function setLogLevel(level) {
273
559
  currentLevel = level;
@@ -3339,6 +3625,7 @@ __export(index_exports, {
3339
3625
  DEFAULT_DAEMON_PORT: () => DEFAULT_DAEMON_PORT,
3340
3626
  DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS: () => DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
3341
3627
  DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
3628
+ DEFAULT_MESH_POLICY: () => DEFAULT_MESH_POLICY,
3342
3629
  DEFAULT_SESSION_HOST_APP_NAME: () => DEFAULT_SESSION_HOST_APP_NAME,
3343
3630
  DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
3344
3631
  DEFAULT_SESSION_HOST_READY_TIMEOUT_MS: () => DEFAULT_SESSION_HOST_READY_TIMEOUT_MS,
@@ -3372,11 +3659,13 @@ __export(index_exports, {
3372
3659
  SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory,
3373
3660
  TurnSnapshotTracker: () => TurnSnapshotTracker,
3374
3661
  VersionArchive: () => VersionArchive,
3662
+ addNode: () => addNode,
3375
3663
  appendRecentActivity: () => appendRecentActivity,
3376
3664
  buildAssistantChatMessage: () => buildAssistantChatMessage,
3377
3665
  buildChatMessage: () => buildChatMessage,
3378
3666
  buildChatMessageSignature: () => buildChatMessageSignature,
3379
3667
  buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
3668
+ buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt,
3380
3669
  buildMachineInfo: () => buildMachineInfo,
3381
3670
  buildPinnedGlobalInstallCommand: () => buildPinnedGlobalInstallCommand,
3382
3671
  buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
@@ -3399,6 +3688,8 @@ __export(index_exports, {
3399
3688
  createGitSnapshotStore: () => createGitSnapshotStore,
3400
3689
  createGitWorkspaceMonitor: () => createGitWorkspaceMonitor,
3401
3690
  createInteractionId: () => createInteractionId,
3691
+ createMesh: () => createMesh,
3692
+ deleteMesh: () => deleteMesh,
3402
3693
  detectAllVersions: () => detectAllVersions,
3403
3694
  detectCLIs: () => detectCLIs,
3404
3695
  detectIDEs: () => detectIDEs,
@@ -3417,6 +3708,8 @@ __export(index_exports, {
3417
3708
  getGitRepoStatus: () => getGitRepoStatus,
3418
3709
  getHostMemorySnapshot: () => getHostMemorySnapshot,
3419
3710
  getLogLevel: () => getLogLevel,
3711
+ getMesh: () => getMesh,
3712
+ getMeshByRepo: () => getMeshByRepo,
3420
3713
  getNpmExecOptions: () => getNpmExecOptions,
3421
3714
  getRecentActivity: () => getRecentActivity,
3422
3715
  getRecentCommands: () => getRecentCommands,
@@ -3447,6 +3740,7 @@ __export(index_exports, {
3447
3740
  launchIDE: () => launchIDE,
3448
3741
  launchWithCdp: () => launchWithCdp,
3449
3742
  listHostedCliRuntimes: () => listHostedCliRuntimes,
3743
+ listMeshes: () => listMeshes,
3450
3744
  loadConfig: () => loadConfig,
3451
3745
  loadState: () => loadState,
3452
3746
  logCommand: () => logCommand,
@@ -3462,6 +3756,7 @@ __export(index_exports, {
3462
3756
  normalizeInputEnvelope: () => normalizeInputEnvelope,
3463
3757
  normalizeManagedStatus: () => normalizeManagedStatus,
3464
3758
  normalizeMessageParts: () => normalizeMessageParts,
3759
+ normalizeRepoIdentity: () => normalizeRepoIdentity,
3465
3760
  normalizeSessionModalFields: () => normalizeSessionModalFields,
3466
3761
  parsePorcelainV2Status: () => parsePorcelainV2Status,
3467
3762
  parseProviderSourceConfigUpdate: () => parseProviderSourceConfigUpdate,
@@ -3473,6 +3768,7 @@ __export(index_exports, {
3473
3768
  readChatHistory: () => readChatHistory,
3474
3769
  recordDebugTrace: () => recordDebugTrace,
3475
3770
  registerExtensionProviders: () => registerExtensionProviders,
3771
+ removeNode: () => removeNode,
3476
3772
  resetConfig: () => resetConfig,
3477
3773
  resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
3478
3774
  resetState: () => resetState,
@@ -3495,10 +3791,14 @@ __export(index_exports, {
3495
3791
  spawnDetachedDaemonUpgradeHelper: () => spawnDetachedDaemonUpgradeHelper,
3496
3792
  startDaemonDevSupport: () => startDaemonDevSupport,
3497
3793
  summarizeGitStatus: () => summarizeGitStatus,
3794
+ syncMeshes: () => syncMeshes,
3498
3795
  updateConfig: () => updateConfig,
3796
+ updateMesh: () => updateMesh,
3797
+ updateNode: () => updateNode,
3499
3798
  upsertSavedProviderSession: () => upsertSavedProviderSession
3500
3799
  });
3501
3800
  module.exports = __toCommonJS(index_exports);
3801
+ init_repo_mesh_types();
3502
3802
 
3503
3803
  // src/git/git-executor.ts
3504
3804
  var import_node_child_process = require("child_process");
@@ -5297,9 +5597,69 @@ function getSavedProviderSessions(state, filters) {
5297
5597
  })).sort((a, b) => b.lastUsedAt - a.lastUsedAt);
5298
5598
  }
5299
5599
 
5600
+ // src/index.ts
5601
+ init_mesh_config();
5602
+ init_coordinator_prompt();
5603
+
5604
+ // src/mesh/mesh-sync.ts
5605
+ init_mesh_config();
5606
+ async function syncMeshes(transport) {
5607
+ const result = { pushed: 0, pulled: 0, deleted: 0, errors: [] };
5608
+ let remoteMeshes;
5609
+ try {
5610
+ const res = await transport.listRemoteMeshes();
5611
+ remoteMeshes = res.meshes;
5612
+ } catch (e) {
5613
+ result.errors.push(`Failed to list remote meshes: ${e.message}`);
5614
+ return result;
5615
+ }
5616
+ const localMeshes = listMeshes();
5617
+ const remoteByIdentity = new Map(remoteMeshes.map((m) => [m.repo_identity, m]));
5618
+ const localByIdentity = new Map(localMeshes.map((m) => [m.repoIdentity, m]));
5619
+ for (const local of localMeshes) {
5620
+ if (!remoteByIdentity.has(local.repoIdentity)) {
5621
+ try {
5622
+ await transport.createRemoteMesh({
5623
+ name: local.name,
5624
+ repo_identity: local.repoIdentity,
5625
+ repo_remote_url: local.repoRemoteUrl,
5626
+ default_branch: local.defaultBranch,
5627
+ policy: JSON.stringify(local.policy)
5628
+ });
5629
+ result.pushed++;
5630
+ } catch (e) {
5631
+ result.errors.push(`Push failed for "${local.name}": ${e.message}`);
5632
+ }
5633
+ }
5634
+ }
5635
+ for (const remote of remoteMeshes) {
5636
+ if (!localByIdentity.has(remote.repo_identity)) {
5637
+ try {
5638
+ let policy;
5639
+ try {
5640
+ policy = JSON.parse(remote.policy);
5641
+ } catch {
5642
+ policy = void 0;
5643
+ }
5644
+ createMesh({
5645
+ name: remote.name,
5646
+ repoIdentity: remote.repo_identity,
5647
+ repoRemoteUrl: remote.repo_remote_url || void 0,
5648
+ defaultBranch: remote.default_branch || void 0,
5649
+ policy
5650
+ });
5651
+ result.pulled++;
5652
+ } catch (e) {
5653
+ result.errors.push(`Pull failed for "${remote.name}": ${e.message}`);
5654
+ }
5655
+ }
5656
+ }
5657
+ return result;
5658
+ }
5659
+
5300
5660
  // src/config/state-store.ts
5301
- var import_fs2 = require("fs");
5302
- var import_path2 = require("path");
5661
+ var import_fs3 = require("fs");
5662
+ var import_path3 = require("path");
5303
5663
  init_config();
5304
5664
  var DEFAULT_STATE = {
5305
5665
  recentActivity: [],
@@ -5313,7 +5673,7 @@ function isPlainObject2(value) {
5313
5673
  return !!value && typeof value === "object" && !Array.isArray(value);
5314
5674
  }
5315
5675
  function getStatePath() {
5316
- return (0, import_path2.join)(getConfigDir(), "state.json");
5676
+ return (0, import_path3.join)(getConfigDir(), "state.json");
5317
5677
  }
5318
5678
  function normalizeState(raw) {
5319
5679
  const parsed = isPlainObject2(raw) ? raw : {};
@@ -5349,11 +5709,11 @@ function normalizeState(raw) {
5349
5709
  }
5350
5710
  function loadState() {
5351
5711
  const statePath = getStatePath();
5352
- if (!(0, import_fs2.existsSync)(statePath)) {
5712
+ if (!(0, import_fs3.existsSync)(statePath)) {
5353
5713
  return { ...DEFAULT_STATE };
5354
5714
  }
5355
5715
  try {
5356
- const raw = (0, import_fs2.readFileSync)(statePath, "utf-8");
5716
+ const raw = (0, import_fs3.readFileSync)(statePath, "utf-8");
5357
5717
  return normalizeState(JSON.parse(raw));
5358
5718
  } catch {
5359
5719
  return { ...DEFAULT_STATE };
@@ -5362,7 +5722,7 @@ function loadState() {
5362
5722
  function saveState(state) {
5363
5723
  const statePath = getStatePath();
5364
5724
  const normalized = normalizeState(state);
5365
- (0, import_fs2.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
5725
+ (0, import_fs3.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
5366
5726
  }
5367
5727
  function resetState() {
5368
5728
  saveState({ ...DEFAULT_STATE });
@@ -5370,7 +5730,7 @@ function resetState() {
5370
5730
 
5371
5731
  // src/detection/ide-detector.ts
5372
5732
  var import_child_process = require("child_process");
5373
- var import_fs3 = require("fs");
5733
+ var import_fs4 = require("fs");
5374
5734
  var import_os2 = require("os");
5375
5735
  var path7 = __toESM(require("path"));
5376
5736
  var BUILTIN_IDE_DEFINITIONS = [];
@@ -5394,7 +5754,7 @@ function findCliCommand(command) {
5394
5754
  if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
5395
5755
  const candidate = trimmed.startsWith("~") ? path7.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
5396
5756
  const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
5397
- return (0, import_fs3.existsSync)(resolved) ? resolved : null;
5757
+ return (0, import_fs4.existsSync)(resolved) ? resolved : null;
5398
5758
  }
5399
5759
  try {
5400
5760
  const result = (0, import_child_process.execSync)(
@@ -5425,9 +5785,9 @@ function checkPathExists(paths) {
5425
5785
  if (normalized.includes("*")) {
5426
5786
  const username = home.split(/[\\/]/).pop() || "";
5427
5787
  const resolved = normalized.replace("*", username);
5428
- if ((0, import_fs3.existsSync)(resolved)) return resolved;
5788
+ if ((0, import_fs4.existsSync)(resolved)) return resolved;
5429
5789
  } else {
5430
- if ((0, import_fs3.existsSync)(normalized)) return normalized;
5790
+ if ((0, import_fs4.existsSync)(normalized)) return normalized;
5431
5791
  }
5432
5792
  }
5433
5793
  return null;
@@ -5441,7 +5801,7 @@ async function detectIDEs(providerLoader) {
5441
5801
  let resolvedCli = cliPath;
5442
5802
  if (!resolvedCli && appPath && os21 === "darwin") {
5443
5803
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
5444
- if ((0, import_fs3.existsSync)(bundledCli)) resolvedCli = bundledCli;
5804
+ if ((0, import_fs4.existsSync)(bundledCli)) resolvedCli = bundledCli;
5445
5805
  }
5446
5806
  if (!resolvedCli && appPath && os21 === "win32") {
5447
5807
  const { dirname: dirname7 } = await import("path");
@@ -5454,7 +5814,7 @@ async function detectIDEs(providerLoader) {
5454
5814
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
5455
5815
  ];
5456
5816
  for (const c of candidates) {
5457
- if ((0, import_fs3.existsSync)(c)) {
5817
+ if ((0, import_fs4.existsSync)(c)) {
5458
5818
  resolvedCli = c;
5459
5819
  break;
5460
5820
  }
@@ -5480,7 +5840,7 @@ async function detectIDEs(providerLoader) {
5480
5840
  var import_child_process2 = require("child_process");
5481
5841
  var os2 = __toESM(require("os"));
5482
5842
  var path8 = __toESM(require("path"));
5483
- var import_fs4 = require("fs");
5843
+ var import_fs5 = require("fs");
5484
5844
  function parseVersion(raw) {
5485
5845
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
5486
5846
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
@@ -5504,7 +5864,7 @@ function resolveCommandPath(command) {
5504
5864
  if (isExplicitCommandPath(trimmed)) {
5505
5865
  const expanded = expandHome(trimmed);
5506
5866
  const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
5507
- return (0, import_fs4.existsSync)(candidate) ? candidate : null;
5867
+ return (0, import_fs5.existsSync)(candidate) ? candidate : null;
5508
5868
  }
5509
5869
  return null;
5510
5870
  }
@@ -14242,7 +14602,7 @@ var DaemonCommandHandler = class {
14242
14602
  var os13 = __toESM(require("os"));
14243
14603
  var path16 = __toESM(require("path"));
14244
14604
  var crypto4 = __toESM(require("crypto"));
14245
- var import_fs5 = require("fs");
14605
+ var import_fs6 = require("fs");
14246
14606
  var import_child_process6 = require("child_process");
14247
14607
  var import_chalk = __toESM(require("chalk"));
14248
14608
  init_provider_cli_adapter();
@@ -16380,7 +16740,7 @@ function commandExists(command) {
16380
16740
  const trimmed = command.trim();
16381
16741
  if (!trimmed) return false;
16382
16742
  if (isExplicitCommand(trimmed)) {
16383
- return (0, import_fs5.existsSync)(expandExecutable(trimmed));
16743
+ return (0, import_fs6.existsSync)(expandExecutable(trimmed));
16384
16744
  }
16385
16745
  try {
16386
16746
  (0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -20893,6 +21253,142 @@ var DaemonCommandRouter = class {
20893
21253
  updateConfig({ machineNickname: nickname || null });
20894
21254
  return { success: true };
20895
21255
  }
21256
+ // ─── Mesh CRUD (local meshes.json) ───
21257
+ case "list_meshes": {
21258
+ try {
21259
+ const { listMeshes: listMeshes2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21260
+ return { success: true, meshes: listMeshes2() };
21261
+ } catch (e) {
21262
+ return { success: false, error: e.message };
21263
+ }
21264
+ }
21265
+ case "get_mesh": {
21266
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21267
+ if (!meshId) return { success: false, error: "meshId required" };
21268
+ try {
21269
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21270
+ const mesh = getMesh3(meshId);
21271
+ if (!mesh) return { success: false, error: "Mesh not found" };
21272
+ return { success: true, mesh };
21273
+ } catch (e) {
21274
+ return { success: false, error: e.message };
21275
+ }
21276
+ }
21277
+ case "create_mesh": {
21278
+ const name = typeof args?.name === "string" ? args.name.trim() : "";
21279
+ const repoIdentity = typeof args?.repoIdentity === "string" ? args.repoIdentity.trim() : "";
21280
+ const repoRemoteUrl = typeof args?.repoRemoteUrl === "string" ? args.repoRemoteUrl.trim() : void 0;
21281
+ const defaultBranch = typeof args?.defaultBranch === "string" ? args.defaultBranch.trim() : void 0;
21282
+ if (!name) return { success: false, error: "name required" };
21283
+ try {
21284
+ const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21285
+ const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
21286
+ return { success: true, mesh };
21287
+ } catch (e) {
21288
+ return { success: false, error: e.message };
21289
+ }
21290
+ }
21291
+ case "delete_mesh": {
21292
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21293
+ if (!meshId) return { success: false, error: "meshId required" };
21294
+ try {
21295
+ const { deleteMesh: deleteMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21296
+ const deleted = deleteMesh3(meshId);
21297
+ return { success: true, deleted };
21298
+ } catch (e) {
21299
+ return { success: false, error: e.message };
21300
+ }
21301
+ }
21302
+ case "add_mesh_node": {
21303
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21304
+ const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
21305
+ if (!meshId) return { success: false, error: "meshId required" };
21306
+ if (!workspace) return { success: false, error: "workspace required" };
21307
+ try {
21308
+ const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21309
+ const node = addNode3(meshId, { workspace });
21310
+ if (!node) return { success: false, error: "Mesh not found" };
21311
+ return { success: true, node };
21312
+ } catch (e) {
21313
+ return { success: false, error: e.message };
21314
+ }
21315
+ }
21316
+ case "remove_mesh_node": {
21317
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21318
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
21319
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
21320
+ try {
21321
+ const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21322
+ const removed = removeNode3(meshId, nodeId);
21323
+ return { success: true, removed };
21324
+ } catch (e) {
21325
+ return { success: false, error: e.message };
21326
+ }
21327
+ }
21328
+ // ─── Mesh Coordinator Launch ───
21329
+ case "launch_mesh_coordinator": {
21330
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
21331
+ const cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "claude-cli";
21332
+ if (!meshId) return { success: false, error: "meshId required" };
21333
+ try {
21334
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
21335
+ const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
21336
+ const mesh = getMesh3(meshId);
21337
+ if (!mesh) return { success: false, error: "Mesh not found" };
21338
+ if (mesh.nodes.length === 0) return { success: false, error: "No nodes in mesh" };
21339
+ const workspace = mesh.nodes[0].workspace;
21340
+ const { existsSync: existsSync21, readFileSync: readFileSync15, writeFileSync: writeFileSync12, copyFileSync: copyFileSync3 } = await import("fs");
21341
+ const { join: join23 } = await import("path");
21342
+ const mcpConfigPath = join23(workspace, ".mcp.json");
21343
+ const hadExistingMcpConfig = existsSync21(mcpConfigPath);
21344
+ let existingMcpConfig = {};
21345
+ if (hadExistingMcpConfig) {
21346
+ try {
21347
+ existingMcpConfig = JSON.parse(readFileSync15(mcpConfigPath, "utf-8"));
21348
+ copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
21349
+ } catch {
21350
+ }
21351
+ }
21352
+ const mcpConfig = {
21353
+ ...existingMcpConfig,
21354
+ mcpServers: {
21355
+ ...existingMcpConfig.mcpServers || {},
21356
+ "adhdev-mesh": {
21357
+ command: "adhdev-mcp",
21358
+ args: ["--repo-mesh", meshId]
21359
+ }
21360
+ }
21361
+ };
21362
+ writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
21363
+ LOG.info("MeshCoordinator", `Wrote .mcp.json to ${workspace} with adhdev-mesh server`);
21364
+ let systemPrompt = "";
21365
+ try {
21366
+ systemPrompt = buildCoordinatorSystemPrompt2({ mesh });
21367
+ } catch {
21368
+ 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).`;
21369
+ }
21370
+ const launchResult = await this.deps.cliManager.handleCliCommand("launch_cli", {
21371
+ cliType,
21372
+ dir: workspace,
21373
+ initialPrompt: systemPrompt
21374
+ });
21375
+ if (!launchResult?.success) {
21376
+ return { success: false, error: launchResult?.error || "Failed to launch CLI session" };
21377
+ }
21378
+ LOG.info("MeshCoordinator", `Launched ${cliType} coordinator for mesh ${meshId} in ${workspace}`);
21379
+ return {
21380
+ success: true,
21381
+ meshId,
21382
+ cliType,
21383
+ workspace,
21384
+ sessionId: launchResult.sessionId || launchResult.id,
21385
+ mcpConfigWritten: true
21386
+ };
21387
+ } catch (e) {
21388
+ LOG.error("MeshCoordinator", `Failed: ${e.message}`);
21389
+ return { success: false, error: e.message };
21390
+ }
21391
+ }
20896
21392
  default:
20897
21393
  break;
20898
21394
  }
@@ -28854,6 +29350,7 @@ async function shutdownDaemonComponents(components) {
28854
29350
  DEFAULT_DAEMON_PORT,
28855
29351
  DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
28856
29352
  DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
29353
+ DEFAULT_MESH_POLICY,
28857
29354
  DEFAULT_SESSION_HOST_APP_NAME,
28858
29355
  DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
28859
29356
  DEFAULT_SESSION_HOST_READY_TIMEOUT_MS,
@@ -28887,11 +29384,13 @@ async function shutdownDaemonComponents(components) {
28887
29384
  SessionHostPtyTransportFactory,
28888
29385
  TurnSnapshotTracker,
28889
29386
  VersionArchive,
29387
+ addNode,
28890
29388
  appendRecentActivity,
28891
29389
  buildAssistantChatMessage,
28892
29390
  buildChatMessage,
28893
29391
  buildChatMessageSignature,
28894
29392
  buildChatTailDeliverySignature,
29393
+ buildCoordinatorSystemPrompt,
28895
29394
  buildMachineInfo,
28896
29395
  buildPinnedGlobalInstallCommand,
28897
29396
  buildRuntimeSystemChatMessage,
@@ -28914,6 +29413,8 @@ async function shutdownDaemonComponents(components) {
28914
29413
  createGitSnapshotStore,
28915
29414
  createGitWorkspaceMonitor,
28916
29415
  createInteractionId,
29416
+ createMesh,
29417
+ deleteMesh,
28917
29418
  detectAllVersions,
28918
29419
  detectCLIs,
28919
29420
  detectIDEs,
@@ -28932,6 +29433,8 @@ async function shutdownDaemonComponents(components) {
28932
29433
  getGitRepoStatus,
28933
29434
  getHostMemorySnapshot,
28934
29435
  getLogLevel,
29436
+ getMesh,
29437
+ getMeshByRepo,
28935
29438
  getNpmExecOptions,
28936
29439
  getRecentActivity,
28937
29440
  getRecentCommands,
@@ -28962,6 +29465,7 @@ async function shutdownDaemonComponents(components) {
28962
29465
  launchIDE,
28963
29466
  launchWithCdp,
28964
29467
  listHostedCliRuntimes,
29468
+ listMeshes,
28965
29469
  loadConfig,
28966
29470
  loadState,
28967
29471
  logCommand,
@@ -28977,6 +29481,7 @@ async function shutdownDaemonComponents(components) {
28977
29481
  normalizeInputEnvelope,
28978
29482
  normalizeManagedStatus,
28979
29483
  normalizeMessageParts,
29484
+ normalizeRepoIdentity,
28980
29485
  normalizeSessionModalFields,
28981
29486
  parsePorcelainV2Status,
28982
29487
  parseProviderSourceConfigUpdate,
@@ -28988,6 +29493,7 @@ async function shutdownDaemonComponents(components) {
28988
29493
  readChatHistory,
28989
29494
  recordDebugTrace,
28990
29495
  registerExtensionProviders,
29496
+ removeNode,
28991
29497
  resetConfig,
28992
29498
  resetDebugRuntimeConfig,
28993
29499
  resetState,
@@ -29010,7 +29516,10 @@ async function shutdownDaemonComponents(components) {
29010
29516
  spawnDetachedDaemonUpgradeHelper,
29011
29517
  startDaemonDevSupport,
29012
29518
  summarizeGitStatus,
29519
+ syncMeshes,
29013
29520
  updateConfig,
29521
+ updateMesh,
29522
+ updateNode,
29014
29523
  upsertSavedProviderSession
29015
29524
  });
29016
29525
  //# sourceMappingURL=index.js.map