@adhdev/daemon-standalone 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
@@ -27884,6 +27884,20 @@ var require_dist2 = __commonJS({
27884
27884
  mod
27885
27885
  ));
27886
27886
  var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
27887
+ var DEFAULT_MESH_POLICY;
27888
+ var init_repo_mesh_types = __esm2({
27889
+ "src/repo-mesh-types.ts"() {
27890
+ "use strict";
27891
+ DEFAULT_MESH_POLICY = {
27892
+ requirePreTaskCheckpoint: false,
27893
+ requirePostTaskCheckpoint: true,
27894
+ requireApprovalForPush: true,
27895
+ requireApprovalForDestructiveGit: true,
27896
+ dirtyWorkspaceBehavior: "warn",
27897
+ maxParallelTasks: 2
27898
+ };
27899
+ }
27900
+ });
27887
27901
  var config_exports = {};
27888
27902
  __export2(config_exports, {
27889
27903
  generateMachineId: () => generateMachineId,
@@ -28125,6 +28139,276 @@ var require_dist2 = __commonJS({
28125
28139
  MACHINE_ID_PREFIX = "mach_";
28126
28140
  }
28127
28141
  });
28142
+ var mesh_config_exports = {};
28143
+ __export2(mesh_config_exports, {
28144
+ addNode: () => addNode,
28145
+ createMesh: () => createMesh,
28146
+ deleteMesh: () => deleteMesh,
28147
+ getMesh: () => getMesh,
28148
+ getMeshByRepo: () => getMeshByRepo,
28149
+ listMeshes: () => listMeshes,
28150
+ normalizeRepoIdentity: () => normalizeRepoIdentity,
28151
+ removeNode: () => removeNode,
28152
+ updateMesh: () => updateMesh,
28153
+ updateNode: () => updateNode
28154
+ });
28155
+ function getMeshConfigPath() {
28156
+ return (0, import_path22.join)(getConfigDir(), "meshes.json");
28157
+ }
28158
+ function loadMeshConfig() {
28159
+ const path26 = getMeshConfigPath();
28160
+ if (!(0, import_fs2.existsSync)(path26)) return { meshes: [] };
28161
+ try {
28162
+ const raw = JSON.parse((0, import_fs2.readFileSync)(path26, "utf-8"));
28163
+ if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
28164
+ return raw;
28165
+ } catch {
28166
+ return { meshes: [] };
28167
+ }
28168
+ }
28169
+ function saveMeshConfig(config2) {
28170
+ const path26 = getMeshConfigPath();
28171
+ (0, import_fs2.writeFileSync)(path26, JSON.stringify(config2, null, 2), { encoding: "utf-8", mode: 384 });
28172
+ }
28173
+ function normalizeRepoIdentity(remoteUrl) {
28174
+ let identity = remoteUrl.trim();
28175
+ if (identity.startsWith("http://") || identity.startsWith("https://")) {
28176
+ try {
28177
+ const url2 = new URL(identity);
28178
+ const path26 = url2.pathname.replace(/^\//, "").replace(/\.git$/, "");
28179
+ return `${url2.hostname}/${path26}`;
28180
+ } catch {
28181
+ }
28182
+ }
28183
+ const sshMatch = identity.match(/^(?:ssh:\/\/)?[\w.-]+@([\w.-]+)[:/]([\w.\-/]+?)(?:\.git)?$/);
28184
+ if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
28185
+ return identity;
28186
+ }
28187
+ function listMeshes() {
28188
+ return loadMeshConfig().meshes;
28189
+ }
28190
+ function getMesh(meshId) {
28191
+ return loadMeshConfig().meshes.find((m) => m.id === meshId);
28192
+ }
28193
+ function getMeshByRepo(repoIdentity) {
28194
+ return loadMeshConfig().meshes.find((m) => m.repoIdentity === repoIdentity);
28195
+ }
28196
+ function createMesh(opts) {
28197
+ const config2 = loadMeshConfig();
28198
+ if (config2.meshes.length >= 20) {
28199
+ throw new Error("Maximum 20 meshes allowed");
28200
+ }
28201
+ const repoIdentity = opts.repoIdentity || (opts.repoRemoteUrl ? normalizeRepoIdentity(opts.repoRemoteUrl) : "");
28202
+ if (!repoIdentity) throw new Error("Either repoRemoteUrl or repoIdentity is required");
28203
+ const now = (/* @__PURE__ */ new Date()).toISOString();
28204
+ const mesh = {
28205
+ id: `mesh_${(0, import_crypto32.randomUUID)().replace(/-/g, "")}`,
28206
+ name: opts.name.trim().slice(0, 100),
28207
+ repoIdentity,
28208
+ repoRemoteUrl: opts.repoRemoteUrl,
28209
+ defaultBranch: opts.defaultBranch,
28210
+ policy: { ...DEFAULT_MESH_POLICY, ...opts.policy },
28211
+ coordinator: opts.coordinator || {},
28212
+ nodes: [],
28213
+ createdAt: now,
28214
+ updatedAt: now
28215
+ };
28216
+ config2.meshes.push(mesh);
28217
+ saveMeshConfig(config2);
28218
+ return mesh;
28219
+ }
28220
+ function updateMesh(meshId, opts) {
28221
+ const config2 = loadMeshConfig();
28222
+ const mesh = config2.meshes.find((m) => m.id === meshId);
28223
+ if (!mesh) return void 0;
28224
+ if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
28225
+ if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
28226
+ if (opts.policy) mesh.policy = { ...mesh.policy, ...opts.policy };
28227
+ if (opts.coordinator) mesh.coordinator = opts.coordinator;
28228
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
28229
+ saveMeshConfig(config2);
28230
+ return mesh;
28231
+ }
28232
+ function deleteMesh(meshId) {
28233
+ const config2 = loadMeshConfig();
28234
+ const idx = config2.meshes.findIndex((m) => m.id === meshId);
28235
+ if (idx === -1) return false;
28236
+ config2.meshes.splice(idx, 1);
28237
+ saveMeshConfig(config2);
28238
+ return true;
28239
+ }
28240
+ function addNode(meshId, opts) {
28241
+ const config2 = loadMeshConfig();
28242
+ const mesh = config2.meshes.find((m) => m.id === meshId);
28243
+ if (!mesh) return void 0;
28244
+ if (mesh.nodes.length >= 10) {
28245
+ throw new Error("Maximum 10 nodes per mesh");
28246
+ }
28247
+ if (mesh.nodes.some((n) => n.workspace === opts.workspace)) {
28248
+ throw new Error("This workspace is already in the mesh");
28249
+ }
28250
+ const node = {
28251
+ id: `node_${(0, import_crypto32.randomUUID)().replace(/-/g, "")}`,
28252
+ workspace: opts.workspace.trim(),
28253
+ repoRoot: opts.repoRoot,
28254
+ userOverrides: opts.userOverrides || {},
28255
+ policy: opts.policy || {},
28256
+ isLocalWorktree: opts.isLocalWorktree
28257
+ };
28258
+ mesh.nodes.push(node);
28259
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
28260
+ saveMeshConfig(config2);
28261
+ return node;
28262
+ }
28263
+ function removeNode(meshId, nodeId) {
28264
+ const config2 = loadMeshConfig();
28265
+ const mesh = config2.meshes.find((m) => m.id === meshId);
28266
+ if (!mesh) return false;
28267
+ const idx = mesh.nodes.findIndex((n) => n.id === nodeId);
28268
+ if (idx === -1) return false;
28269
+ mesh.nodes.splice(idx, 1);
28270
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
28271
+ saveMeshConfig(config2);
28272
+ return true;
28273
+ }
28274
+ function updateNode(meshId, nodeId, opts) {
28275
+ const config2 = loadMeshConfig();
28276
+ const mesh = config2.meshes.find((m) => m.id === meshId);
28277
+ if (!mesh) return void 0;
28278
+ const node = mesh.nodes.find((n) => n.id === nodeId);
28279
+ if (!node) return void 0;
28280
+ if (opts.userOverrides) node.userOverrides = { ...node.userOverrides, ...opts.userOverrides };
28281
+ if (opts.policy) node.policy = { ...node.policy, ...opts.policy };
28282
+ mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
28283
+ saveMeshConfig(config2);
28284
+ return node;
28285
+ }
28286
+ var import_fs2;
28287
+ var import_path22;
28288
+ var import_crypto32;
28289
+ var init_mesh_config = __esm2({
28290
+ "src/config/mesh-config.ts"() {
28291
+ "use strict";
28292
+ import_fs2 = require("fs");
28293
+ import_path22 = require("path");
28294
+ import_crypto32 = require("crypto");
28295
+ init_config();
28296
+ init_repo_mesh_types();
28297
+ }
28298
+ });
28299
+ var coordinator_prompt_exports = {};
28300
+ __export2(coordinator_prompt_exports, {
28301
+ buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
28302
+ });
28303
+ function buildCoordinatorSystemPrompt(ctx) {
28304
+ const { mesh, status, userInstruction } = ctx;
28305
+ const sections = [];
28306
+ 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.
28307
+
28308
+ Your mesh: **${mesh.name}**
28309
+ Repository: \`${mesh.repoIdentity}\`${mesh.defaultBranch ? `
28310
+ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
28311
+ if (status?.nodes?.length) {
28312
+ sections.push(buildNodeStatusSection(status.nodes));
28313
+ } else if (mesh.nodes.length) {
28314
+ sections.push(buildNodeConfigSection(mesh));
28315
+ } else {
28316
+ sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
28317
+ }
28318
+ sections.push(buildPolicySection(mesh.policy));
28319
+ sections.push(TOOLS_SECTION);
28320
+ sections.push(WORKFLOW_SECTION);
28321
+ sections.push(RULES_SECTION);
28322
+ if (userInstruction) {
28323
+ sections.push(`## Additional Context
28324
+ ${userInstruction}`);
28325
+ }
28326
+ if (mesh.coordinator.systemPromptSuffix) {
28327
+ sections.push(mesh.coordinator.systemPromptSuffix);
28328
+ }
28329
+ return sections.join("\n\n");
28330
+ }
28331
+ function buildNodeStatusSection(nodes) {
28332
+ const lines = ["## Current Node Status", ""];
28333
+ for (const n of nodes) {
28334
+ const healthIcon = n.health === "online" ? "\u{1F7E2}" : n.health === "dirty" ? "\u{1F7E1}" : n.health === "offline" ? "\u26AB" : "\u{1F534}";
28335
+ const sessions = n.activeSessions.length > 0 ? `sessions: ${n.activeSessions.join(", ")}` : "no active sessions";
28336
+ const branch = n.git?.branch ? `branch: \`${n.git.branch}\`` : "";
28337
+ lines.push(`- ${healthIcon} **${n.machineLabel}** (${n.nodeId})`);
28338
+ lines.push(` workspace: \`${n.workspace}\` | ${branch} | ${sessions}`);
28339
+ if (n.error) lines.push(` \u26A0\uFE0F ${n.error}`);
28340
+ }
28341
+ return lines.join("\n");
28342
+ }
28343
+ function buildNodeConfigSection(mesh) {
28344
+ const lines = ["## Configured Nodes", ""];
28345
+ for (const n of mesh.nodes) {
28346
+ const labels = [];
28347
+ if (n.isLocalWorktree) labels.push("worktree");
28348
+ if (n.policy.readOnly) labels.push("read-only");
28349
+ const suffix = labels.length ? ` [${labels.join(", ")}]` : "";
28350
+ lines.push(`- **${n.workspace}** (${n.id})${suffix}`);
28351
+ }
28352
+ lines.push("", "_Use `mesh_status` to probe live health before delegating work._");
28353
+ return lines.join("\n");
28354
+ }
28355
+ function buildPolicySection(policy) {
28356
+ const rules = [];
28357
+ if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
28358
+ if (policy.requirePostTaskCheckpoint) rules.push("- Create a git checkpoint **after** each task completes");
28359
+ if (policy.requireApprovalForPush) rules.push("- **Ask for user approval** before pushing to remote");
28360
+ if (policy.requireApprovalForDestructiveGit) rules.push("- **Ask for user approval** before destructive git operations (force push, reset, etc.)");
28361
+ const dirtyBehavior = {
28362
+ block: "- **Do not** send tasks to nodes with dirty workspaces",
28363
+ warn: "- Warn the user if a node has uncommitted changes before sending a task",
28364
+ checkpoint_then_continue: "- Auto-checkpoint dirty nodes before sending tasks"
28365
+ }[policy.dirtyWorkspaceBehavior] || "";
28366
+ if (dirtyBehavior) rules.push(dirtyBehavior);
28367
+ rules.push(`- Maximum **${policy.maxParallelTasks}** tasks running in parallel`);
28368
+ return `## Policy
28369
+ ${rules.join("\n")}`;
28370
+ }
28371
+ var TOOLS_SECTION;
28372
+ var WORKFLOW_SECTION;
28373
+ var RULES_SECTION;
28374
+ var init_coordinator_prompt = __esm2({
28375
+ "src/mesh/coordinator-prompt.ts"() {
28376
+ "use strict";
28377
+ TOOLS_SECTION = `## Available Tools
28378
+
28379
+ | Tool | Purpose |
28380
+ |------|---------|
28381
+ | \`mesh_status\` | Check all nodes' health, git state, and active sessions |
28382
+ | \`mesh_list_nodes\` | List nodes with workspace paths |
28383
+ | \`mesh_launch_session\` | Start a new agent session on a node |
28384
+ | \`mesh_send_task\` | Send a task (natural language) to a running agent |
28385
+ | \`mesh_read_chat\` | Read an agent's recent messages to check progress |
28386
+ | \`mesh_git_status\` | Check git status on a specific node |
28387
+ | \`mesh_checkpoint\` | Create a git checkpoint on a node |
28388
+ | \`mesh_approve\` | Approve/reject a pending agent action |`;
28389
+ WORKFLOW_SECTION = `## Orchestration Workflow
28390
+
28391
+ 1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
28392
+ 2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
28393
+ 3. **Delegate** \u2014 For each task:
28394
+ a. Pick the best node (consider: health, dirty state, current workload).
28395
+ b. If no session exists, call \`mesh_launch_session\` to start one.
28396
+ c. Call \`mesh_send_task\` with a clear, self-contained natural-language instruction.
28397
+ 4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
28398
+ 5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
28399
+ 6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
28400
+ 7. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
28401
+ RULES_SECTION = `## Rules
28402
+
28403
+ - **Be conversational.** Delegate work the way a tech lead would \u2014 clear, specific instructions in natural language.
28404
+ - **Don't inspect code.** Trust the agent's output. Verify via git diff/status, not by reading source files.
28405
+ - **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
28406
+ - **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
28407
+ - **Keep the user informed.** Report progress after each delegation round.
28408
+ - **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
28409
+ - **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
28410
+ }
28411
+ });
28128
28412
  function setLogLevel(level) {
28129
28413
  currentLevel = level;
28130
28414
  daemonLog("Logger", `Log level set to: ${level}`, "info");
@@ -31208,6 +31492,7 @@ var require_dist2 = __commonJS({
31208
31492
  DEFAULT_DAEMON_PORT: () => DEFAULT_DAEMON_PORT,
31209
31493
  DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS: () => DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
31210
31494
  DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS2,
31495
+ DEFAULT_MESH_POLICY: () => DEFAULT_MESH_POLICY,
31211
31496
  DEFAULT_SESSION_HOST_APP_NAME: () => DEFAULT_SESSION_HOST_APP_NAME,
31212
31497
  DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS2,
31213
31498
  DEFAULT_SESSION_HOST_READY_TIMEOUT_MS: () => DEFAULT_SESSION_HOST_READY_TIMEOUT_MS2,
@@ -31241,11 +31526,13 @@ var require_dist2 = __commonJS({
31241
31526
  SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory2,
31242
31527
  TurnSnapshotTracker: () => TurnSnapshotTracker,
31243
31528
  VersionArchive: () => VersionArchive,
31529
+ addNode: () => addNode,
31244
31530
  appendRecentActivity: () => appendRecentActivity,
31245
31531
  buildAssistantChatMessage: () => buildAssistantChatMessage,
31246
31532
  buildChatMessage: () => buildChatMessage,
31247
31533
  buildChatMessageSignature: () => buildChatMessageSignature,
31248
31534
  buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
31535
+ buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt,
31249
31536
  buildMachineInfo: () => buildMachineInfo2,
31250
31537
  buildPinnedGlobalInstallCommand: () => buildPinnedGlobalInstallCommand,
31251
31538
  buildRuntimeSystemChatMessage: () => buildRuntimeSystemChatMessage,
@@ -31268,6 +31555,8 @@ var require_dist2 = __commonJS({
31268
31555
  createGitSnapshotStore: () => createGitSnapshotStore,
31269
31556
  createGitWorkspaceMonitor: () => createGitWorkspaceMonitor2,
31270
31557
  createInteractionId: () => createInteractionId,
31558
+ createMesh: () => createMesh,
31559
+ deleteMesh: () => deleteMesh,
31271
31560
  detectAllVersions: () => detectAllVersions,
31272
31561
  detectCLIs: () => detectCLIs,
31273
31562
  detectIDEs: () => detectIDEs,
@@ -31286,6 +31575,8 @@ var require_dist2 = __commonJS({
31286
31575
  getGitRepoStatus: () => getGitRepoStatus,
31287
31576
  getHostMemorySnapshot: () => getHostMemorySnapshot,
31288
31577
  getLogLevel: () => getLogLevel,
31578
+ getMesh: () => getMesh,
31579
+ getMeshByRepo: () => getMeshByRepo,
31289
31580
  getNpmExecOptions: () => getNpmExecOptions,
31290
31581
  getRecentActivity: () => getRecentActivity,
31291
31582
  getRecentCommands: () => getRecentCommands,
@@ -31316,6 +31607,7 @@ var require_dist2 = __commonJS({
31316
31607
  launchIDE: () => launchIDE,
31317
31608
  launchWithCdp: () => launchWithCdp,
31318
31609
  listHostedCliRuntimes: () => listHostedCliRuntimes2,
31610
+ listMeshes: () => listMeshes,
31319
31611
  loadConfig: () => loadConfig2,
31320
31612
  loadState: () => loadState,
31321
31613
  logCommand: () => logCommand,
@@ -31331,6 +31623,7 @@ var require_dist2 = __commonJS({
31331
31623
  normalizeInputEnvelope: () => normalizeInputEnvelope,
31332
31624
  normalizeManagedStatus: () => normalizeManagedStatus,
31333
31625
  normalizeMessageParts: () => normalizeMessageParts,
31626
+ normalizeRepoIdentity: () => normalizeRepoIdentity,
31334
31627
  normalizeSessionModalFields: () => normalizeSessionModalFields,
31335
31628
  parsePorcelainV2Status: () => parsePorcelainV2Status,
31336
31629
  parseProviderSourceConfigUpdate: () => parseProviderSourceConfigUpdate,
@@ -31342,6 +31635,7 @@ var require_dist2 = __commonJS({
31342
31635
  readChatHistory: () => readChatHistory,
31343
31636
  recordDebugTrace: () => recordDebugTrace,
31344
31637
  registerExtensionProviders: () => registerExtensionProviders,
31638
+ removeNode: () => removeNode,
31345
31639
  resetConfig: () => resetConfig,
31346
31640
  resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
31347
31641
  resetState: () => resetState,
@@ -31364,10 +31658,14 @@ var require_dist2 = __commonJS({
31364
31658
  spawnDetachedDaemonUpgradeHelper: () => spawnDetachedDaemonUpgradeHelper,
31365
31659
  startDaemonDevSupport: () => startDaemonDevSupport2,
31366
31660
  summarizeGitStatus: () => summarizeGitStatus,
31661
+ syncMeshes: () => syncMeshes,
31367
31662
  updateConfig: () => updateConfig,
31663
+ updateMesh: () => updateMesh,
31664
+ updateNode: () => updateNode,
31368
31665
  upsertSavedProviderSession: () => upsertSavedProviderSession
31369
31666
  });
31370
31667
  module2.exports = __toCommonJS2(index_exports);
31668
+ init_repo_mesh_types();
31371
31669
  var import_node_child_process = require("child_process");
31372
31670
  var import_node_fs3 = require("fs");
31373
31671
  var import_promises4 = require("fs/promises");
@@ -33137,8 +33435,64 @@ var require_dist2 = __commonJS({
33137
33435
  })
33138
33436
  })).sort((a, b2) => b2.lastUsedAt - a.lastUsedAt);
33139
33437
  }
33140
- var import_fs2 = require("fs");
33141
- var import_path22 = require("path");
33438
+ init_mesh_config();
33439
+ init_coordinator_prompt();
33440
+ init_mesh_config();
33441
+ async function syncMeshes(transport) {
33442
+ const result = { pushed: 0, pulled: 0, deleted: 0, errors: [] };
33443
+ let remoteMeshes;
33444
+ try {
33445
+ const res = await transport.listRemoteMeshes();
33446
+ remoteMeshes = res.meshes;
33447
+ } catch (e) {
33448
+ result.errors.push(`Failed to list remote meshes: ${e.message}`);
33449
+ return result;
33450
+ }
33451
+ const localMeshes = listMeshes();
33452
+ const remoteByIdentity = new Map(remoteMeshes.map((m) => [m.repo_identity, m]));
33453
+ const localByIdentity = new Map(localMeshes.map((m) => [m.repoIdentity, m]));
33454
+ for (const local of localMeshes) {
33455
+ if (!remoteByIdentity.has(local.repoIdentity)) {
33456
+ try {
33457
+ await transport.createRemoteMesh({
33458
+ name: local.name,
33459
+ repo_identity: local.repoIdentity,
33460
+ repo_remote_url: local.repoRemoteUrl,
33461
+ default_branch: local.defaultBranch,
33462
+ policy: JSON.stringify(local.policy)
33463
+ });
33464
+ result.pushed++;
33465
+ } catch (e) {
33466
+ result.errors.push(`Push failed for "${local.name}": ${e.message}`);
33467
+ }
33468
+ }
33469
+ }
33470
+ for (const remote of remoteMeshes) {
33471
+ if (!localByIdentity.has(remote.repo_identity)) {
33472
+ try {
33473
+ let policy;
33474
+ try {
33475
+ policy = JSON.parse(remote.policy);
33476
+ } catch {
33477
+ policy = void 0;
33478
+ }
33479
+ createMesh({
33480
+ name: remote.name,
33481
+ repoIdentity: remote.repo_identity,
33482
+ repoRemoteUrl: remote.repo_remote_url || void 0,
33483
+ defaultBranch: remote.default_branch || void 0,
33484
+ policy
33485
+ });
33486
+ result.pulled++;
33487
+ } catch (e) {
33488
+ result.errors.push(`Pull failed for "${remote.name}": ${e.message}`);
33489
+ }
33490
+ }
33491
+ }
33492
+ return result;
33493
+ }
33494
+ var import_fs3 = require("fs");
33495
+ var import_path3 = require("path");
33142
33496
  init_config();
33143
33497
  var DEFAULT_STATE = {
33144
33498
  recentActivity: [],
@@ -33152,7 +33506,7 @@ var require_dist2 = __commonJS({
33152
33506
  return !!value && typeof value === "object" && !Array.isArray(value);
33153
33507
  }
33154
33508
  function getStatePath() {
33155
- return (0, import_path22.join)(getConfigDir(), "state.json");
33509
+ return (0, import_path3.join)(getConfigDir(), "state.json");
33156
33510
  }
33157
33511
  function normalizeState(raw) {
33158
33512
  const parsed = isPlainObject22(raw) ? raw : {};
@@ -33188,11 +33542,11 @@ var require_dist2 = __commonJS({
33188
33542
  }
33189
33543
  function loadState() {
33190
33544
  const statePath = getStatePath();
33191
- if (!(0, import_fs2.existsSync)(statePath)) {
33545
+ if (!(0, import_fs3.existsSync)(statePath)) {
33192
33546
  return { ...DEFAULT_STATE };
33193
33547
  }
33194
33548
  try {
33195
- const raw = (0, import_fs2.readFileSync)(statePath, "utf-8");
33549
+ const raw = (0, import_fs3.readFileSync)(statePath, "utf-8");
33196
33550
  return normalizeState(JSON.parse(raw));
33197
33551
  } catch {
33198
33552
  return { ...DEFAULT_STATE };
@@ -33201,13 +33555,13 @@ var require_dist2 = __commonJS({
33201
33555
  function saveState(state) {
33202
33556
  const statePath = getStatePath();
33203
33557
  const normalized = normalizeState(state);
33204
- (0, import_fs2.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
33558
+ (0, import_fs3.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
33205
33559
  }
33206
33560
  function resetState() {
33207
33561
  saveState({ ...DEFAULT_STATE });
33208
33562
  }
33209
33563
  var import_child_process = require("child_process");
33210
- var import_fs3 = require("fs");
33564
+ var import_fs4 = require("fs");
33211
33565
  var import_os22 = require("os");
33212
33566
  var path7 = __toESM2(require("path"));
33213
33567
  var BUILTIN_IDE_DEFINITIONS = [];
@@ -33231,7 +33585,7 @@ var require_dist2 = __commonJS({
33231
33585
  if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
33232
33586
  const candidate = trimmed.startsWith("~") ? path7.join((0, import_os22.homedir)(), trimmed.slice(1)) : trimmed;
33233
33587
  const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
33234
- return (0, import_fs3.existsSync)(resolved) ? resolved : null;
33588
+ return (0, import_fs4.existsSync)(resolved) ? resolved : null;
33235
33589
  }
33236
33590
  try {
33237
33591
  const result = (0, import_child_process.execSync)(
@@ -33262,9 +33616,9 @@ var require_dist2 = __commonJS({
33262
33616
  if (normalized.includes("*")) {
33263
33617
  const username = home.split(/[\\/]/).pop() || "";
33264
33618
  const resolved = normalized.replace("*", username);
33265
- if ((0, import_fs3.existsSync)(resolved)) return resolved;
33619
+ if ((0, import_fs4.existsSync)(resolved)) return resolved;
33266
33620
  } else {
33267
- if ((0, import_fs3.existsSync)(normalized)) return normalized;
33621
+ if ((0, import_fs4.existsSync)(normalized)) return normalized;
33268
33622
  }
33269
33623
  }
33270
33624
  return null;
@@ -33278,7 +33632,7 @@ var require_dist2 = __commonJS({
33278
33632
  let resolvedCli = cliPath;
33279
33633
  if (!resolvedCli && appPath && os21 === "darwin") {
33280
33634
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
33281
- if ((0, import_fs3.existsSync)(bundledCli)) resolvedCli = bundledCli;
33635
+ if ((0, import_fs4.existsSync)(bundledCli)) resolvedCli = bundledCli;
33282
33636
  }
33283
33637
  if (!resolvedCli && appPath && os21 === "win32") {
33284
33638
  const { dirname: dirname7 } = await import("path");
@@ -33291,7 +33645,7 @@ var require_dist2 = __commonJS({
33291
33645
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
33292
33646
  ];
33293
33647
  for (const c of candidates) {
33294
- if ((0, import_fs3.existsSync)(c)) {
33648
+ if ((0, import_fs4.existsSync)(c)) {
33295
33649
  resolvedCli = c;
33296
33650
  break;
33297
33651
  }
@@ -33315,7 +33669,7 @@ var require_dist2 = __commonJS({
33315
33669
  var import_child_process2 = require("child_process");
33316
33670
  var os22 = __toESM2(require("os"));
33317
33671
  var path8 = __toESM2(require("path"));
33318
- var import_fs4 = require("fs");
33672
+ var import_fs5 = require("fs");
33319
33673
  function parseVersion(raw) {
33320
33674
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
33321
33675
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
@@ -33339,7 +33693,7 @@ var require_dist2 = __commonJS({
33339
33693
  if (isExplicitCommandPath(trimmed)) {
33340
33694
  const expanded = expandHome(trimmed);
33341
33695
  const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
33342
- return (0, import_fs4.existsSync)(candidate) ? candidate : null;
33696
+ return (0, import_fs5.existsSync)(candidate) ? candidate : null;
33343
33697
  }
33344
33698
  return null;
33345
33699
  }
@@ -41991,7 +42345,7 @@ ${effect.notification.body || ""}`.trim();
41991
42345
  var os13 = __toESM2(require("os"));
41992
42346
  var path16 = __toESM2(require("path"));
41993
42347
  var crypto4 = __toESM2(require("crypto"));
41994
- var import_fs5 = require("fs");
42348
+ var import_fs6 = require("fs");
41995
42349
  var import_child_process6 = require("child_process");
41996
42350
  var import_chalk = __toESM2(require("chalk"));
41997
42351
  init_provider_cli_adapter();
@@ -44115,7 +44469,7 @@ ${rawInput}` : rawInput;
44115
44469
  const trimmed = command.trim();
44116
44470
  if (!trimmed) return false;
44117
44471
  if (isExplicitCommand(trimmed)) {
44118
- return (0, import_fs5.existsSync)(expandExecutable(trimmed));
44472
+ return (0, import_fs6.existsSync)(expandExecutable(trimmed));
44119
44473
  }
44120
44474
  try {
44121
44475
  (0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -48604,6 +48958,142 @@ Run 'adhdev doctor' for detailed diagnostics.`
48604
48958
  updateConfig({ machineNickname: nickname || null });
48605
48959
  return { success: true };
48606
48960
  }
48961
+ // ─── Mesh CRUD (local meshes.json) ───
48962
+ case "list_meshes": {
48963
+ try {
48964
+ const { listMeshes: listMeshes2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
48965
+ return { success: true, meshes: listMeshes2() };
48966
+ } catch (e) {
48967
+ return { success: false, error: e.message };
48968
+ }
48969
+ }
48970
+ case "get_mesh": {
48971
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
48972
+ if (!meshId) return { success: false, error: "meshId required" };
48973
+ try {
48974
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
48975
+ const mesh = getMesh3(meshId);
48976
+ if (!mesh) return { success: false, error: "Mesh not found" };
48977
+ return { success: true, mesh };
48978
+ } catch (e) {
48979
+ return { success: false, error: e.message };
48980
+ }
48981
+ }
48982
+ case "create_mesh": {
48983
+ const name = typeof args?.name === "string" ? args.name.trim() : "";
48984
+ const repoIdentity = typeof args?.repoIdentity === "string" ? args.repoIdentity.trim() : "";
48985
+ const repoRemoteUrl = typeof args?.repoRemoteUrl === "string" ? args.repoRemoteUrl.trim() : void 0;
48986
+ const defaultBranch = typeof args?.defaultBranch === "string" ? args.defaultBranch.trim() : void 0;
48987
+ if (!name) return { success: false, error: "name required" };
48988
+ try {
48989
+ const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
48990
+ const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
48991
+ return { success: true, mesh };
48992
+ } catch (e) {
48993
+ return { success: false, error: e.message };
48994
+ }
48995
+ }
48996
+ case "delete_mesh": {
48997
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
48998
+ if (!meshId) return { success: false, error: "meshId required" };
48999
+ try {
49000
+ const { deleteMesh: deleteMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
49001
+ const deleted = deleteMesh3(meshId);
49002
+ return { success: true, deleted };
49003
+ } catch (e) {
49004
+ return { success: false, error: e.message };
49005
+ }
49006
+ }
49007
+ case "add_mesh_node": {
49008
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
49009
+ const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
49010
+ if (!meshId) return { success: false, error: "meshId required" };
49011
+ if (!workspace) return { success: false, error: "workspace required" };
49012
+ try {
49013
+ const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
49014
+ const node = addNode3(meshId, { workspace });
49015
+ if (!node) return { success: false, error: "Mesh not found" };
49016
+ return { success: true, node };
49017
+ } catch (e) {
49018
+ return { success: false, error: e.message };
49019
+ }
49020
+ }
49021
+ case "remove_mesh_node": {
49022
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
49023
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
49024
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
49025
+ try {
49026
+ const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
49027
+ const removed = removeNode3(meshId, nodeId);
49028
+ return { success: true, removed };
49029
+ } catch (e) {
49030
+ return { success: false, error: e.message };
49031
+ }
49032
+ }
49033
+ // ─── Mesh Coordinator Launch ───
49034
+ case "launch_mesh_coordinator": {
49035
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
49036
+ const cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "claude-cli";
49037
+ if (!meshId) return { success: false, error: "meshId required" };
49038
+ try {
49039
+ const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
49040
+ const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
49041
+ const mesh = getMesh3(meshId);
49042
+ if (!mesh) return { success: false, error: "Mesh not found" };
49043
+ if (mesh.nodes.length === 0) return { success: false, error: "No nodes in mesh" };
49044
+ const workspace = mesh.nodes[0].workspace;
49045
+ const { existsSync: existsSync21, readFileSync: readFileSync15, writeFileSync: writeFileSync12, copyFileSync: copyFileSync3 } = await import("fs");
49046
+ const { join: join23 } = await import("path");
49047
+ const mcpConfigPath = join23(workspace, ".mcp.json");
49048
+ const hadExistingMcpConfig = existsSync21(mcpConfigPath);
49049
+ let existingMcpConfig = {};
49050
+ if (hadExistingMcpConfig) {
49051
+ try {
49052
+ existingMcpConfig = JSON.parse(readFileSync15(mcpConfigPath, "utf-8"));
49053
+ copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
49054
+ } catch {
49055
+ }
49056
+ }
49057
+ const mcpConfig = {
49058
+ ...existingMcpConfig,
49059
+ mcpServers: {
49060
+ ...existingMcpConfig.mcpServers || {},
49061
+ "adhdev-mesh": {
49062
+ command: "adhdev-mcp",
49063
+ args: ["--repo-mesh", meshId]
49064
+ }
49065
+ }
49066
+ };
49067
+ writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
49068
+ LOG2.info("MeshCoordinator", `Wrote .mcp.json to ${workspace} with adhdev-mesh server`);
49069
+ let systemPrompt = "";
49070
+ try {
49071
+ systemPrompt = buildCoordinatorSystemPrompt2({ mesh });
49072
+ } catch {
49073
+ 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).`;
49074
+ }
49075
+ const launchResult = await this.deps.cliManager.handleCliCommand("launch_cli", {
49076
+ cliType,
49077
+ dir: workspace,
49078
+ initialPrompt: systemPrompt
49079
+ });
49080
+ if (!launchResult?.success) {
49081
+ return { success: false, error: launchResult?.error || "Failed to launch CLI session" };
49082
+ }
49083
+ LOG2.info("MeshCoordinator", `Launched ${cliType} coordinator for mesh ${meshId} in ${workspace}`);
49084
+ return {
49085
+ success: true,
49086
+ meshId,
49087
+ cliType,
49088
+ workspace,
49089
+ sessionId: launchResult.sessionId || launchResult.id,
49090
+ mcpConfigWritten: true
49091
+ };
49092
+ } catch (e) {
49093
+ LOG2.error("MeshCoordinator", `Failed: ${e.message}`);
49094
+ return { success: false, error: e.message };
49095
+ }
49096
+ }
48607
49097
  default:
48608
49098
  break;
48609
49099
  }