@adhdev/daemon-core 0.9.76-rc.5 → 0.9.76-rc.51
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/cli-adapters/provider-cli-adapter.d.ts +2 -1
- package/dist/cli-adapters/provider-cli-runtime.d.ts +1 -0
- package/dist/commands/cli-manager.d.ts +17 -4
- package/dist/commands/mesh-coordinator.d.ts +2 -0
- package/dist/commands/router.d.ts +11 -0
- package/dist/config/mesh-config.d.ts +3 -0
- package/dist/git/git-types.d.ts +1 -1
- package/dist/git/git-worktree.d.ts +64 -0
- package/dist/git/index.d.ts +2 -0
- package/dist/index.js +1398 -436
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1425 -467
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +1 -0
- package/dist/mesh/mesh-events.d.ts +9 -0
- package/dist/providers/chat-message-normalization.d.ts +11 -0
- package/dist/providers/cli-provider-instance.d.ts +3 -0
- package/dist/providers/provider-instance-manager.d.ts +1 -0
- package/dist/providers/provider-instance.d.ts +2 -0
- package/dist/repo-mesh-types.d.ts +13 -0
- package/dist/shared-types.d.ts +4 -0
- package/package.json +4 -5
- package/src/cli-adapters/provider-cli-adapter.ts +28 -7
- package/src/cli-adapters/provider-cli-runtime.ts +3 -2
- package/src/commands/chat-commands.ts +109 -8
- package/src/commands/cli-manager.ts +78 -5
- package/src/commands/handler.ts +13 -4
- package/src/commands/mesh-coordinator.ts +149 -6
- package/src/commands/router.d.ts +1 -0
- package/src/commands/router.ts +554 -34
- package/src/config/mesh-config.ts +23 -2
- package/src/git/git-commands.ts +5 -1
- package/src/git/git-types.ts +1 -0
- package/src/git/git-worktree.ts +214 -0
- package/src/git/index.ts +14 -0
- package/src/mesh/coordinator-prompt.ts +25 -10
- package/src/mesh/mesh-events.ts +109 -43
- package/src/providers/chat-message-normalization.ts +54 -0
- package/src/providers/cli-provider-instance.d.ts +2 -0
- package/src/providers/cli-provider-instance.ts +58 -7
- package/src/providers/provider-instance-manager.ts +20 -1
- package/src/providers/provider-instance.ts +2 -0
- package/src/repo-mesh-types.ts +15 -0
- package/src/shared-types.ts +4 -0
- package/src/status/builders.ts +17 -12
- package/src/status/reporter.ts +6 -0
package/dist/index.mjs
CHANGED
|
@@ -36,11 +36,140 @@ var init_repo_mesh_types = __esm({
|
|
|
36
36
|
requireApprovalForPush: true,
|
|
37
37
|
requireApprovalForDestructiveGit: true,
|
|
38
38
|
dirtyWorkspaceBehavior: "warn",
|
|
39
|
-
maxParallelTasks: 2
|
|
39
|
+
maxParallelTasks: 2,
|
|
40
|
+
sessionCleanupOnNodeRemove: "preserve"
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
});
|
|
43
44
|
|
|
45
|
+
// src/git/git-worktree.ts
|
|
46
|
+
var git_worktree_exports = {};
|
|
47
|
+
__export(git_worktree_exports, {
|
|
48
|
+
createWorktree: () => createWorktree,
|
|
49
|
+
listWorktrees: () => listWorktrees,
|
|
50
|
+
parseWorktreeListOutput: () => parseWorktreeListOutput,
|
|
51
|
+
removeWorktree: () => removeWorktree,
|
|
52
|
+
resolveWorktreePath: () => resolveWorktreePath
|
|
53
|
+
});
|
|
54
|
+
import * as path4 from "path";
|
|
55
|
+
import { mkdir } from "fs/promises";
|
|
56
|
+
import { existsSync } from "fs";
|
|
57
|
+
import { execFile as execFile2 } from "child_process";
|
|
58
|
+
import { promisify as promisify2 } from "util";
|
|
59
|
+
function resolveWorktreePath(repoRoot, meshName, branch) {
|
|
60
|
+
const safeBranch = branch.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
|
|
61
|
+
const safeMeshName = meshName.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
|
|
62
|
+
const parentDir = path4.dirname(repoRoot);
|
|
63
|
+
return path4.join(parentDir, WORKTREE_DIR_NAME, safeMeshName, safeBranch);
|
|
64
|
+
}
|
|
65
|
+
async function createWorktree(opts) {
|
|
66
|
+
const { repoRoot, branch, baseBranch, meshName } = opts;
|
|
67
|
+
const targetDir = opts.targetDir || resolveWorktreePath(repoRoot, meshName, branch);
|
|
68
|
+
if (existsSync(targetDir)) {
|
|
69
|
+
throw new Error(`Worktree target directory already exists: ${targetDir}`);
|
|
70
|
+
}
|
|
71
|
+
await mkdir(path4.dirname(targetDir), { recursive: true });
|
|
72
|
+
const args = ["worktree", "add", targetDir, "-b", branch];
|
|
73
|
+
if (baseBranch) {
|
|
74
|
+
args.push(baseBranch);
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
await execFileAsync2("git", args, {
|
|
78
|
+
cwd: repoRoot,
|
|
79
|
+
encoding: "utf8",
|
|
80
|
+
timeout: GIT_TIMEOUT_MS,
|
|
81
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
82
|
+
windowsHide: true
|
|
83
|
+
});
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const stderr = typeof error.stderr === "string" ? error.stderr : "";
|
|
86
|
+
if (/already exists/i.test(stderr)) {
|
|
87
|
+
throw new Error(`Branch '${branch}' already exists or is checked out in another worktree`);
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`git worktree add failed: ${stderr.trim() || error.message}`);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
worktreePath: targetDir,
|
|
94
|
+
branch
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async function removeWorktree(repoRoot, worktreePath) {
|
|
98
|
+
if (!existsSync(worktreePath)) {
|
|
99
|
+
await pruneWorktrees(repoRoot);
|
|
100
|
+
return { success: true, removedPath: worktreePath };
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
await execFileAsync2("git", ["worktree", "remove", worktreePath, "--force"], {
|
|
104
|
+
cwd: repoRoot,
|
|
105
|
+
encoding: "utf8",
|
|
106
|
+
timeout: GIT_TIMEOUT_MS,
|
|
107
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
108
|
+
windowsHide: true
|
|
109
|
+
});
|
|
110
|
+
} catch (error) {
|
|
111
|
+
const stderr = typeof error.stderr === "string" ? error.stderr : "";
|
|
112
|
+
throw new Error(`git worktree remove failed: ${stderr.trim() || error.message}`);
|
|
113
|
+
}
|
|
114
|
+
return { success: true, removedPath: worktreePath };
|
|
115
|
+
}
|
|
116
|
+
async function listWorktrees(repoRoot) {
|
|
117
|
+
const { stdout } = await execFileAsync2("git", ["worktree", "list", "--porcelain"], {
|
|
118
|
+
cwd: repoRoot,
|
|
119
|
+
encoding: "utf8",
|
|
120
|
+
timeout: GIT_TIMEOUT_MS,
|
|
121
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
122
|
+
windowsHide: true
|
|
123
|
+
});
|
|
124
|
+
return parseWorktreeListOutput(stdout);
|
|
125
|
+
}
|
|
126
|
+
function parseWorktreeListOutput(output) {
|
|
127
|
+
const entries = [];
|
|
128
|
+
const blocks = output.trim().split(/\n\n+/);
|
|
129
|
+
for (const block of blocks) {
|
|
130
|
+
if (!block.trim()) continue;
|
|
131
|
+
const lines = block.trim().split("\n");
|
|
132
|
+
const entry = { path: "", head: "", branch: null, bare: false };
|
|
133
|
+
for (const line of lines) {
|
|
134
|
+
if (line.startsWith("worktree ")) {
|
|
135
|
+
entry.path = line.slice("worktree ".length).trim();
|
|
136
|
+
} else if (line.startsWith("HEAD ")) {
|
|
137
|
+
entry.head = line.slice("HEAD ".length).trim();
|
|
138
|
+
} else if (line.startsWith("branch ")) {
|
|
139
|
+
const ref = line.slice("branch ".length).trim();
|
|
140
|
+
entry.branch = ref.replace(/^refs\/heads\//, "");
|
|
141
|
+
} else if (line === "bare") {
|
|
142
|
+
entry.bare = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (entry.path) {
|
|
146
|
+
entries.push(entry);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return entries;
|
|
150
|
+
}
|
|
151
|
+
async function pruneWorktrees(repoRoot) {
|
|
152
|
+
try {
|
|
153
|
+
await execFileAsync2("git", ["worktree", "prune"], {
|
|
154
|
+
cwd: repoRoot,
|
|
155
|
+
encoding: "utf8",
|
|
156
|
+
timeout: GIT_TIMEOUT_MS,
|
|
157
|
+
windowsHide: true
|
|
158
|
+
});
|
|
159
|
+
} catch {
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
var execFileAsync2, WORKTREE_DIR_NAME, GIT_TIMEOUT_MS, GIT_MAX_BUFFER;
|
|
163
|
+
var init_git_worktree = __esm({
|
|
164
|
+
"src/git/git-worktree.ts"() {
|
|
165
|
+
"use strict";
|
|
166
|
+
execFileAsync2 = promisify2(execFile2);
|
|
167
|
+
WORKTREE_DIR_NAME = ".adhdev-worktrees";
|
|
168
|
+
GIT_TIMEOUT_MS = 3e4;
|
|
169
|
+
GIT_MAX_BUFFER = 4 * 1024 * 1024;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
44
173
|
// src/config/config.ts
|
|
45
174
|
var config_exports = {};
|
|
46
175
|
__export(config_exports, {
|
|
@@ -56,8 +185,8 @@ __export(config_exports, {
|
|
|
56
185
|
updateConfig: () => updateConfig
|
|
57
186
|
});
|
|
58
187
|
import { homedir } from "os";
|
|
59
|
-
import { join } from "path";
|
|
60
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
|
|
188
|
+
import { join as join2 } from "path";
|
|
189
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
|
|
61
190
|
import { randomUUID } from "crypto";
|
|
62
191
|
function resolveProviderSourceMode(providerSourceMode, legacyDisableUpstream) {
|
|
63
192
|
if (providerSourceMode === "normal" || providerSourceMode === "no-upstream") {
|
|
@@ -151,18 +280,18 @@ function ensureMachineId(config) {
|
|
|
151
280
|
};
|
|
152
281
|
}
|
|
153
282
|
function getConfigDir() {
|
|
154
|
-
const dir =
|
|
155
|
-
if (!
|
|
283
|
+
const dir = join2(homedir(), ".adhdev");
|
|
284
|
+
if (!existsSync2(dir)) {
|
|
156
285
|
mkdirSync(dir, { recursive: true });
|
|
157
286
|
}
|
|
158
287
|
return dir;
|
|
159
288
|
}
|
|
160
289
|
function getConfigPath() {
|
|
161
|
-
return
|
|
290
|
+
return join2(getConfigDir(), "config.json");
|
|
162
291
|
}
|
|
163
292
|
function migrateStateToStateFile(raw) {
|
|
164
|
-
const statePath =
|
|
165
|
-
if (
|
|
293
|
+
const statePath = join2(getConfigDir(), "state.json");
|
|
294
|
+
if (existsSync2(statePath)) return;
|
|
166
295
|
const recentActivity = Array.isArray(raw.recentActivity) ? raw.recentActivity : [];
|
|
167
296
|
const savedProviderSessions = Array.isArray(raw.savedProviderSessions) ? raw.savedProviderSessions : [];
|
|
168
297
|
const legacySessionReads = isPlainObject(raw.recentSessionReads) ? raw.recentSessionReads : {};
|
|
@@ -186,7 +315,7 @@ function migrateStateToStateFile(raw) {
|
|
|
186
315
|
}
|
|
187
316
|
function loadConfig() {
|
|
188
317
|
const configPath = getConfigPath();
|
|
189
|
-
if (!
|
|
318
|
+
if (!existsSync2(configPath)) {
|
|
190
319
|
const initialized = ensureMachineId({ ...DEFAULT_CONFIG });
|
|
191
320
|
try {
|
|
192
321
|
saveConfig(initialized.config);
|
|
@@ -217,7 +346,7 @@ function saveConfig(config) {
|
|
|
217
346
|
const configPath = getConfigPath();
|
|
218
347
|
const dir = getConfigDir();
|
|
219
348
|
const normalized = normalizeConfig(config);
|
|
220
|
-
if (!
|
|
349
|
+
if (!existsSync2(dir)) {
|
|
221
350
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
222
351
|
}
|
|
223
352
|
writeFileSync(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
@@ -295,17 +424,17 @@ __export(mesh_config_exports, {
|
|
|
295
424
|
updateMesh: () => updateMesh,
|
|
296
425
|
updateNode: () => updateNode
|
|
297
426
|
});
|
|
298
|
-
import { existsSync as
|
|
299
|
-
import { join as
|
|
427
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
428
|
+
import { join as join4 } from "path";
|
|
300
429
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
301
430
|
function getMeshConfigPath() {
|
|
302
|
-
return
|
|
431
|
+
return join4(getConfigDir(), "meshes.json");
|
|
303
432
|
}
|
|
304
433
|
function loadMeshConfig() {
|
|
305
|
-
const
|
|
306
|
-
if (!
|
|
434
|
+
const path27 = getMeshConfigPath();
|
|
435
|
+
if (!existsSync4(path27)) return { meshes: [] };
|
|
307
436
|
try {
|
|
308
|
-
const raw = JSON.parse(readFileSync2(
|
|
437
|
+
const raw = JSON.parse(readFileSync2(path27, "utf-8"));
|
|
309
438
|
if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
|
|
310
439
|
return raw;
|
|
311
440
|
} catch {
|
|
@@ -313,16 +442,16 @@ function loadMeshConfig() {
|
|
|
313
442
|
}
|
|
314
443
|
}
|
|
315
444
|
function saveMeshConfig(config) {
|
|
316
|
-
const
|
|
317
|
-
writeFileSync2(
|
|
445
|
+
const path27 = getMeshConfigPath();
|
|
446
|
+
writeFileSync2(path27, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
|
|
318
447
|
}
|
|
319
448
|
function normalizeRepoIdentity(remoteUrl) {
|
|
320
449
|
let identity = remoteUrl.trim();
|
|
321
450
|
if (identity.startsWith("http://") || identity.startsWith("https://")) {
|
|
322
451
|
try {
|
|
323
452
|
const url = new URL(identity);
|
|
324
|
-
const
|
|
325
|
-
return `${url.hostname}/${
|
|
453
|
+
const path27 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
|
|
454
|
+
return `${url.hostname}/${path27}`;
|
|
326
455
|
} catch {
|
|
327
456
|
}
|
|
328
457
|
}
|
|
@@ -330,6 +459,18 @@ function normalizeRepoIdentity(remoteUrl) {
|
|
|
330
459
|
if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
|
|
331
460
|
return identity;
|
|
332
461
|
}
|
|
462
|
+
function mergeMeshPolicy(base, patch) {
|
|
463
|
+
const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
|
|
464
|
+
if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
|
|
465
|
+
policy.dirtyWorkspaceBehavior = "warn";
|
|
466
|
+
}
|
|
467
|
+
const maxParallelTasks = Number(policy.maxParallelTasks);
|
|
468
|
+
policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
|
|
469
|
+
if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
|
|
470
|
+
policy.sessionCleanupOnNodeRemove = "preserve";
|
|
471
|
+
}
|
|
472
|
+
return policy;
|
|
473
|
+
}
|
|
333
474
|
function listMeshes() {
|
|
334
475
|
return loadMeshConfig().meshes;
|
|
335
476
|
}
|
|
@@ -353,7 +494,7 @@ function createMesh(opts) {
|
|
|
353
494
|
repoIdentity,
|
|
354
495
|
repoRemoteUrl: opts.repoRemoteUrl,
|
|
355
496
|
defaultBranch: opts.defaultBranch,
|
|
356
|
-
policy:
|
|
497
|
+
policy: mergeMeshPolicy(void 0, opts.policy),
|
|
357
498
|
coordinator: opts.coordinator || {},
|
|
358
499
|
nodes: [],
|
|
359
500
|
createdAt: now,
|
|
@@ -369,7 +510,7 @@ function updateMesh(meshId, opts) {
|
|
|
369
510
|
if (!mesh) return void 0;
|
|
370
511
|
if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
|
|
371
512
|
if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
|
|
372
|
-
if (opts.policy) mesh.policy =
|
|
513
|
+
if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
|
|
373
514
|
if (opts.coordinator) mesh.coordinator = opts.coordinator;
|
|
374
515
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
375
516
|
saveMeshConfig(config);
|
|
@@ -397,9 +538,12 @@ function addNode(meshId, opts) {
|
|
|
397
538
|
id: `node_${randomUUID3().replace(/-/g, "")}`,
|
|
398
539
|
workspace: opts.workspace.trim(),
|
|
399
540
|
repoRoot: opts.repoRoot,
|
|
541
|
+
daemonId: opts.daemonId,
|
|
400
542
|
userOverrides: opts.userOverrides || {},
|
|
401
543
|
policy: opts.policy || {},
|
|
402
|
-
isLocalWorktree: opts.isLocalWorktree
|
|
544
|
+
isLocalWorktree: opts.isLocalWorktree,
|
|
545
|
+
worktreeBranch: opts.worktreeBranch,
|
|
546
|
+
clonedFromNodeId: opts.clonedFromNodeId
|
|
403
547
|
};
|
|
404
548
|
mesh.nodes.push(node);
|
|
405
549
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -429,11 +573,13 @@ function updateNode(meshId, nodeId, opts) {
|
|
|
429
573
|
saveMeshConfig(config);
|
|
430
574
|
return node;
|
|
431
575
|
}
|
|
576
|
+
var SESSION_CLEANUP_MODES;
|
|
432
577
|
var init_mesh_config = __esm({
|
|
433
578
|
"src/config/mesh-config.ts"() {
|
|
434
579
|
"use strict";
|
|
435
580
|
init_config();
|
|
436
581
|
init_repo_mesh_types();
|
|
582
|
+
SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
|
|
437
583
|
}
|
|
438
584
|
});
|
|
439
585
|
|
|
@@ -443,7 +589,7 @@ __export(coordinator_prompt_exports, {
|
|
|
443
589
|
buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
|
|
444
590
|
});
|
|
445
591
|
function buildCoordinatorSystemPrompt(ctx) {
|
|
446
|
-
const { mesh, status, userInstruction } = ctx;
|
|
592
|
+
const { mesh, status, userInstruction, coordinatorCliType } = ctx;
|
|
447
593
|
const sections = [];
|
|
448
594
|
sections.push(`You are a **Repo Mesh Coordinator** \u2014 a technical team lead who orchestrates work across multiple agent sessions on a shared Git repository.
|
|
449
595
|
|
|
@@ -457,15 +603,15 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
457
603
|
} else {
|
|
458
604
|
sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
|
|
459
605
|
}
|
|
460
|
-
sections.push(buildPolicySection(mesh.policy));
|
|
606
|
+
sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
|
|
461
607
|
sections.push(TOOLS_SECTION);
|
|
462
608
|
sections.push(WORKFLOW_SECTION);
|
|
463
|
-
sections.push(
|
|
609
|
+
sections.push(buildRulesSection(coordinatorCliType));
|
|
464
610
|
if (userInstruction) {
|
|
465
611
|
sections.push(`## Additional Context
|
|
466
612
|
${userInstruction}`);
|
|
467
613
|
}
|
|
468
|
-
if (mesh.coordinator
|
|
614
|
+
if (mesh.coordinator?.systemPromptSuffix) {
|
|
469
615
|
sections.push(mesh.coordinator.systemPromptSuffix);
|
|
470
616
|
}
|
|
471
617
|
return sections.join("\n\n");
|
|
@@ -510,10 +656,29 @@ function buildPolicySection(policy) {
|
|
|
510
656
|
return `## Policy
|
|
511
657
|
${rules.join("\n")}`;
|
|
512
658
|
}
|
|
513
|
-
|
|
659
|
+
function buildRulesSection(coordinatorCliType) {
|
|
660
|
+
const coordinatorNote = coordinatorCliType ? `
|
|
661
|
+
- **Coordinator runtime is not a delegation default.** This coordinator is running as \`${coordinatorCliType}\`, but delegated node sessions must follow the user's requested provider, not the coordinator's own runtime.` : "";
|
|
662
|
+
return `## Rules
|
|
663
|
+
|
|
664
|
+
- **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
|
|
665
|
+
- **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
|
|
666
|
+
- **Respect explicit provider requests.** If the user names an agent/provider, pass the matching provider type to \`mesh_launch_session\`: Hermes \u2192 \`hermes-cli\`, Claude Code/Claude \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`. Never substitute \`claude-cli\` just because the coordinator itself is Claude Code.
|
|
667
|
+
- **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
|
|
668
|
+
- **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
|
|
669
|
+
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
|
|
670
|
+
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
671
|
+
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
672
|
+
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
673
|
+
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.
|
|
674
|
+
- **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
|
|
675
|
+
- **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
|
|
676
|
+
}
|
|
677
|
+
var TOOLS_SECTION, WORKFLOW_SECTION;
|
|
514
678
|
var init_coordinator_prompt = __esm({
|
|
515
679
|
"src/mesh/coordinator-prompt.ts"() {
|
|
516
680
|
"use strict";
|
|
681
|
+
init_repo_mesh_types();
|
|
517
682
|
TOOLS_SECTION = `## Available Tools
|
|
518
683
|
|
|
519
684
|
| Tool | Purpose |
|
|
@@ -525,36 +690,29 @@ var init_coordinator_prompt = __esm({
|
|
|
525
690
|
| \`mesh_read_chat\` | Read an agent's recent messages to check progress |
|
|
526
691
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
527
692
|
| \`mesh_checkpoint\` | Create a git checkpoint on a node |
|
|
528
|
-
| \`mesh_approve\` | Approve/reject a pending agent action
|
|
693
|
+
| \`mesh_approve\` | Approve/reject a pending agent action |
|
|
694
|
+
| \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
|
|
695
|
+
| \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |`;
|
|
529
696
|
WORKFLOW_SECTION = `## Orchestration Workflow
|
|
530
697
|
|
|
531
698
|
1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
|
|
532
699
|
2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
|
|
533
700
|
3. **Delegate** \u2014 For each task:
|
|
534
701
|
a. Pick the best node (consider: health, dirty state, current workload).
|
|
535
|
-
b. If
|
|
536
|
-
c.
|
|
702
|
+
b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
|
|
703
|
+
c. If no session exists, call \`mesh_launch_session\` to start one.
|
|
704
|
+
d. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
|
|
537
705
|
4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
|
|
538
706
|
5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
|
|
539
707
|
6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
|
|
540
|
-
7. **
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
- **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
|
|
544
|
-
- **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
|
|
545
|
-
- **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
|
|
546
|
-
- **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
|
|
547
|
-
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
|
|
548
|
-
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
549
|
-
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
550
|
-
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
551
|
-
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
|
|
708
|
+
7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
|
|
709
|
+
8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
|
|
552
710
|
}
|
|
553
711
|
});
|
|
554
712
|
|
|
555
713
|
// src/logging/logger.ts
|
|
556
714
|
import * as fs2 from "fs";
|
|
557
|
-
import * as
|
|
715
|
+
import * as path10 from "path";
|
|
558
716
|
import * as os4 from "os";
|
|
559
717
|
function setLogLevel(level) {
|
|
560
718
|
currentLevel = level;
|
|
@@ -570,13 +728,13 @@ function getDaemonLogDir() {
|
|
|
570
728
|
return LOG_DIR;
|
|
571
729
|
}
|
|
572
730
|
function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
|
|
573
|
-
return
|
|
731
|
+
return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
|
|
574
732
|
}
|
|
575
733
|
function checkDateRotation() {
|
|
576
734
|
const today = getDateStr();
|
|
577
735
|
if (today !== currentDate) {
|
|
578
736
|
currentDate = today;
|
|
579
|
-
currentLogFile =
|
|
737
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
580
738
|
cleanOldLogs();
|
|
581
739
|
}
|
|
582
740
|
}
|
|
@@ -590,7 +748,7 @@ function cleanOldLogs() {
|
|
|
590
748
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
591
749
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
592
750
|
try {
|
|
593
|
-
fs2.unlinkSync(
|
|
751
|
+
fs2.unlinkSync(path10.join(LOG_DIR, file));
|
|
594
752
|
} catch {
|
|
595
753
|
}
|
|
596
754
|
}
|
|
@@ -713,7 +871,7 @@ var init_logger = __esm({
|
|
|
713
871
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
714
872
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
715
873
|
currentLevel = "info";
|
|
716
|
-
LOG_DIR = process.platform === "win32" ?
|
|
874
|
+
LOG_DIR = process.platform === "win32" ? path10.join(process.env.LOCALAPPDATA || process.env.APPDATA || path10.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path10.join(os4.homedir(), "Library", "Logs", "adhdev") : path10.join(os4.homedir(), ".local", "share", "adhdev", "logs");
|
|
717
875
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
718
876
|
MAX_LOG_DAYS = 7;
|
|
719
877
|
try {
|
|
@@ -721,16 +879,16 @@ var init_logger = __esm({
|
|
|
721
879
|
} catch {
|
|
722
880
|
}
|
|
723
881
|
currentDate = getDateStr();
|
|
724
|
-
currentLogFile =
|
|
882
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
725
883
|
cleanOldLogs();
|
|
726
884
|
try {
|
|
727
|
-
const oldLog =
|
|
885
|
+
const oldLog = path10.join(LOG_DIR, "daemon.log");
|
|
728
886
|
if (fs2.existsSync(oldLog)) {
|
|
729
887
|
const stat2 = fs2.statSync(oldLog);
|
|
730
888
|
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
731
|
-
fs2.renameSync(oldLog,
|
|
889
|
+
fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
732
890
|
}
|
|
733
|
-
const oldLogBackup =
|
|
891
|
+
const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
|
|
734
892
|
if (fs2.existsSync(oldLogBackup)) {
|
|
735
893
|
fs2.unlinkSync(oldLogBackup);
|
|
736
894
|
}
|
|
@@ -762,7 +920,7 @@ var init_logger = __esm({
|
|
|
762
920
|
}
|
|
763
921
|
};
|
|
764
922
|
interceptorInstalled = false;
|
|
765
|
-
LOG_PATH =
|
|
923
|
+
LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
766
924
|
}
|
|
767
925
|
});
|
|
768
926
|
|
|
@@ -1171,7 +1329,7 @@ var init_pty_transport = __esm({
|
|
|
1171
1329
|
|
|
1172
1330
|
// src/cli-adapters/provider-cli-shared.ts
|
|
1173
1331
|
import * as os9 from "os";
|
|
1174
|
-
import * as
|
|
1332
|
+
import * as path14 from "path";
|
|
1175
1333
|
import { execSync as execSync3 } from "child_process";
|
|
1176
1334
|
function stripAnsi(str) {
|
|
1177
1335
|
return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
|
|
@@ -1236,9 +1394,9 @@ function buildCliScreenSnapshot(text) {
|
|
|
1236
1394
|
function findBinary(name) {
|
|
1237
1395
|
const trimmed = String(name || "").trim();
|
|
1238
1396
|
if (!trimmed) return trimmed;
|
|
1239
|
-
const expanded = trimmed.startsWith("~") ?
|
|
1240
|
-
if (
|
|
1241
|
-
return
|
|
1397
|
+
const expanded = trimmed.startsWith("~") ? path14.join(os9.homedir(), trimmed.slice(1)) : trimmed;
|
|
1398
|
+
if (path14.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
|
|
1399
|
+
return path14.isAbsolute(expanded) ? expanded : path14.resolve(expanded);
|
|
1242
1400
|
}
|
|
1243
1401
|
const isWin = os9.platform() === "win32";
|
|
1244
1402
|
try {
|
|
@@ -1254,7 +1412,7 @@ function findBinary(name) {
|
|
|
1254
1412
|
}
|
|
1255
1413
|
}
|
|
1256
1414
|
function isScriptBinary(binaryPath) {
|
|
1257
|
-
if (!
|
|
1415
|
+
if (!path14.isAbsolute(binaryPath)) return false;
|
|
1258
1416
|
try {
|
|
1259
1417
|
const fs16 = __require("fs");
|
|
1260
1418
|
const resolved = fs16.realpathSync(binaryPath);
|
|
@@ -1270,7 +1428,7 @@ function isScriptBinary(binaryPath) {
|
|
|
1270
1428
|
}
|
|
1271
1429
|
}
|
|
1272
1430
|
function looksLikeMachOOrElf(filePath) {
|
|
1273
|
-
if (!
|
|
1431
|
+
if (!path14.isAbsolute(filePath)) return false;
|
|
1274
1432
|
try {
|
|
1275
1433
|
const fs16 = __require("fs");
|
|
1276
1434
|
const resolved = fs16.realpathSync(filePath);
|
|
@@ -1484,10 +1642,10 @@ var init_provider_cli_config = __esm({
|
|
|
1484
1642
|
|
|
1485
1643
|
// src/cli-adapters/provider-cli-runtime.ts
|
|
1486
1644
|
import * as os10 from "os";
|
|
1487
|
-
import * as
|
|
1645
|
+
import * as path15 from "path";
|
|
1488
1646
|
import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from "@adhdev/session-host-core";
|
|
1489
1647
|
function resolveCliSpawnPlan(options) {
|
|
1490
|
-
const { provider, runtimeSettings, workingDir, extraArgs } = options;
|
|
1648
|
+
const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
|
|
1491
1649
|
const { spawn: spawnConfig } = provider;
|
|
1492
1650
|
const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
|
|
1493
1651
|
const binaryPath = findBinary(configuredCommand);
|
|
@@ -1495,9 +1653,9 @@ function resolveCliSpawnPlan(options) {
|
|
|
1495
1653
|
const allArgs = [...spawnConfig.args, ...extraArgs];
|
|
1496
1654
|
let shellCmd;
|
|
1497
1655
|
let shellArgs;
|
|
1498
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1656
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1499
1657
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
1500
|
-
const useShellWin = !!spawnConfig.shell || isCmdShim || !
|
|
1658
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
1501
1659
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
1502
1660
|
if (useShell) {
|
|
1503
1661
|
shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
|
|
@@ -1511,7 +1669,7 @@ function resolveCliSpawnPlan(options) {
|
|
|
1511
1669
|
shellCmd = binaryPath;
|
|
1512
1670
|
shellArgs = allArgs;
|
|
1513
1671
|
}
|
|
1514
|
-
const env = buildCliSpawnEnv(process.env, spawnConfig.env);
|
|
1672
|
+
const env = buildCliSpawnEnv(process.env, { ...spawnConfig.env || {}, ...extraEnv || {} });
|
|
1515
1673
|
env.TERMINAL_CWD = workingDir;
|
|
1516
1674
|
return {
|
|
1517
1675
|
binaryPath,
|
|
@@ -1610,8 +1768,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1610
1768
|
init_provider_cli_runtime();
|
|
1611
1769
|
init_provider_cli_shared();
|
|
1612
1770
|
ProviderCliAdapter = class _ProviderCliAdapter {
|
|
1613
|
-
constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
|
|
1771
|
+
constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
|
|
1614
1772
|
this.extraArgs = extraArgs;
|
|
1773
|
+
this.extraEnv = extraEnv;
|
|
1615
1774
|
this.provider = provider;
|
|
1616
1775
|
this.transportFactory = transportFactory;
|
|
1617
1776
|
this.cliType = provider.type;
|
|
@@ -1762,8 +1921,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1762
1921
|
const currentSnapshot = normalizeScreenSnapshot(screenText);
|
|
1763
1922
|
const lastSnapshot = this.lastScreenSnapshot;
|
|
1764
1923
|
if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
|
|
1765
|
-
const
|
|
1766
|
-
const
|
|
1924
|
+
const activeScreenPattern = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel|Enter to confirm\s*[·•-]\s*Esc to cancel|\b(?:MCP servers?|tool calls?)\b[^\n\r]{0,160}\brequire approval\b/i;
|
|
1925
|
+
const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
|
|
1926
|
+
const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
|
|
1767
1927
|
if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
|
|
1768
1928
|
if (currentSnapshot.length >= lastSnapshot.length) return screenText;
|
|
1769
1929
|
return `${screenText}
|
|
@@ -1926,7 +2086,8 @@ ${lastSnapshot}`;
|
|
|
1926
2086
|
provider: this.provider,
|
|
1927
2087
|
runtimeSettings: this.runtimeSettings,
|
|
1928
2088
|
workingDir: this.workingDir,
|
|
1929
|
-
extraArgs: this.extraArgs
|
|
2089
|
+
extraArgs: this.extraArgs,
|
|
2090
|
+
extraEnv: this.extraEnv
|
|
1930
2091
|
});
|
|
1931
2092
|
LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
1932
2093
|
this.resetTraceSession();
|
|
@@ -3124,9 +3285,8 @@ ${lastSnapshot}`;
|
|
|
3124
3285
|
};
|
|
3125
3286
|
this.recordTrace("submit_echo_missing", diagnostic);
|
|
3126
3287
|
if (this.requirePromptEchoBeforeSubmit) {
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
completion.rejectOnce(new Error(message));
|
|
3288
|
+
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending guarded submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
|
|
3289
|
+
this.submitSendKey(state, completion);
|
|
3130
3290
|
return;
|
|
3131
3291
|
}
|
|
3132
3292
|
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
|
|
@@ -3173,7 +3333,14 @@ ${lastSnapshot}`;
|
|
|
3173
3333
|
})() : null;
|
|
3174
3334
|
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
|
|
3175
3335
|
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
|
|
3176
|
-
|
|
3336
|
+
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
3337
|
+
const parsedHasActionableModal = Boolean(
|
|
3338
|
+
parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
|
|
3339
|
+
);
|
|
3340
|
+
const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
|
|
3341
|
+
if (!terminalLooksIdle) {
|
|
3342
|
+
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
3343
|
+
}
|
|
3177
3344
|
}
|
|
3178
3345
|
if (this.isWaitingForResponse && !allowInputDuringGeneration) {
|
|
3179
3346
|
if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
|
|
@@ -4547,6 +4714,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
|
4547
4714
|
"dirty_index_required",
|
|
4548
4715
|
"conflict",
|
|
4549
4716
|
"invalid_args",
|
|
4717
|
+
"nothing_to_commit",
|
|
4550
4718
|
"git_command_failed"
|
|
4551
4719
|
]);
|
|
4552
4720
|
function failure(reason, error) {
|
|
@@ -4791,7 +4959,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
|
4791
4959
|
} catch (err) {
|
|
4792
4960
|
const output = (err?.stdout || "") + (err?.stderr || "");
|
|
4793
4961
|
if (/nothing to commit/i.test(output)) {
|
|
4794
|
-
throw new GitCommandError("
|
|
4962
|
+
throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
|
|
4963
|
+
stdout: err?.stdout,
|
|
4964
|
+
stderr: err?.stderr
|
|
4965
|
+
});
|
|
4795
4966
|
}
|
|
4796
4967
|
throw err;
|
|
4797
4968
|
}
|
|
@@ -4983,20 +5154,23 @@ var TurnSnapshotTracker = class {
|
|
|
4983
5154
|
}
|
|
4984
5155
|
};
|
|
4985
5156
|
|
|
5157
|
+
// src/git/index.ts
|
|
5158
|
+
init_git_worktree();
|
|
5159
|
+
|
|
4986
5160
|
// src/index.ts
|
|
4987
5161
|
init_config();
|
|
4988
5162
|
|
|
4989
5163
|
// src/config/workspaces.ts
|
|
4990
5164
|
import * as fs from "fs";
|
|
4991
5165
|
import * as os from "os";
|
|
4992
|
-
import * as
|
|
5166
|
+
import * as path5 from "path";
|
|
4993
5167
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4994
5168
|
var MAX_WORKSPACES = 50;
|
|
4995
5169
|
function expandPath(p) {
|
|
4996
5170
|
const t = (p || "").trim();
|
|
4997
5171
|
if (!t) return "";
|
|
4998
|
-
if (t.startsWith("~")) return
|
|
4999
|
-
return
|
|
5172
|
+
if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5173
|
+
return path5.resolve(t);
|
|
5000
5174
|
}
|
|
5001
5175
|
function validateWorkspacePath(absPath) {
|
|
5002
5176
|
try {
|
|
@@ -5010,7 +5184,7 @@ function validateWorkspacePath(absPath) {
|
|
|
5010
5184
|
}
|
|
5011
5185
|
}
|
|
5012
5186
|
function defaultWorkspaceLabel(absPath) {
|
|
5013
|
-
const base =
|
|
5187
|
+
const base = path5.basename(absPath) || absPath;
|
|
5014
5188
|
return base;
|
|
5015
5189
|
}
|
|
5016
5190
|
function getDefaultWorkspacePath(config) {
|
|
@@ -5101,9 +5275,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
5101
5275
|
return getDefaultWorkspacePath(config) || void 0;
|
|
5102
5276
|
}
|
|
5103
5277
|
function findWorkspaceByPath(config, rawPath) {
|
|
5104
|
-
const abs =
|
|
5278
|
+
const abs = path5.resolve(expandPath(rawPath));
|
|
5105
5279
|
if (!abs) return void 0;
|
|
5106
|
-
return (config.workspaces || []).find((w) =>
|
|
5280
|
+
return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
|
|
5107
5281
|
}
|
|
5108
5282
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
5109
5283
|
const abs = expandPath(rawPath);
|
|
@@ -5119,7 +5293,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
5119
5293
|
const v = validateWorkspacePath(abs);
|
|
5120
5294
|
if (!v.ok) return { error: v.error };
|
|
5121
5295
|
const list = [...config.workspaces || []];
|
|
5122
|
-
if (list.some((w) =>
|
|
5296
|
+
if (list.some((w) => path5.resolve(w.path) === abs)) {
|
|
5123
5297
|
return { error: "Workspace already in list" };
|
|
5124
5298
|
}
|
|
5125
5299
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -5153,7 +5327,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
5153
5327
|
}
|
|
5154
5328
|
|
|
5155
5329
|
// src/config/recent-activity.ts
|
|
5156
|
-
import * as
|
|
5330
|
+
import * as path6 from "path";
|
|
5157
5331
|
|
|
5158
5332
|
// src/providers/summary-metadata.ts
|
|
5159
5333
|
function normalizeSummaryItem(item) {
|
|
@@ -5222,9 +5396,9 @@ var MAX_ACTIVITY = 30;
|
|
|
5222
5396
|
function normalizeWorkspace(workspace) {
|
|
5223
5397
|
if (!workspace) return "";
|
|
5224
5398
|
try {
|
|
5225
|
-
return
|
|
5399
|
+
return path6.resolve(expandPath(workspace));
|
|
5226
5400
|
} catch {
|
|
5227
|
-
return
|
|
5401
|
+
return path6.resolve(workspace);
|
|
5228
5402
|
}
|
|
5229
5403
|
}
|
|
5230
5404
|
function buildRecentActivityKey(entry) {
|
|
@@ -5392,14 +5566,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5392
5566
|
}
|
|
5393
5567
|
|
|
5394
5568
|
// src/config/saved-sessions.ts
|
|
5395
|
-
import * as
|
|
5569
|
+
import * as path7 from "path";
|
|
5396
5570
|
var MAX_SAVED_SESSIONS = 500;
|
|
5397
5571
|
function normalizeWorkspace2(workspace) {
|
|
5398
5572
|
if (!workspace) return "";
|
|
5399
5573
|
try {
|
|
5400
|
-
return
|
|
5574
|
+
return path7.resolve(expandPath(workspace));
|
|
5401
5575
|
} catch {
|
|
5402
|
-
return
|
|
5576
|
+
return path7.resolve(workspace);
|
|
5403
5577
|
}
|
|
5404
5578
|
}
|
|
5405
5579
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5505,8 +5679,8 @@ async function syncMeshes(transport) {
|
|
|
5505
5679
|
|
|
5506
5680
|
// src/config/state-store.ts
|
|
5507
5681
|
init_config();
|
|
5508
|
-
import { existsSync as
|
|
5509
|
-
import { join as
|
|
5682
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5683
|
+
import { join as join5 } from "path";
|
|
5510
5684
|
var DEFAULT_STATE = {
|
|
5511
5685
|
recentActivity: [],
|
|
5512
5686
|
savedProviderSessions: [],
|
|
@@ -5519,7 +5693,7 @@ function isPlainObject2(value) {
|
|
|
5519
5693
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5520
5694
|
}
|
|
5521
5695
|
function getStatePath() {
|
|
5522
|
-
return
|
|
5696
|
+
return join5(getConfigDir(), "state.json");
|
|
5523
5697
|
}
|
|
5524
5698
|
function normalizeState(raw) {
|
|
5525
5699
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -5555,7 +5729,7 @@ function normalizeState(raw) {
|
|
|
5555
5729
|
}
|
|
5556
5730
|
function loadState() {
|
|
5557
5731
|
const statePath = getStatePath();
|
|
5558
|
-
if (!
|
|
5732
|
+
if (!existsSync5(statePath)) {
|
|
5559
5733
|
return { ...DEFAULT_STATE };
|
|
5560
5734
|
}
|
|
5561
5735
|
try {
|
|
@@ -5576,9 +5750,9 @@ function resetState() {
|
|
|
5576
5750
|
|
|
5577
5751
|
// src/detection/ide-detector.ts
|
|
5578
5752
|
import { execSync } from "child_process";
|
|
5579
|
-
import { existsSync as
|
|
5753
|
+
import { existsSync as existsSync6 } from "fs";
|
|
5580
5754
|
import { platform, homedir as homedir3 } from "os";
|
|
5581
|
-
import * as
|
|
5755
|
+
import * as path8 from "path";
|
|
5582
5756
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5583
5757
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5584
5758
|
function registerIDEDefinition(def) {
|
|
@@ -5597,10 +5771,10 @@ function getMergedDefinitions() {
|
|
|
5597
5771
|
function findCliCommand(command) {
|
|
5598
5772
|
const trimmed = String(command || "").trim();
|
|
5599
5773
|
if (!trimmed) return null;
|
|
5600
|
-
if (
|
|
5601
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5602
|
-
const resolved =
|
|
5603
|
-
return
|
|
5774
|
+
if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
5775
|
+
const candidate = trimmed.startsWith("~") ? path8.join(homedir3(), trimmed.slice(1)) : trimmed;
|
|
5776
|
+
const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
|
|
5777
|
+
return existsSync6(resolved) ? resolved : null;
|
|
5604
5778
|
}
|
|
5605
5779
|
try {
|
|
5606
5780
|
const result = execSync(
|
|
@@ -5627,31 +5801,31 @@ function getIdeVersion(cliCommand) {
|
|
|
5627
5801
|
function checkPathExists(paths) {
|
|
5628
5802
|
const home = homedir3();
|
|
5629
5803
|
for (const p of paths) {
|
|
5630
|
-
const normalized = p.startsWith("~") ?
|
|
5804
|
+
const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
|
|
5631
5805
|
if (normalized.includes("*")) {
|
|
5632
5806
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5633
5807
|
const resolved = normalized.replace("*", username);
|
|
5634
|
-
if (
|
|
5808
|
+
if (existsSync6(resolved)) return resolved;
|
|
5635
5809
|
} else {
|
|
5636
|
-
if (
|
|
5810
|
+
if (existsSync6(normalized)) return normalized;
|
|
5637
5811
|
}
|
|
5638
5812
|
}
|
|
5639
5813
|
return null;
|
|
5640
5814
|
}
|
|
5641
5815
|
async function detectIDEs(providerLoader) {
|
|
5642
|
-
const
|
|
5816
|
+
const os22 = platform();
|
|
5643
5817
|
const results = [];
|
|
5644
5818
|
for (const def of getMergedDefinitions()) {
|
|
5645
5819
|
const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
|
|
5646
|
-
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[
|
|
5820
|
+
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
|
|
5647
5821
|
let resolvedCli = cliPath;
|
|
5648
|
-
if (!resolvedCli && appPath &&
|
|
5822
|
+
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
5649
5823
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
5650
|
-
if (
|
|
5824
|
+
if (existsSync6(bundledCli)) resolvedCli = bundledCli;
|
|
5651
5825
|
}
|
|
5652
|
-
if (!resolvedCli && appPath &&
|
|
5653
|
-
const { dirname:
|
|
5654
|
-
const appDir =
|
|
5826
|
+
if (!resolvedCli && appPath && os22 === "win32") {
|
|
5827
|
+
const { dirname: dirname9 } = await import("path");
|
|
5828
|
+
const appDir = dirname9(appPath);
|
|
5655
5829
|
const candidates = [
|
|
5656
5830
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
5657
5831
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -5660,13 +5834,13 @@ async function detectIDEs(providerLoader) {
|
|
|
5660
5834
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
5661
5835
|
];
|
|
5662
5836
|
for (const c of candidates) {
|
|
5663
|
-
if (
|
|
5837
|
+
if (existsSync6(c)) {
|
|
5664
5838
|
resolvedCli = c;
|
|
5665
5839
|
break;
|
|
5666
5840
|
}
|
|
5667
5841
|
}
|
|
5668
5842
|
}
|
|
5669
|
-
const installed =
|
|
5843
|
+
const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
|
|
5670
5844
|
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
5671
5845
|
results.push({
|
|
5672
5846
|
id: def.id,
|
|
@@ -5685,8 +5859,8 @@ async function detectIDEs(providerLoader) {
|
|
|
5685
5859
|
// src/detection/cli-detector.ts
|
|
5686
5860
|
import { exec } from "child_process";
|
|
5687
5861
|
import * as os2 from "os";
|
|
5688
|
-
import * as
|
|
5689
|
-
import { existsSync as
|
|
5862
|
+
import * as path9 from "path";
|
|
5863
|
+
import { existsSync as existsSync7 } from "fs";
|
|
5690
5864
|
function parseVersion(raw) {
|
|
5691
5865
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
5692
5866
|
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
@@ -5698,19 +5872,19 @@ function shellQuote(value) {
|
|
|
5698
5872
|
function expandHome(value) {
|
|
5699
5873
|
const trimmed = value.trim();
|
|
5700
5874
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5701
|
-
return
|
|
5875
|
+
return path9.join(os2.homedir(), trimmed.slice(1));
|
|
5702
5876
|
}
|
|
5703
5877
|
function isExplicitCommandPath(command) {
|
|
5704
5878
|
const trimmed = command.trim();
|
|
5705
|
-
return
|
|
5879
|
+
return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5706
5880
|
}
|
|
5707
5881
|
function resolveCommandPath(command) {
|
|
5708
5882
|
const trimmed = command.trim();
|
|
5709
5883
|
if (!trimmed) return null;
|
|
5710
5884
|
if (isExplicitCommandPath(trimmed)) {
|
|
5711
5885
|
const expanded = expandHome(trimmed);
|
|
5712
|
-
const candidate =
|
|
5713
|
-
return
|
|
5886
|
+
const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
|
|
5887
|
+
return existsSync7(candidate) ? candidate : null;
|
|
5714
5888
|
}
|
|
5715
5889
|
return null;
|
|
5716
5890
|
}
|
|
@@ -7978,9 +8152,9 @@ ${cleanBody}`;
|
|
|
7978
8152
|
|
|
7979
8153
|
// src/config/chat-history.ts
|
|
7980
8154
|
import * as fs3 from "fs";
|
|
7981
|
-
import * as
|
|
8155
|
+
import * as path11 from "path";
|
|
7982
8156
|
import * as os5 from "os";
|
|
7983
|
-
var HISTORY_DIR =
|
|
8157
|
+
var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
|
|
7984
8158
|
var RETAIN_DAYS = 30;
|
|
7985
8159
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
7986
8160
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -8143,7 +8317,7 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
8143
8317
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
8144
8318
|
return new Map(files.map((file) => {
|
|
8145
8319
|
try {
|
|
8146
|
-
const stat2 = fs3.statSync(
|
|
8320
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8147
8321
|
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
8148
8322
|
} catch {
|
|
8149
8323
|
return [file, `${file}:missing`];
|
|
@@ -8154,7 +8328,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
8154
8328
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
8155
8329
|
}
|
|
8156
8330
|
function getSavedHistoryIndexFilePath(dir) {
|
|
8157
|
-
return
|
|
8331
|
+
return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
8158
8332
|
}
|
|
8159
8333
|
function getSavedHistoryIndexLockPath(dir) {
|
|
8160
8334
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -8256,7 +8430,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
8256
8430
|
}
|
|
8257
8431
|
for (const file of Array.from(currentEntries.keys())) {
|
|
8258
8432
|
if (incomingFiles.has(file)) continue;
|
|
8259
|
-
if (!fs3.existsSync(
|
|
8433
|
+
if (!fs3.existsSync(path11.join(dir, file))) {
|
|
8260
8434
|
currentEntries.delete(file);
|
|
8261
8435
|
}
|
|
8262
8436
|
}
|
|
@@ -8282,7 +8456,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8282
8456
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8283
8457
|
const files = listHistoryFiles(dir);
|
|
8284
8458
|
for (const file of files) {
|
|
8285
|
-
const stat2 = fs3.statSync(
|
|
8459
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8286
8460
|
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
8287
8461
|
}
|
|
8288
8462
|
return false;
|
|
@@ -8292,14 +8466,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8292
8466
|
}
|
|
8293
8467
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
8294
8468
|
try {
|
|
8295
|
-
const stat2 = fs3.statSync(
|
|
8469
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8296
8470
|
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
8297
8471
|
} catch {
|
|
8298
8472
|
return `${file}:missing`;
|
|
8299
8473
|
}
|
|
8300
8474
|
}
|
|
8301
8475
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
8302
|
-
const filePath =
|
|
8476
|
+
const filePath = path11.join(dir, file);
|
|
8303
8477
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
8304
8478
|
const currentEntry = entries.get(file) || null;
|
|
8305
8479
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -8372,7 +8546,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
8372
8546
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
8373
8547
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
8374
8548
|
if (!historySessionId) return null;
|
|
8375
|
-
const filePath =
|
|
8549
|
+
const filePath = path11.join(dir, file);
|
|
8376
8550
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8377
8551
|
const lines = content.split("\n").filter(Boolean);
|
|
8378
8552
|
let messageCount = 0;
|
|
@@ -8459,7 +8633,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
8459
8633
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
8460
8634
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
8461
8635
|
for (const file of files.slice().sort()) {
|
|
8462
|
-
const filePath =
|
|
8636
|
+
const filePath = path11.join(dir, file);
|
|
8463
8637
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
8464
8638
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
8465
8639
|
const persisted = persistedEntries.get(file);
|
|
@@ -8579,12 +8753,12 @@ var ChatHistoryWriter = class {
|
|
|
8579
8753
|
});
|
|
8580
8754
|
}
|
|
8581
8755
|
if (newMessages.length === 0) return;
|
|
8582
|
-
const dir =
|
|
8756
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8583
8757
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8584
8758
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8585
8759
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
8586
8760
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
8587
|
-
const filePath =
|
|
8761
|
+
const filePath = path11.join(dir, fileName);
|
|
8588
8762
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
8589
8763
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
8590
8764
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -8675,11 +8849,11 @@ var ChatHistoryWriter = class {
|
|
|
8675
8849
|
const ws = String(workspace || "").trim();
|
|
8676
8850
|
if (!id || !ws) return;
|
|
8677
8851
|
try {
|
|
8678
|
-
const dir =
|
|
8852
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8679
8853
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8680
8854
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8681
8855
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
8682
|
-
const filePath =
|
|
8856
|
+
const filePath = path11.join(dir, fileName);
|
|
8683
8857
|
const record = {
|
|
8684
8858
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8685
8859
|
receivedAt: Date.now(),
|
|
@@ -8725,14 +8899,14 @@ var ChatHistoryWriter = class {
|
|
|
8725
8899
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8726
8900
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8727
8901
|
}
|
|
8728
|
-
const dir =
|
|
8902
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8729
8903
|
if (!fs3.existsSync(dir)) return;
|
|
8730
8904
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8731
8905
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8732
8906
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8733
8907
|
for (const file of files) {
|
|
8734
|
-
const sourcePath =
|
|
8735
|
-
const targetPath =
|
|
8908
|
+
const sourcePath = path11.join(dir, file);
|
|
8909
|
+
const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8736
8910
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8737
8911
|
const rewritten = sourceLines.map((line) => {
|
|
8738
8912
|
try {
|
|
@@ -8766,13 +8940,13 @@ var ChatHistoryWriter = class {
|
|
|
8766
8940
|
const sessionId = String(historySessionId || "").trim();
|
|
8767
8941
|
if (!sessionId) return;
|
|
8768
8942
|
try {
|
|
8769
|
-
const dir =
|
|
8943
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8770
8944
|
if (!fs3.existsSync(dir)) return;
|
|
8771
8945
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8772
8946
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8773
8947
|
const seen = /* @__PURE__ */ new Set();
|
|
8774
8948
|
for (const file of files) {
|
|
8775
|
-
const filePath =
|
|
8949
|
+
const filePath = path11.join(dir, file);
|
|
8776
8950
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8777
8951
|
const next = [];
|
|
8778
8952
|
for (const line of lines) {
|
|
@@ -8826,11 +9000,11 @@ var ChatHistoryWriter = class {
|
|
|
8826
9000
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
8827
9001
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
8828
9002
|
for (const dir of agentDirs) {
|
|
8829
|
-
const dirPath =
|
|
9003
|
+
const dirPath = path11.join(HISTORY_DIR, dir.name);
|
|
8830
9004
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
8831
9005
|
let removedAny = false;
|
|
8832
9006
|
for (const file of files) {
|
|
8833
|
-
const filePath =
|
|
9007
|
+
const filePath = path11.join(dirPath, file);
|
|
8834
9008
|
const stat2 = fs3.statSync(filePath);
|
|
8835
9009
|
if (stat2.mtimeMs < cutoff) {
|
|
8836
9010
|
fs3.unlinkSync(filePath);
|
|
@@ -8880,13 +9054,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8880
9054
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8881
9055
|
try {
|
|
8882
9056
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8883
|
-
const dir =
|
|
9057
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8884
9058
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
8885
9059
|
const files = listHistoryFiles(dir, historySessionId);
|
|
8886
9060
|
const allMessages = [];
|
|
8887
9061
|
const seen = /* @__PURE__ */ new Set();
|
|
8888
9062
|
for (const file of files) {
|
|
8889
|
-
const filePath =
|
|
9063
|
+
const filePath = path11.join(dir, file);
|
|
8890
9064
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8891
9065
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
8892
9066
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8910,7 +9084,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8910
9084
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
8911
9085
|
try {
|
|
8912
9086
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8913
|
-
const dir =
|
|
9087
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8914
9088
|
if (!fs3.existsSync(dir)) {
|
|
8915
9089
|
savedHistorySessionCache.delete(sanitized);
|
|
8916
9090
|
return { sessions: [], hasMore: false };
|
|
@@ -8971,11 +9145,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8971
9145
|
}
|
|
8972
9146
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8973
9147
|
try {
|
|
8974
|
-
const dir =
|
|
9148
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8975
9149
|
if (!fs3.existsSync(dir)) return null;
|
|
8976
9150
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
8977
9151
|
for (const file of files) {
|
|
8978
|
-
const lines = fs3.readFileSync(
|
|
9152
|
+
const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
8979
9153
|
for (const line of lines) {
|
|
8980
9154
|
try {
|
|
8981
9155
|
const parsed = JSON.parse(line);
|
|
@@ -8995,16 +9169,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
8995
9169
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
8996
9170
|
if (records.length === 0) return false;
|
|
8997
9171
|
try {
|
|
8998
|
-
const dir =
|
|
9172
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8999
9173
|
fs3.mkdirSync(dir, { recursive: true });
|
|
9000
9174
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
9001
9175
|
for (const file of fs3.readdirSync(dir)) {
|
|
9002
9176
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
9003
|
-
fs3.unlinkSync(
|
|
9177
|
+
fs3.unlinkSync(path11.join(dir, file));
|
|
9004
9178
|
}
|
|
9005
9179
|
}
|
|
9006
9180
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
9007
|
-
const filePath =
|
|
9181
|
+
const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
9008
9182
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
9009
9183
|
`, "utf-8");
|
|
9010
9184
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -10999,6 +11173,14 @@ function getActiveChatOptions(profile) {
|
|
|
10999
11173
|
if (profile === "full") return {};
|
|
11000
11174
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
11001
11175
|
}
|
|
11176
|
+
function resolveSessionStatus(activeChat, providerStatus) {
|
|
11177
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
11178
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
11179
|
+
if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
|
|
11180
|
+
if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
|
|
11181
|
+
if (topLevelStatus !== "idle") return topLevelStatus;
|
|
11182
|
+
return chatStatus;
|
|
11183
|
+
}
|
|
11002
11184
|
function shouldIncludeSessionControls(profile) {
|
|
11003
11185
|
return profile !== "live";
|
|
11004
11186
|
}
|
|
@@ -11077,9 +11259,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11077
11259
|
providerName: state.name,
|
|
11078
11260
|
kind: "workspace",
|
|
11079
11261
|
transport: "cdp-page",
|
|
11080
|
-
status:
|
|
11081
|
-
activeModal: activeChat?.activeModal || null
|
|
11082
|
-
}),
|
|
11262
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11083
11263
|
title,
|
|
11084
11264
|
workspace,
|
|
11085
11265
|
...git && { git },
|
|
@@ -11114,9 +11294,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11114
11294
|
providerSessionId: ext.providerSessionId,
|
|
11115
11295
|
kind: "agent",
|
|
11116
11296
|
transport: "cdp-webview",
|
|
11117
|
-
status:
|
|
11118
|
-
activeModal: activeChat?.activeModal || null
|
|
11119
|
-
}),
|
|
11297
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
11120
11298
|
title: activeChat?.title || ext.name,
|
|
11121
11299
|
workspace,
|
|
11122
11300
|
...git && { git },
|
|
@@ -11166,9 +11344,7 @@ function buildCliSession(state, options) {
|
|
|
11166
11344
|
providerSessionId: state.providerSessionId,
|
|
11167
11345
|
kind: "agent",
|
|
11168
11346
|
transport: "pty",
|
|
11169
|
-
status:
|
|
11170
|
-
activeModal: activeChat?.activeModal || null
|
|
11171
|
-
}),
|
|
11347
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11172
11348
|
title: activeChat?.title || state.name,
|
|
11173
11349
|
workspace,
|
|
11174
11350
|
...git && { git },
|
|
@@ -11216,9 +11392,7 @@ function buildAcpSession(state, options) {
|
|
|
11216
11392
|
providerName: state.name,
|
|
11217
11393
|
kind: "agent",
|
|
11218
11394
|
transport: "acp",
|
|
11219
|
-
status:
|
|
11220
|
-
activeModal: activeChat?.activeModal || null
|
|
11221
|
-
}),
|
|
11395
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11222
11396
|
title: activeChat?.title || state.name,
|
|
11223
11397
|
workspace,
|
|
11224
11398
|
...git && { git },
|
|
@@ -11341,7 +11515,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
11341
11515
|
// src/commands/chat-commands.ts
|
|
11342
11516
|
import * as fs4 from "fs";
|
|
11343
11517
|
import * as os6 from "os";
|
|
11344
|
-
import * as
|
|
11518
|
+
import * as path12 from "path";
|
|
11345
11519
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
11346
11520
|
|
|
11347
11521
|
// src/providers/provider-input-support.ts
|
|
@@ -11544,6 +11718,7 @@ function buildSessionModalDeliverySignature(payload) {
|
|
|
11544
11718
|
// src/commands/chat-commands.ts
|
|
11545
11719
|
var RECENT_SEND_WINDOW_MS = 1200;
|
|
11546
11720
|
var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
|
|
11721
|
+
var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
|
|
11547
11722
|
var recentSendByTarget = /* @__PURE__ */ new Map();
|
|
11548
11723
|
function getCurrentProviderType(h, fallback = "") {
|
|
11549
11724
|
return h.currentSession?.providerType || h.currentProviderType || fallback;
|
|
@@ -11596,6 +11771,16 @@ function buildSendInputSignature(input) {
|
|
|
11596
11771
|
function getSendChatInputEnvelope(args) {
|
|
11597
11772
|
return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
|
|
11598
11773
|
}
|
|
11774
|
+
function sleep(ms) {
|
|
11775
|
+
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
11776
|
+
}
|
|
11777
|
+
async function waitOnceForFreshHermesCliStart(adapter, log) {
|
|
11778
|
+
if (adapter.cliType !== "hermes-cli") return;
|
|
11779
|
+
const status = typeof adapter.getStatus === "function" ? adapter.getStatus()?.status : void 0;
|
|
11780
|
+
if (status !== "starting") return;
|
|
11781
|
+
log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
|
|
11782
|
+
await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
|
|
11783
|
+
}
|
|
11599
11784
|
function getHistorySessionId(h, args) {
|
|
11600
11785
|
const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
|
|
11601
11786
|
if (explicit) return explicit;
|
|
@@ -11704,6 +11889,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
11704
11889
|
return raw;
|
|
11705
11890
|
}
|
|
11706
11891
|
}
|
|
11892
|
+
function isGeneratingLikeStatus(status) {
|
|
11893
|
+
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
11894
|
+
}
|
|
11895
|
+
function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
11896
|
+
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
11897
|
+
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
11898
|
+
const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
|
|
11899
|
+
if (adapterRawStatus !== "idle") return false;
|
|
11900
|
+
if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
|
|
11901
|
+
return true;
|
|
11902
|
+
}
|
|
11903
|
+
function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
11904
|
+
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
11905
|
+
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
11906
|
+
}
|
|
11907
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
11908
|
+
if (status !== "idle") return messages;
|
|
11909
|
+
return messages.map((message) => {
|
|
11910
|
+
const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
11911
|
+
const hasStreamingMeta = meta?.streaming === true;
|
|
11912
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
11913
|
+
return {
|
|
11914
|
+
...message,
|
|
11915
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
11916
|
+
...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
|
|
11917
|
+
};
|
|
11918
|
+
});
|
|
11919
|
+
}
|
|
11707
11920
|
function buildReadChatCommandResult(payload, args) {
|
|
11708
11921
|
let validatedPayload;
|
|
11709
11922
|
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
@@ -11852,7 +12065,7 @@ function buildDebugBundleText(bundle) {
|
|
|
11852
12065
|
}
|
|
11853
12066
|
function getChatDebugBundleDir() {
|
|
11854
12067
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
11855
|
-
return override ||
|
|
12068
|
+
return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
11856
12069
|
}
|
|
11857
12070
|
function safeBundleIdSegment(value, fallback) {
|
|
11858
12071
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -11868,6 +12081,14 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
11868
12081
|
const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
|
|
11869
12082
|
const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
|
|
11870
12083
|
const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
|
|
12084
|
+
const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
|
|
12085
|
+
const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
|
|
12086
|
+
const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
|
|
12087
|
+
const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
|
|
12088
|
+
const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
|
|
12089
|
+
const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
|
|
12090
|
+
const cliStatus = typeof cli?.status === "string" ? cli.status : "";
|
|
12091
|
+
const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
|
|
11871
12092
|
return {
|
|
11872
12093
|
createdAt: bundle.createdAt,
|
|
11873
12094
|
targetSessionId: target.targetSessionId,
|
|
@@ -11876,8 +12097,22 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
11876
12097
|
readChatSuccess: readChat.success,
|
|
11877
12098
|
readChatStatus: readChat.status,
|
|
11878
12099
|
readChatTotalMessages: readChat.totalMessages,
|
|
12100
|
+
readChatReturnedMessages,
|
|
11879
12101
|
cliStatus: cli?.status,
|
|
12102
|
+
cliParsedStatus: cliParsedStatus || void 0,
|
|
11880
12103
|
cliMessageCount: cli?.messageCount,
|
|
12104
|
+
cliParsedMessageCount,
|
|
12105
|
+
cliPartialResponseChars: cliPartialResponse.length,
|
|
12106
|
+
parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
|
|
12107
|
+
parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
|
|
12108
|
+
readChatDebug: Object.keys(debugReadChat).length ? {
|
|
12109
|
+
adapterStatus: debugReadChat.adapterStatus,
|
|
12110
|
+
parsedStatus: debugReadChat.parsedStatus,
|
|
12111
|
+
returnedStatus: debugReadChat.returnedStatus,
|
|
12112
|
+
parsedMsgCount: debugReadChat.parsedMsgCount,
|
|
12113
|
+
returnedMsgCount: debugReadChat.returnedMsgCount,
|
|
12114
|
+
shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
|
|
12115
|
+
} : void 0,
|
|
11881
12116
|
hasFrontendSnapshot: !!frontend
|
|
11882
12117
|
};
|
|
11883
12118
|
}
|
|
@@ -11885,7 +12120,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
11885
12120
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
11886
12121
|
const dir = getChatDebugBundleDir();
|
|
11887
12122
|
fs4.mkdirSync(dir, { recursive: true });
|
|
11888
|
-
const savedPath =
|
|
12123
|
+
const savedPath = path12.join(dir, `${bundleId}.json`);
|
|
11889
12124
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
11890
12125
|
`;
|
|
11891
12126
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -12115,7 +12350,7 @@ async function handleChatHistory(h, args) {
|
|
|
12115
12350
|
}
|
|
12116
12351
|
}
|
|
12117
12352
|
async function handleReadChat(h, args) {
|
|
12118
|
-
const provider = h.getProvider(args?.agentType);
|
|
12353
|
+
const provider = h.getProvider(args?.agentType || args?.providerType);
|
|
12119
12354
|
const transport = getTargetTransport(h, provider);
|
|
12120
12355
|
const historySessionId = getHistorySessionId(h, args);
|
|
12121
12356
|
const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
|
|
@@ -12142,10 +12377,13 @@ async function handleReadChat(h, args) {
|
|
|
12142
12377
|
const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
12143
12378
|
const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
12144
12379
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
12145
|
-
const returnedStatus = parsedRecord.status
|
|
12146
|
-
|
|
12380
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
12381
|
+
const runtimeMessageMerger = getTargetInstance(h, args);
|
|
12382
|
+
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
|
|
12383
|
+
const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
|
|
12384
|
+
LOG.debug("Command", `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord.status || "")} parsedMsgCount=${parsedRecord.messages.length} returnedMsgCount=${returnedMessages.length}`);
|
|
12147
12385
|
return buildReadChatCommandResult({
|
|
12148
|
-
messages:
|
|
12386
|
+
messages: returnedMessages,
|
|
12149
12387
|
status: returnedStatus,
|
|
12150
12388
|
activeModal,
|
|
12151
12389
|
debugReadChat: {
|
|
@@ -12156,7 +12394,7 @@ async function handleReadChat(h, args) {
|
|
|
12156
12394
|
returnedStatus: String(returnedStatus || ""),
|
|
12157
12395
|
shouldPreferAdapterMessages: false,
|
|
12158
12396
|
parsedMsgCount: parsedRecord.messages.length,
|
|
12159
|
-
returnedMsgCount:
|
|
12397
|
+
returnedMsgCount: returnedMessages.length
|
|
12160
12398
|
},
|
|
12161
12399
|
...title ? { title } : {},
|
|
12162
12400
|
...providerSessionId ? { providerSessionId } : {},
|
|
@@ -12402,6 +12640,7 @@ async function handleSendChat(h, args) {
|
|
|
12402
12640
|
try {
|
|
12403
12641
|
assertTextOnlyInput(provider, input);
|
|
12404
12642
|
if (!text) return { success: false, error: "text required for PTY send" };
|
|
12643
|
+
await waitOnceForFreshHermesCliStart(adapter, _log);
|
|
12405
12644
|
await adapter.sendMessage(text);
|
|
12406
12645
|
return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
|
|
12407
12646
|
} catch (e) {
|
|
@@ -12901,9 +13140,17 @@ async function handleResolveAction(h, args) {
|
|
|
12901
13140
|
const targetState = targetInstance?.getState?.();
|
|
12902
13141
|
const surfacedModal = targetState?.activeChat?.activeModal && Array.isArray(targetState.activeChat.activeModal.buttons) && targetState.activeChat.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? targetState.activeChat.activeModal : null;
|
|
12903
13142
|
const statusModal = status?.activeModal && Array.isArray(status.activeModal.buttons) && status.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? status.activeModal : null;
|
|
12904
|
-
const
|
|
12905
|
-
|
|
12906
|
-
|
|
13143
|
+
const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
|
|
13144
|
+
try {
|
|
13145
|
+
return parseMaybeJson(adapter.getScriptParsedStatus());
|
|
13146
|
+
} catch {
|
|
13147
|
+
return null;
|
|
13148
|
+
}
|
|
13149
|
+
})() : null;
|
|
13150
|
+
const parsedModal = parsedStatus?.status === "waiting_approval" && parsedStatus?.activeModal && Array.isArray(parsedStatus.activeModal.buttons) && parsedStatus.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? parsedStatus.activeModal : null;
|
|
13151
|
+
const effectiveModal = statusModal || surfacedModal || parsedModal;
|
|
13152
|
+
const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
|
|
13153
|
+
LOG.info("Command", `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || "")} rawStatus=${String(status?.status || "")} effectiveStatus=${String(effectiveStatus || "")} statusModal=${statusModal ? "yes" : "no"} surfacedModal=${surfacedModal ? "yes" : "no"} parsedModal=${parsedModal ? "yes" : "no"} instance=${targetInstance ? "yes" : "no"}`);
|
|
12907
13154
|
if (!effectiveModal) {
|
|
12908
13155
|
return { success: false, error: "Not in approval state" };
|
|
12909
13156
|
}
|
|
@@ -13029,7 +13276,7 @@ async function handleResolveAction(h, args) {
|
|
|
13029
13276
|
|
|
13030
13277
|
// src/commands/cdp-commands.ts
|
|
13031
13278
|
import * as fs5 from "fs";
|
|
13032
|
-
import * as
|
|
13279
|
+
import * as path13 from "path";
|
|
13033
13280
|
import * as os7 from "os";
|
|
13034
13281
|
var KEY_TO_VK = {
|
|
13035
13282
|
Backspace: 8,
|
|
@@ -13286,25 +13533,25 @@ function resolveSafePath(requestedPath) {
|
|
|
13286
13533
|
const inputPath = rawPath || ".";
|
|
13287
13534
|
const home = os7.homedir();
|
|
13288
13535
|
if (inputPath.startsWith("~")) {
|
|
13289
|
-
return
|
|
13536
|
+
return path13.resolve(path13.join(home, inputPath.slice(1)));
|
|
13290
13537
|
}
|
|
13291
13538
|
if (process.platform === "win32") {
|
|
13292
13539
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
13293
|
-
if (
|
|
13294
|
-
return
|
|
13540
|
+
if (path13.win32.isAbsolute(normalized)) {
|
|
13541
|
+
return path13.win32.normalize(normalized);
|
|
13295
13542
|
}
|
|
13296
|
-
return
|
|
13543
|
+
return path13.win32.resolve(normalized);
|
|
13297
13544
|
}
|
|
13298
|
-
if (
|
|
13299
|
-
return
|
|
13545
|
+
if (path13.isAbsolute(inputPath)) {
|
|
13546
|
+
return path13.normalize(inputPath);
|
|
13300
13547
|
}
|
|
13301
|
-
return
|
|
13548
|
+
return path13.resolve(inputPath);
|
|
13302
13549
|
}
|
|
13303
13550
|
function listDirectoryEntriesSafe(dirPath) {
|
|
13304
13551
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
13305
13552
|
const files = [];
|
|
13306
13553
|
for (const entry of entries) {
|
|
13307
|
-
const entryPath =
|
|
13554
|
+
const entryPath = path13.join(dirPath, entry.name);
|
|
13308
13555
|
try {
|
|
13309
13556
|
if (entry.isDirectory()) {
|
|
13310
13557
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -13358,7 +13605,7 @@ async function handleFileRead(h, args) {
|
|
|
13358
13605
|
async function handleFileWrite(h, args) {
|
|
13359
13606
|
try {
|
|
13360
13607
|
const filePath = resolveSafePath(args?.path);
|
|
13361
|
-
fs5.mkdirSync(
|
|
13608
|
+
fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
13362
13609
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
13363
13610
|
return { success: true, path: filePath };
|
|
13364
13611
|
} catch (e) {
|
|
@@ -14142,9 +14389,11 @@ var DaemonCommandHandler = class {
|
|
|
14142
14389
|
}
|
|
14143
14390
|
const sessionLookupFailed = !!targetSessionId && !session;
|
|
14144
14391
|
const managerKey = this.extractIdeType(args, sessionLookupFailed);
|
|
14145
|
-
let providerType;
|
|
14392
|
+
let providerType = args?.agentType || args?.providerType;
|
|
14146
14393
|
if (!sessionLookupFailed) {
|
|
14147
|
-
providerType = session?.providerType ||
|
|
14394
|
+
providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
|
|
14395
|
+
} else if (!providerType) {
|
|
14396
|
+
providerType = this.inferProviderType(managerKey);
|
|
14148
14397
|
}
|
|
14149
14398
|
return { session, managerKey, providerType, sessionLookupFailed };
|
|
14150
14399
|
}
|
|
@@ -14224,7 +14473,8 @@ var DaemonCommandHandler = class {
|
|
|
14224
14473
|
"pty_resize",
|
|
14225
14474
|
"invoke_provider_script"
|
|
14226
14475
|
]);
|
|
14227
|
-
|
|
14476
|
+
const allowsInactiveReadChatFallback = cmd === "read_chat" && !!this._currentRoute.providerType && (typeof args?.providerSessionId === "string" && args.providerSessionId.trim().length > 0 || typeof args?.historySessionId === "string" && args.historySessionId.trim().length > 0);
|
|
14477
|
+
if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
|
|
14228
14478
|
const result2 = {
|
|
14229
14479
|
success: false,
|
|
14230
14480
|
error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
|
|
@@ -14478,16 +14728,16 @@ var DaemonCommandHandler = class {
|
|
|
14478
14728
|
// src/commands/cli-manager.ts
|
|
14479
14729
|
init_provider_cli_adapter();
|
|
14480
14730
|
import * as os13 from "os";
|
|
14481
|
-
import * as
|
|
14731
|
+
import * as path17 from "path";
|
|
14482
14732
|
import * as crypto4 from "crypto";
|
|
14483
|
-
import { existsSync as
|
|
14733
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
14484
14734
|
import { execFileSync } from "child_process";
|
|
14485
14735
|
import chalk from "chalk";
|
|
14486
14736
|
init_config();
|
|
14487
14737
|
|
|
14488
14738
|
// src/providers/cli-provider-instance.ts
|
|
14489
14739
|
import * as os12 from "os";
|
|
14490
|
-
import * as
|
|
14740
|
+
import * as path16 from "path";
|
|
14491
14741
|
import * as crypto3 from "crypto";
|
|
14492
14742
|
import * as fs6 from "fs";
|
|
14493
14743
|
import { createRequire } from "module";
|
|
@@ -14546,7 +14796,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
14546
14796
|
var CachedDatabaseSync = null;
|
|
14547
14797
|
function getDatabaseSync() {
|
|
14548
14798
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
14549
|
-
const requireFn = typeof __require === "function" ? __require : createRequire(
|
|
14799
|
+
const requireFn = typeof __require === "function" ? __require : createRequire(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
14550
14800
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
14551
14801
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
14552
14802
|
if (!CachedDatabaseSync) {
|
|
@@ -14599,7 +14849,7 @@ var CliProviderInstance = class {
|
|
|
14599
14849
|
this.providerSessionId = options?.providerSessionId;
|
|
14600
14850
|
this.launchMode = options?.launchMode || "new";
|
|
14601
14851
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
14602
|
-
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
|
|
14852
|
+
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
14603
14853
|
this.monitor = new StatusMonitor();
|
|
14604
14854
|
this.historyWriter = new ChatHistoryWriter();
|
|
14605
14855
|
}
|
|
@@ -15076,7 +15326,19 @@ var CliProviderInstance = class {
|
|
|
15076
15326
|
}
|
|
15077
15327
|
}
|
|
15078
15328
|
pushEvent(event) {
|
|
15079
|
-
|
|
15329
|
+
const enrichedEvent = {
|
|
15330
|
+
...event,
|
|
15331
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
|
|
15332
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
|
|
15333
|
+
providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
|
|
15334
|
+
workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
|
|
15335
|
+
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
15336
|
+
};
|
|
15337
|
+
if (this.context?.emitProviderEvent) {
|
|
15338
|
+
this.context.emitProviderEvent(enrichedEvent);
|
|
15339
|
+
return;
|
|
15340
|
+
}
|
|
15341
|
+
this.events.push(enrichedEvent);
|
|
15080
15342
|
}
|
|
15081
15343
|
flushEvents() {
|
|
15082
15344
|
const events = [...this.events];
|
|
@@ -15283,12 +15545,29 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15283
15545
|
);
|
|
15284
15546
|
}
|
|
15285
15547
|
}
|
|
15548
|
+
mergeRuntimeChatMessages(parsedMessages) {
|
|
15549
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
15550
|
+
}
|
|
15286
15551
|
mergeConversationMessages(parsedMessages) {
|
|
15287
15552
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15553
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
15554
|
+
message,
|
|
15555
|
+
index,
|
|
15556
|
+
source: "parsed"
|
|
15557
|
+
}));
|
|
15558
|
+
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
15559
|
+
message: entry.message,
|
|
15560
|
+
index: parsedMessages.length + index,
|
|
15561
|
+
source: "runtime"
|
|
15562
|
+
}));
|
|
15563
|
+
const getTime = (message) => {
|
|
15564
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
15565
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
15566
|
+
};
|
|
15567
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
15568
|
+
const aTime = getTime(a.message);
|
|
15569
|
+
const bTime = getTime(b.message);
|
|
15570
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
15292
15571
|
return a.index - b.index;
|
|
15293
15572
|
}).map((entry) => entry.message));
|
|
15294
15573
|
}
|
|
@@ -16617,17 +16896,17 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
16617
16896
|
// src/commands/cli-manager.ts
|
|
16618
16897
|
function isExplicitCommand(command) {
|
|
16619
16898
|
const trimmed = command.trim();
|
|
16620
|
-
return
|
|
16899
|
+
return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
16621
16900
|
}
|
|
16622
16901
|
function expandExecutable(command) {
|
|
16623
16902
|
const trimmed = command.trim();
|
|
16624
|
-
return trimmed.startsWith("~") ?
|
|
16903
|
+
return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
16625
16904
|
}
|
|
16626
16905
|
function commandExists(command) {
|
|
16627
16906
|
const trimmed = command.trim();
|
|
16628
16907
|
if (!trimmed) return false;
|
|
16629
16908
|
if (isExplicitCommand(trimmed)) {
|
|
16630
|
-
return
|
|
16909
|
+
return existsSync12(expandExecutable(trimmed));
|
|
16631
16910
|
}
|
|
16632
16911
|
try {
|
|
16633
16912
|
execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -16645,6 +16924,35 @@ function colorize(color, text) {
|
|
|
16645
16924
|
const fn = chalkApi?.[color];
|
|
16646
16925
|
return typeof fn === "function" ? fn(text) : text;
|
|
16647
16926
|
}
|
|
16927
|
+
var COORDINATOR_DELEGATED_ENV_UNSETS = {
|
|
16928
|
+
ADHDEV_INLINE_MESH: "",
|
|
16929
|
+
ADHDEV_MCP_TRANSPORT: "",
|
|
16930
|
+
ADHDEV_MESH_ID: "",
|
|
16931
|
+
HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
|
|
16932
|
+
};
|
|
16933
|
+
function hasCliArg(args, flag) {
|
|
16934
|
+
return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
16935
|
+
}
|
|
16936
|
+
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
16937
|
+
const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
16938
|
+
mkdirSync7(baseDir, { recursive: true });
|
|
16939
|
+
const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
16940
|
+
const filePath = path17.join(baseDir, `${workspaceHash}.json`);
|
|
16941
|
+
writeFileSync7(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
16942
|
+
return filePath;
|
|
16943
|
+
}
|
|
16944
|
+
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
16945
|
+
const cliType = String(input.cliType || "").trim();
|
|
16946
|
+
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
16947
|
+
const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
|
|
16948
|
+
if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
|
|
16949
|
+
cliArgs.unshift("--ignore-user-config");
|
|
16950
|
+
}
|
|
16951
|
+
if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
|
|
16952
|
+
cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
16953
|
+
}
|
|
16954
|
+
return { cliArgs, env };
|
|
16955
|
+
}
|
|
16648
16956
|
function isUuid(value) {
|
|
16649
16957
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
16650
16958
|
}
|
|
@@ -16815,7 +17123,7 @@ var DaemonCliManager = class {
|
|
|
16815
17123
|
attachExisting
|
|
16816
17124
|
}) || void 0;
|
|
16817
17125
|
}
|
|
16818
|
-
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
|
|
17126
|
+
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
|
|
16819
17127
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16820
17128
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
16821
17129
|
if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
|
|
@@ -16829,7 +17137,7 @@ var DaemonCliManager = class {
|
|
|
16829
17137
|
providerSessionId,
|
|
16830
17138
|
attachExisting
|
|
16831
17139
|
);
|
|
16832
|
-
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
|
|
17140
|
+
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
16833
17141
|
}
|
|
16834
17142
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
16835
17143
|
}
|
|
@@ -16902,7 +17210,7 @@ var DaemonCliManager = class {
|
|
|
16902
17210
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
16903
17211
|
const trimmed = (workingDir || "").trim();
|
|
16904
17212
|
if (!trimmed) throw new Error("working directory required");
|
|
16905
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17213
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
|
|
16906
17214
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16907
17215
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
16908
17216
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -17032,6 +17340,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17032
17340
|
{
|
|
17033
17341
|
providerSessionId: sessionBinding.providerSessionId,
|
|
17034
17342
|
launchMode: sessionBinding.launchMode,
|
|
17343
|
+
extraEnv: options?.extraEnv,
|
|
17035
17344
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
17036
17345
|
this.persistRecentActivity({
|
|
17037
17346
|
kind: "cli",
|
|
@@ -17052,7 +17361,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17052
17361
|
resolvedCliArgs,
|
|
17053
17362
|
key,
|
|
17054
17363
|
sessionBinding.providerSessionId,
|
|
17055
|
-
false
|
|
17364
|
+
false,
|
|
17365
|
+
options?.extraEnv
|
|
17056
17366
|
);
|
|
17057
17367
|
try {
|
|
17058
17368
|
await adapter.spawn();
|
|
@@ -17276,12 +17586,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17276
17586
|
const dir = resolved.path;
|
|
17277
17587
|
const launchSource = resolved.source;
|
|
17278
17588
|
if (!cliType) throw new Error("cliType required");
|
|
17589
|
+
const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
|
|
17590
|
+
const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
|
|
17591
|
+
cliType,
|
|
17592
|
+
workspace: dir,
|
|
17593
|
+
cliArgs: args?.cliArgs,
|
|
17594
|
+
env: args?.env
|
|
17595
|
+
}) : null;
|
|
17279
17596
|
const started = await this.startSession(
|
|
17280
17597
|
cliType,
|
|
17281
17598
|
dir,
|
|
17282
|
-
args?.cliArgs,
|
|
17599
|
+
delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
|
|
17283
17600
|
args?.initialModel,
|
|
17284
|
-
{
|
|
17601
|
+
{
|
|
17602
|
+
resumeSessionId: args?.resumeSessionId,
|
|
17603
|
+
settingsOverride,
|
|
17604
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
17605
|
+
}
|
|
17285
17606
|
);
|
|
17286
17607
|
return {
|
|
17287
17608
|
success: true,
|
|
@@ -17403,11 +17724,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17403
17724
|
import { execSync as execSync4, spawn as spawn2 } from "child_process";
|
|
17404
17725
|
import * as net from "net";
|
|
17405
17726
|
import * as os15 from "os";
|
|
17406
|
-
import * as
|
|
17727
|
+
import * as path19 from "path";
|
|
17407
17728
|
|
|
17408
17729
|
// src/providers/provider-loader.ts
|
|
17409
17730
|
import * as fs7 from "fs";
|
|
17410
|
-
import * as
|
|
17731
|
+
import * as path18 from "path";
|
|
17411
17732
|
import * as os14 from "os";
|
|
17412
17733
|
import * as chokidar from "chokidar";
|
|
17413
17734
|
init_logger();
|
|
@@ -17731,7 +18052,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17731
18052
|
try {
|
|
17732
18053
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
17733
18054
|
return ["ide", "extension", "cli", "acp"].some(
|
|
17734
|
-
(category) => fs7.existsSync(
|
|
18055
|
+
(category) => fs7.existsSync(path18.join(candidate, category))
|
|
17735
18056
|
);
|
|
17736
18057
|
} catch {
|
|
17737
18058
|
return false;
|
|
@@ -17739,20 +18060,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17739
18060
|
}
|
|
17740
18061
|
static hasProviderRootMarker(candidate) {
|
|
17741
18062
|
try {
|
|
17742
|
-
return fs7.existsSync(
|
|
18063
|
+
return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
17743
18064
|
} catch {
|
|
17744
18065
|
return false;
|
|
17745
18066
|
}
|
|
17746
18067
|
}
|
|
17747
18068
|
detectDefaultUserDir() {
|
|
17748
|
-
const fallback =
|
|
18069
|
+
const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17749
18070
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17750
18071
|
const visited = /* @__PURE__ */ new Set();
|
|
17751
18072
|
for (const start of this.probeStarts) {
|
|
17752
|
-
let current =
|
|
18073
|
+
let current = path18.resolve(start);
|
|
17753
18074
|
while (!visited.has(current)) {
|
|
17754
18075
|
visited.add(current);
|
|
17755
|
-
const siblingCandidate =
|
|
18076
|
+
const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17756
18077
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17757
18078
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17758
18079
|
if (envOptIn || hasMarker) {
|
|
@@ -17774,7 +18095,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17774
18095
|
return { path: siblingCandidate, source };
|
|
17775
18096
|
}
|
|
17776
18097
|
}
|
|
17777
|
-
const parent =
|
|
18098
|
+
const parent = path18.dirname(current);
|
|
17778
18099
|
if (parent === current) break;
|
|
17779
18100
|
current = parent;
|
|
17780
18101
|
}
|
|
@@ -17784,11 +18105,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17784
18105
|
constructor(options) {
|
|
17785
18106
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17786
18107
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17787
|
-
this.defaultProvidersDir =
|
|
18108
|
+
this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17788
18109
|
const detected = this.detectDefaultUserDir();
|
|
17789
18110
|
this.userDir = detected.path;
|
|
17790
18111
|
this.userDirSource = detected.source;
|
|
17791
|
-
this.upstreamDir =
|
|
18112
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17792
18113
|
this.disableUpstream = false;
|
|
17793
18114
|
this.applySourceConfig({
|
|
17794
18115
|
userDir: options?.userDir,
|
|
@@ -17847,7 +18168,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17847
18168
|
this.userDir = detected.path;
|
|
17848
18169
|
this.userDirSource = detected.source;
|
|
17849
18170
|
}
|
|
17850
|
-
this.upstreamDir =
|
|
18171
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17851
18172
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
17852
18173
|
if (this.explicitProviderDir) {
|
|
17853
18174
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -17861,7 +18182,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17861
18182
|
* Canonical provider directory shape for a given root.
|
|
17862
18183
|
*/
|
|
17863
18184
|
getProviderDir(root, category, type) {
|
|
17864
|
-
return
|
|
18185
|
+
return path18.join(root, category, type);
|
|
17865
18186
|
}
|
|
17866
18187
|
/**
|
|
17867
18188
|
* Canonical user override directory for a provider.
|
|
@@ -17888,7 +18209,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17888
18209
|
resolveProviderFile(type, ...segments) {
|
|
17889
18210
|
const dir = this.findProviderDirInternal(type);
|
|
17890
18211
|
if (!dir) return null;
|
|
17891
|
-
return
|
|
18212
|
+
return path18.join(dir, ...segments);
|
|
17892
18213
|
}
|
|
17893
18214
|
/**
|
|
17894
18215
|
* Load all providers (3-tier priority)
|
|
@@ -17927,7 +18248,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17927
18248
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
17928
18249
|
try {
|
|
17929
18250
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
17930
|
-
(d) => fs7.statSync(
|
|
18251
|
+
(d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
|
|
17931
18252
|
);
|
|
17932
18253
|
} catch {
|
|
17933
18254
|
return false;
|
|
@@ -18424,8 +18745,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18424
18745
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
18425
18746
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
18426
18747
|
if (providerDir) {
|
|
18427
|
-
const fullDir =
|
|
18428
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18748
|
+
const fullDir = path18.join(providerDir, entry.scriptDir);
|
|
18749
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18429
18750
|
}
|
|
18430
18751
|
matched = true;
|
|
18431
18752
|
}
|
|
@@ -18440,8 +18761,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18440
18761
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18441
18762
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
18442
18763
|
if (providerDir) {
|
|
18443
|
-
const fullDir =
|
|
18444
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18764
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18765
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18445
18766
|
}
|
|
18446
18767
|
}
|
|
18447
18768
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -18458,8 +18779,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18458
18779
|
resolved._resolvedScriptDir = dirOverride;
|
|
18459
18780
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
18460
18781
|
if (providerDir) {
|
|
18461
|
-
const fullDir =
|
|
18462
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18782
|
+
const fullDir = path18.join(providerDir, dirOverride);
|
|
18783
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18463
18784
|
}
|
|
18464
18785
|
}
|
|
18465
18786
|
} else if (override.scripts) {
|
|
@@ -18475,8 +18796,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18475
18796
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18476
18797
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
18477
18798
|
if (providerDir) {
|
|
18478
|
-
const fullDir =
|
|
18479
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18799
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18800
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18480
18801
|
}
|
|
18481
18802
|
}
|
|
18482
18803
|
}
|
|
@@ -18508,14 +18829,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18508
18829
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
18509
18830
|
return null;
|
|
18510
18831
|
}
|
|
18511
|
-
const dir =
|
|
18832
|
+
const dir = path18.join(providerDir, scriptDir);
|
|
18512
18833
|
if (!fs7.existsSync(dir)) {
|
|
18513
18834
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
18514
18835
|
return null;
|
|
18515
18836
|
}
|
|
18516
18837
|
const cached = this.scriptsCache.get(dir);
|
|
18517
18838
|
if (cached) return cached;
|
|
18518
|
-
const scriptsJs =
|
|
18839
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
18519
18840
|
if (fs7.existsSync(scriptsJs)) {
|
|
18520
18841
|
try {
|
|
18521
18842
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -18557,7 +18878,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18557
18878
|
return;
|
|
18558
18879
|
}
|
|
18559
18880
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
18560
|
-
this.log(`File changed: ${
|
|
18881
|
+
this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
|
|
18561
18882
|
this.reload();
|
|
18562
18883
|
}
|
|
18563
18884
|
};
|
|
@@ -18612,7 +18933,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18612
18933
|
}
|
|
18613
18934
|
const https = __require("https");
|
|
18614
18935
|
const { execSync: execSync7 } = __require("child_process");
|
|
18615
|
-
const metaPath =
|
|
18936
|
+
const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
18616
18937
|
let prevEtag = "";
|
|
18617
18938
|
let prevTimestamp = 0;
|
|
18618
18939
|
try {
|
|
@@ -18672,17 +18993,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18672
18993
|
return { updated: false };
|
|
18673
18994
|
}
|
|
18674
18995
|
this.log("Downloading latest providers from GitHub...");
|
|
18675
|
-
const tmpTar =
|
|
18676
|
-
const tmpExtract =
|
|
18996
|
+
const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
18997
|
+
const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
18677
18998
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
18678
18999
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
18679
19000
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
18680
19001
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
18681
19002
|
const rootDir = extracted.find(
|
|
18682
|
-
(d) => fs7.statSync(
|
|
19003
|
+
(d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
18683
19004
|
);
|
|
18684
19005
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
18685
|
-
const sourceDir =
|
|
19006
|
+
const sourceDir = path18.join(tmpExtract, rootDir);
|
|
18686
19007
|
const backupDir = this.upstreamDir + ".bak";
|
|
18687
19008
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
18688
19009
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -18757,8 +19078,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18757
19078
|
copyDirRecursive(src, dest) {
|
|
18758
19079
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18759
19080
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18760
|
-
const srcPath =
|
|
18761
|
-
const destPath =
|
|
19081
|
+
const srcPath = path18.join(src, entry.name);
|
|
19082
|
+
const destPath = path18.join(dest, entry.name);
|
|
18762
19083
|
if (entry.isDirectory()) {
|
|
18763
19084
|
this.copyDirRecursive(srcPath, destPath);
|
|
18764
19085
|
} else {
|
|
@@ -18769,7 +19090,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18769
19090
|
/** .meta.json save */
|
|
18770
19091
|
writeMeta(metaPath, etag, timestamp) {
|
|
18771
19092
|
try {
|
|
18772
|
-
fs7.mkdirSync(
|
|
19093
|
+
fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
|
|
18773
19094
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18774
19095
|
etag,
|
|
18775
19096
|
timestamp,
|
|
@@ -18786,7 +19107,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18786
19107
|
const scan = (d) => {
|
|
18787
19108
|
try {
|
|
18788
19109
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18789
|
-
if (entry.isDirectory()) scan(
|
|
19110
|
+
if (entry.isDirectory()) scan(path18.join(d, entry.name));
|
|
18790
19111
|
else if (entry.name === "provider.json") count++;
|
|
18791
19112
|
}
|
|
18792
19113
|
} catch {
|
|
@@ -19014,17 +19335,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19014
19335
|
for (const root of searchRoots) {
|
|
19015
19336
|
if (!fs7.existsSync(root)) continue;
|
|
19016
19337
|
const candidate = this.getProviderDir(root, cat, type);
|
|
19017
|
-
if (fs7.existsSync(
|
|
19018
|
-
const catDir =
|
|
19338
|
+
if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
|
|
19339
|
+
const catDir = path18.join(root, cat);
|
|
19019
19340
|
if (fs7.existsSync(catDir)) {
|
|
19020
19341
|
try {
|
|
19021
19342
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
19022
19343
|
if (!entry.isDirectory()) continue;
|
|
19023
|
-
const jsonPath =
|
|
19344
|
+
const jsonPath = path18.join(catDir, entry.name, "provider.json");
|
|
19024
19345
|
if (fs7.existsSync(jsonPath)) {
|
|
19025
19346
|
try {
|
|
19026
19347
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
19027
|
-
if (data.type === type) return
|
|
19348
|
+
if (data.type === type) return path18.join(catDir, entry.name);
|
|
19028
19349
|
} catch {
|
|
19029
19350
|
}
|
|
19030
19351
|
}
|
|
@@ -19041,7 +19362,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19041
19362
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
19042
19363
|
*/
|
|
19043
19364
|
buildScriptWrappersFromDir(dir) {
|
|
19044
|
-
const scriptsJs =
|
|
19365
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
19045
19366
|
if (fs7.existsSync(scriptsJs)) {
|
|
19046
19367
|
try {
|
|
19047
19368
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -19055,7 +19376,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19055
19376
|
for (const file of fs7.readdirSync(dir)) {
|
|
19056
19377
|
if (!file.endsWith(".js")) continue;
|
|
19057
19378
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
19058
|
-
const filePath =
|
|
19379
|
+
const filePath = path18.join(dir, file);
|
|
19059
19380
|
result[scriptName] = (...args) => {
|
|
19060
19381
|
try {
|
|
19061
19382
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -19115,7 +19436,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19115
19436
|
}
|
|
19116
19437
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
19117
19438
|
if (hasJson) {
|
|
19118
|
-
const jsonPath =
|
|
19439
|
+
const jsonPath = path18.join(d, "provider.json");
|
|
19119
19440
|
try {
|
|
19120
19441
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
19121
19442
|
const mod = JSON.parse(raw);
|
|
@@ -19136,7 +19457,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19136
19457
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
19137
19458
|
} else {
|
|
19138
19459
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
19139
|
-
const scriptsPath =
|
|
19460
|
+
const scriptsPath = path18.join(d, "scripts.js");
|
|
19140
19461
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
19141
19462
|
try {
|
|
19142
19463
|
delete __require.cache[__require.resolve(scriptsPath)];
|
|
@@ -19162,7 +19483,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19162
19483
|
if (!entry.isDirectory()) continue;
|
|
19163
19484
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
19164
19485
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
19165
|
-
scan(
|
|
19486
|
+
scan(path18.join(d, entry.name));
|
|
19166
19487
|
}
|
|
19167
19488
|
}
|
|
19168
19489
|
};
|
|
@@ -19487,8 +19808,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
19487
19808
|
const appNameMap = getMacAppIdentifiers();
|
|
19488
19809
|
const appName = appNameMap[ideId];
|
|
19489
19810
|
if (appName) {
|
|
19490
|
-
const storagePath =
|
|
19491
|
-
process.env.APPDATA ||
|
|
19811
|
+
const storagePath = path19.join(
|
|
19812
|
+
process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
|
|
19492
19813
|
appName,
|
|
19493
19814
|
"storage.json"
|
|
19494
19815
|
);
|
|
@@ -19677,9 +19998,9 @@ init_logger();
|
|
|
19677
19998
|
|
|
19678
19999
|
// src/logging/command-log.ts
|
|
19679
20000
|
import * as fs8 from "fs";
|
|
19680
|
-
import * as
|
|
20001
|
+
import * as path20 from "path";
|
|
19681
20002
|
import * as os16 from "os";
|
|
19682
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
20003
|
+
var LOG_DIR2 = process.platform === "win32" ? path20.join(process.env.LOCALAPPDATA || process.env.APPDATA || path20.join(os16.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path20.join(os16.homedir(), "Library", "Logs", "adhdev") : path20.join(os16.homedir(), ".local", "share", "adhdev", "logs");
|
|
19683
20004
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
19684
20005
|
var MAX_DAYS = 7;
|
|
19685
20006
|
try {
|
|
@@ -19717,13 +20038,13 @@ function getDateStr2() {
|
|
|
19717
20038
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19718
20039
|
}
|
|
19719
20040
|
var currentDate2 = getDateStr2();
|
|
19720
|
-
var currentFile =
|
|
20041
|
+
var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19721
20042
|
var writeCount2 = 0;
|
|
19722
20043
|
function checkRotation() {
|
|
19723
20044
|
const today = getDateStr2();
|
|
19724
20045
|
if (today !== currentDate2) {
|
|
19725
20046
|
currentDate2 = today;
|
|
19726
|
-
currentFile =
|
|
20047
|
+
currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19727
20048
|
cleanOldFiles();
|
|
19728
20049
|
}
|
|
19729
20050
|
}
|
|
@@ -19737,7 +20058,7 @@ function cleanOldFiles() {
|
|
|
19737
20058
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
19738
20059
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
19739
20060
|
try {
|
|
19740
|
-
fs8.unlinkSync(
|
|
20061
|
+
fs8.unlinkSync(path20.join(LOG_DIR2, file));
|
|
19741
20062
|
} catch {
|
|
19742
20063
|
}
|
|
19743
20064
|
}
|
|
@@ -19821,13 +20142,65 @@ cleanOldFiles();
|
|
|
19821
20142
|
|
|
19822
20143
|
// src/commands/router.ts
|
|
19823
20144
|
init_logger();
|
|
20145
|
+
import * as yaml from "js-yaml";
|
|
19824
20146
|
|
|
19825
20147
|
// src/commands/mesh-coordinator.ts
|
|
19826
|
-
import {
|
|
20148
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
20149
|
+
import { existsSync as existsSync15, readdirSync as readdirSync6, realpathSync as realpathSync2 } from "fs";
|
|
19827
20150
|
import { createRequire as createRequire2 } from "module";
|
|
19828
|
-
import
|
|
20151
|
+
import * as os17 from "os";
|
|
20152
|
+
import { dirname as dirname4, isAbsolute as isAbsolute10, join as join18, resolve as resolve13 } from "path";
|
|
19829
20153
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
19830
20154
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20155
|
+
var HERMES_CLI_TYPE = "hermes-cli";
|
|
20156
|
+
var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
|
|
20157
|
+
function isHermesProvider(provider, cliType) {
|
|
20158
|
+
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
20159
|
+
return type === HERMES_CLI_TYPE;
|
|
20160
|
+
}
|
|
20161
|
+
function resolveHermesMeshCoordinatorSetup(options) {
|
|
20162
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
20163
|
+
meshId: options.meshId,
|
|
20164
|
+
nodeExecutable: options.nodeExecutable,
|
|
20165
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath
|
|
20166
|
+
});
|
|
20167
|
+
if (!mcpServer) {
|
|
20168
|
+
return {
|
|
20169
|
+
kind: "unsupported",
|
|
20170
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20171
|
+
};
|
|
20172
|
+
}
|
|
20173
|
+
const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
|
|
20174
|
+
if (!configPath.trim()) {
|
|
20175
|
+
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20176
|
+
}
|
|
20177
|
+
return {
|
|
20178
|
+
kind: "auto_import",
|
|
20179
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20180
|
+
configPath,
|
|
20181
|
+
configFormat: "hermes_config_yaml",
|
|
20182
|
+
mcpServer
|
|
20183
|
+
};
|
|
20184
|
+
}
|
|
20185
|
+
function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
|
|
20186
|
+
return {
|
|
20187
|
+
kind: "manual",
|
|
20188
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20189
|
+
configFormat: "hermes_config_yaml",
|
|
20190
|
+
configPathCommand: HERMES_MCP_CONFIG_PATH,
|
|
20191
|
+
requiresRestart: true,
|
|
20192
|
+
instructions: "Hermes CLI does not auto-import repo-local .mcp.json. Add this MCP server to Hermes config under mcp_servers, then start a fresh Hermes session.",
|
|
20193
|
+
template: renderMeshCoordinatorTemplate(
|
|
20194
|
+
"mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
|
|
20195
|
+
{
|
|
20196
|
+
meshId,
|
|
20197
|
+
workspace,
|
|
20198
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20199
|
+
adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
|
|
20200
|
+
}
|
|
20201
|
+
)
|
|
20202
|
+
};
|
|
20203
|
+
}
|
|
19831
20204
|
function resolveMeshCoordinatorSetup(options) {
|
|
19832
20205
|
const { provider, meshId, workspace } = options;
|
|
19833
20206
|
const config = provider?.meshCoordinator;
|
|
@@ -19837,6 +20210,9 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19837
20210
|
reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
|
|
19838
20211
|
};
|
|
19839
20212
|
}
|
|
20213
|
+
if (isHermesProvider(provider, options.cliType)) {
|
|
20214
|
+
return resolveHermesMeshCoordinatorSetup(options);
|
|
20215
|
+
}
|
|
19840
20216
|
const mcpConfig = config.mcpConfig;
|
|
19841
20217
|
if (!mcpConfig || mcpConfig.mode === "none") {
|
|
19842
20218
|
return {
|
|
@@ -19846,8 +20222,8 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19846
20222
|
}
|
|
19847
20223
|
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
|
|
19848
20224
|
if (mcpConfig.mode === "auto_import") {
|
|
19849
|
-
const
|
|
19850
|
-
if (!
|
|
20225
|
+
const path27 = mcpConfig.path?.trim();
|
|
20226
|
+
if (!path27) {
|
|
19851
20227
|
return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
|
|
19852
20228
|
}
|
|
19853
20229
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
@@ -19858,13 +20234,13 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19858
20234
|
if (!mcpServer) {
|
|
19859
20235
|
return {
|
|
19860
20236
|
kind: "unsupported",
|
|
19861
|
-
reason: "Could not resolve the ADHDev MCP server entrypoint
|
|
20237
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
19862
20238
|
};
|
|
19863
20239
|
}
|
|
19864
20240
|
return {
|
|
19865
20241
|
kind: "auto_import",
|
|
19866
20242
|
serverName,
|
|
19867
|
-
configPath:
|
|
20243
|
+
configPath: resolveMcpConfigPath(path27, workspace),
|
|
19868
20244
|
configFormat: mcpConfig.format,
|
|
19869
20245
|
mcpServer
|
|
19870
20246
|
};
|
|
@@ -19898,14 +20274,85 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19898
20274
|
function renderMeshCoordinatorTemplate(template, values) {
|
|
19899
20275
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
|
|
19900
20276
|
}
|
|
20277
|
+
function resolveMcpConfigPath(configPath, workspace) {
|
|
20278
|
+
const trimmed = configPath.trim();
|
|
20279
|
+
if (trimmed === "~") return os17.homedir();
|
|
20280
|
+
if (trimmed.startsWith("~/")) return join18(os17.homedir(), trimmed.slice(2));
|
|
20281
|
+
if (isAbsolute10(trimmed)) return trimmed;
|
|
20282
|
+
return join18(workspace, trimmed);
|
|
20283
|
+
}
|
|
19901
20284
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
19902
20285
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
19903
20286
|
if (!entryPath) return null;
|
|
20287
|
+
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
|
|
20288
|
+
if (!nodeExecutable) return null;
|
|
19904
20289
|
return {
|
|
19905
|
-
command:
|
|
19906
|
-
args: [entryPath, "--repo-mesh", options.meshId]
|
|
20290
|
+
command: nodeExecutable,
|
|
20291
|
+
args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
|
|
19907
20292
|
};
|
|
19908
20293
|
}
|
|
20294
|
+
function resolveMcpNodeExecutable(explicitExecutable) {
|
|
20295
|
+
const explicit = explicitExecutable?.trim();
|
|
20296
|
+
if (explicit) return explicit;
|
|
20297
|
+
const candidates = [];
|
|
20298
|
+
const addCandidate = (candidate) => {
|
|
20299
|
+
const trimmed = candidate?.trim();
|
|
20300
|
+
if (!trimmed) return;
|
|
20301
|
+
const normalized = normalizeExistingPath(trimmed) || trimmed;
|
|
20302
|
+
if (!candidates.includes(normalized)) candidates.push(normalized);
|
|
20303
|
+
};
|
|
20304
|
+
addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
|
|
20305
|
+
addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
|
|
20306
|
+
addCandidate(process.env.npm_node_execpath);
|
|
20307
|
+
addNodeCandidatesFromPath(process.env.PATH, addCandidate);
|
|
20308
|
+
addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
|
|
20309
|
+
addCandidate("/opt/homebrew/bin/node");
|
|
20310
|
+
addCandidate("/usr/local/bin/node");
|
|
20311
|
+
addCandidate("/usr/bin/node");
|
|
20312
|
+
addCandidate(process.execPath);
|
|
20313
|
+
for (const candidate of candidates) {
|
|
20314
|
+
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
|
|
20315
|
+
}
|
|
20316
|
+
return null;
|
|
20317
|
+
}
|
|
20318
|
+
function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
20319
|
+
for (const entry of (pathValue || "").split(":")) {
|
|
20320
|
+
const dir = entry.trim();
|
|
20321
|
+
if (!dir) continue;
|
|
20322
|
+
addCandidate(join18(dir, "node"));
|
|
20323
|
+
}
|
|
20324
|
+
}
|
|
20325
|
+
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
20326
|
+
const versionsDir = join18(homeDir, ".nvm", "versions", "node");
|
|
20327
|
+
try {
|
|
20328
|
+
const versionDirs = readdirSync6(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
20329
|
+
for (const versionDir of versionDirs) {
|
|
20330
|
+
addCandidate(join18(versionsDir, versionDir, "bin", "node"));
|
|
20331
|
+
}
|
|
20332
|
+
} catch {
|
|
20333
|
+
}
|
|
20334
|
+
}
|
|
20335
|
+
function compareNodeVersionNamesDescending(a, b) {
|
|
20336
|
+
const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
20337
|
+
const left = parse(a);
|
|
20338
|
+
const right = parse(b);
|
|
20339
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
20340
|
+
const diff = (right[i] || 0) - (left[i] || 0);
|
|
20341
|
+
if (diff !== 0) return diff;
|
|
20342
|
+
}
|
|
20343
|
+
return b.localeCompare(a);
|
|
20344
|
+
}
|
|
20345
|
+
function nodeRuntimeSupportsWebSocket(nodeExecutable) {
|
|
20346
|
+
try {
|
|
20347
|
+
execFileSync2(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
|
|
20348
|
+
stdio: "ignore",
|
|
20349
|
+
timeout: 3e3
|
|
20350
|
+
});
|
|
20351
|
+
return true;
|
|
20352
|
+
} catch {
|
|
20353
|
+
return false;
|
|
20354
|
+
}
|
|
20355
|
+
}
|
|
19909
20356
|
function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
19910
20357
|
const explicit = explicitPath?.trim();
|
|
19911
20358
|
if (explicit) return normalizeExistingPath(explicit) || explicit;
|
|
@@ -19918,7 +20365,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19918
20365
|
const addPackagedCandidates = (baseFile) => {
|
|
19919
20366
|
if (!baseFile) return;
|
|
19920
20367
|
const realBase = normalizeExistingPath(baseFile) || baseFile;
|
|
19921
|
-
const dir =
|
|
20368
|
+
const dir = dirname4(realBase);
|
|
19922
20369
|
addCandidate(resolve13(dir, "../vendor/mcp-server/index.js"));
|
|
19923
20370
|
addCandidate(resolve13(dir, "../../vendor/mcp-server/index.js"));
|
|
19924
20371
|
addCandidate(resolve13(dir, "../../../vendor/mcp-server/index.js"));
|
|
@@ -19931,7 +20378,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19931
20378
|
if (normalized) return normalized;
|
|
19932
20379
|
}
|
|
19933
20380
|
try {
|
|
19934
|
-
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] :
|
|
20381
|
+
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join18(process.cwd(), "adhdev-daemon.js");
|
|
19935
20382
|
const req = createRequire2(requireBase);
|
|
19936
20383
|
const resolvedModule = req.resolve("@adhdev/mcp-server");
|
|
19937
20384
|
return normalizeExistingPath(resolvedModule) || resolvedModule;
|
|
@@ -19941,16 +20388,110 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19941
20388
|
}
|
|
19942
20389
|
function normalizeExistingPath(filePath) {
|
|
19943
20390
|
try {
|
|
19944
|
-
if (!
|
|
20391
|
+
if (!existsSync15(filePath)) return null;
|
|
19945
20392
|
return realpathSync2.native(filePath);
|
|
19946
20393
|
} catch {
|
|
19947
20394
|
return null;
|
|
19948
20395
|
}
|
|
19949
20396
|
}
|
|
19950
20397
|
|
|
20398
|
+
// src/mesh/mesh-events.ts
|
|
20399
|
+
init_mesh_config();
|
|
20400
|
+
init_logger();
|
|
20401
|
+
function readNonEmptyString(value) {
|
|
20402
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
20403
|
+
}
|
|
20404
|
+
function formatCompletionMetadata(event) {
|
|
20405
|
+
const parts = [
|
|
20406
|
+
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
20407
|
+
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
20408
|
+
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
20409
|
+
].filter(Boolean);
|
|
20410
|
+
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
20411
|
+
}
|
|
20412
|
+
function buildMeshSystemMessage(args) {
|
|
20413
|
+
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
20414
|
+
if (args.event === "agent:generating_completed") {
|
|
20415
|
+
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path; use mesh_read_chat once to review its final progress, but do not poll repeatedly.`;
|
|
20416
|
+
}
|
|
20417
|
+
if (args.event === "agent:waiting_approval") {
|
|
20418
|
+
return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
20419
|
+
}
|
|
20420
|
+
return "";
|
|
20421
|
+
}
|
|
20422
|
+
function injectMeshSystemMessage(components, args) {
|
|
20423
|
+
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
20424
|
+
const instState = inst.getState();
|
|
20425
|
+
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
20426
|
+
if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
|
|
20427
|
+
return true;
|
|
20428
|
+
});
|
|
20429
|
+
if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
|
|
20430
|
+
const messageText = buildMeshSystemMessage({
|
|
20431
|
+
event: args.event,
|
|
20432
|
+
nodeLabel: args.nodeLabel,
|
|
20433
|
+
metadataEvent: args.metadataEvent
|
|
20434
|
+
});
|
|
20435
|
+
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
20436
|
+
for (const coord of coordinatorInstances) {
|
|
20437
|
+
const coordState = coord.getState();
|
|
20438
|
+
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
20439
|
+
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
20440
|
+
}
|
|
20441
|
+
return { success: true, forwarded: coordinatorInstances.length };
|
|
20442
|
+
}
|
|
20443
|
+
function handleMeshForwardEvent(components, payload) {
|
|
20444
|
+
const eventName = readNonEmptyString(payload.event);
|
|
20445
|
+
if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
|
|
20446
|
+
return { success: false, error: "unsupported mesh event" };
|
|
20447
|
+
}
|
|
20448
|
+
const meshId = readNonEmptyString(payload.meshId);
|
|
20449
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
20450
|
+
const nodeId = readNonEmptyString(payload.nodeId);
|
|
20451
|
+
const workspace = readNonEmptyString(payload.workspace);
|
|
20452
|
+
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
20453
|
+
return injectMeshSystemMessage(components, {
|
|
20454
|
+
meshId,
|
|
20455
|
+
nodeLabel,
|
|
20456
|
+
event: eventName,
|
|
20457
|
+
metadataEvent: {
|
|
20458
|
+
targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
|
|
20459
|
+
providerType: readNonEmptyString(payload.providerType),
|
|
20460
|
+
providerSessionId: readNonEmptyString(payload.providerSessionId)
|
|
20461
|
+
}
|
|
20462
|
+
});
|
|
20463
|
+
}
|
|
20464
|
+
function setupMeshEventForwarding(components) {
|
|
20465
|
+
components.instanceManager.onEvent((event) => {
|
|
20466
|
+
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
20467
|
+
const instanceId = readNonEmptyString(event.instanceId);
|
|
20468
|
+
if (!instanceId) return;
|
|
20469
|
+
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
20470
|
+
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
20471
|
+
const state = sourceInstance.getState();
|
|
20472
|
+
const workspace = readNonEmptyString(state.workspace);
|
|
20473
|
+
if (!workspace) return;
|
|
20474
|
+
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
20475
|
+
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
20476
|
+
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
20477
|
+
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
20478
|
+
if (!meshId) return;
|
|
20479
|
+
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
20480
|
+
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
20481
|
+
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
20482
|
+
injectMeshSystemMessage(components, {
|
|
20483
|
+
meshId,
|
|
20484
|
+
sourceInstanceId: instanceId,
|
|
20485
|
+
nodeLabel,
|
|
20486
|
+
event: event.event,
|
|
20487
|
+
metadataEvent: event
|
|
20488
|
+
});
|
|
20489
|
+
});
|
|
20490
|
+
}
|
|
20491
|
+
|
|
19951
20492
|
// src/status/snapshot.ts
|
|
19952
20493
|
init_config();
|
|
19953
|
-
import * as
|
|
20494
|
+
import * as os18 from "os";
|
|
19954
20495
|
init_terminal_screen();
|
|
19955
20496
|
init_logger();
|
|
19956
20497
|
var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
|
|
@@ -20005,8 +20546,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20005
20546
|
}
|
|
20006
20547
|
function buildMachineInfo(profile = "full") {
|
|
20007
20548
|
const base = {
|
|
20008
|
-
hostname:
|
|
20009
|
-
platform:
|
|
20549
|
+
hostname: os18.hostname(),
|
|
20550
|
+
platform: os18.platform()
|
|
20010
20551
|
};
|
|
20011
20552
|
if (profile === "live") {
|
|
20012
20553
|
return base;
|
|
@@ -20015,23 +20556,23 @@ function buildMachineInfo(profile = "full") {
|
|
|
20015
20556
|
const memSnap2 = getHostMemorySnapshot();
|
|
20016
20557
|
return {
|
|
20017
20558
|
...base,
|
|
20018
|
-
arch:
|
|
20019
|
-
cpus:
|
|
20559
|
+
arch: os18.arch(),
|
|
20560
|
+
cpus: os18.cpus().length,
|
|
20020
20561
|
totalMem: memSnap2.totalMem,
|
|
20021
|
-
release:
|
|
20562
|
+
release: os18.release()
|
|
20022
20563
|
};
|
|
20023
20564
|
}
|
|
20024
20565
|
const memSnap = getHostMemorySnapshot();
|
|
20025
20566
|
return {
|
|
20026
20567
|
...base,
|
|
20027
|
-
arch:
|
|
20028
|
-
cpus:
|
|
20568
|
+
arch: os18.arch(),
|
|
20569
|
+
cpus: os18.cpus().length,
|
|
20029
20570
|
totalMem: memSnap.totalMem,
|
|
20030
20571
|
freeMem: memSnap.freeMem,
|
|
20031
20572
|
availableMem: memSnap.availableMem,
|
|
20032
|
-
loadavg:
|
|
20033
|
-
uptime:
|
|
20034
|
-
release:
|
|
20573
|
+
loadavg: os18.loadavg(),
|
|
20574
|
+
uptime: os18.uptime(),
|
|
20575
|
+
release: os18.release()
|
|
20035
20576
|
};
|
|
20036
20577
|
}
|
|
20037
20578
|
function parseMessageTime(value) {
|
|
@@ -20262,17 +20803,17 @@ function buildStatusSnapshot(options) {
|
|
|
20262
20803
|
}
|
|
20263
20804
|
|
|
20264
20805
|
// src/commands/upgrade-helper.ts
|
|
20265
|
-
import { execFileSync as
|
|
20806
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
20266
20807
|
import { spawn as spawn3 } from "child_process";
|
|
20267
20808
|
import * as fs9 from "fs";
|
|
20268
|
-
import * as
|
|
20269
|
-
import * as
|
|
20809
|
+
import * as os19 from "os";
|
|
20810
|
+
import * as path21 from "path";
|
|
20270
20811
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
20271
20812
|
function getUpgradeLogPath() {
|
|
20272
|
-
const home =
|
|
20273
|
-
const dir =
|
|
20813
|
+
const home = os19.homedir();
|
|
20814
|
+
const dir = path21.join(home, ".adhdev");
|
|
20274
20815
|
fs9.mkdirSync(dir, { recursive: true });
|
|
20275
|
-
return
|
|
20816
|
+
return path21.join(dir, "daemon-upgrade.log");
|
|
20276
20817
|
}
|
|
20277
20818
|
function appendUpgradeLog(message) {
|
|
20278
20819
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -20283,14 +20824,14 @@ function appendUpgradeLog(message) {
|
|
|
20283
20824
|
}
|
|
20284
20825
|
}
|
|
20285
20826
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
20286
|
-
const binDir =
|
|
20827
|
+
const binDir = path21.dirname(nodeExecutable);
|
|
20287
20828
|
if (platform10 === "win32") {
|
|
20288
|
-
const npmCliPath =
|
|
20829
|
+
const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
20289
20830
|
if (fs9.existsSync(npmCliPath)) {
|
|
20290
20831
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20291
20832
|
}
|
|
20292
20833
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
20293
|
-
const candidatePath =
|
|
20834
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20294
20835
|
if (fs9.existsSync(candidatePath)) {
|
|
20295
20836
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20296
20837
|
}
|
|
@@ -20298,7 +20839,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
20298
20839
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20299
20840
|
}
|
|
20300
20841
|
for (const candidate of ["npm"]) {
|
|
20301
|
-
const candidatePath =
|
|
20842
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20302
20843
|
if (fs9.existsSync(candidatePath)) {
|
|
20303
20844
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20304
20845
|
}
|
|
@@ -20315,13 +20856,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20315
20856
|
let currentDir = resolvedPath;
|
|
20316
20857
|
try {
|
|
20317
20858
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
20318
|
-
currentDir =
|
|
20859
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20319
20860
|
}
|
|
20320
20861
|
} catch {
|
|
20321
|
-
currentDir =
|
|
20862
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20322
20863
|
}
|
|
20323
20864
|
while (true) {
|
|
20324
|
-
const packageJsonPath =
|
|
20865
|
+
const packageJsonPath = path21.join(currentDir, "package.json");
|
|
20325
20866
|
try {
|
|
20326
20867
|
if (fs9.existsSync(packageJsonPath)) {
|
|
20327
20868
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -20332,7 +20873,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20332
20873
|
}
|
|
20333
20874
|
} catch {
|
|
20334
20875
|
}
|
|
20335
|
-
const parentDir =
|
|
20876
|
+
const parentDir = path21.dirname(currentDir);
|
|
20336
20877
|
if (parentDir === currentDir) {
|
|
20337
20878
|
return null;
|
|
20338
20879
|
}
|
|
@@ -20340,13 +20881,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20340
20881
|
}
|
|
20341
20882
|
}
|
|
20342
20883
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
20343
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
20344
|
-
if (
|
|
20884
|
+
const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
|
|
20885
|
+
if (path21.basename(nodeModulesDir) !== "node_modules") {
|
|
20345
20886
|
return null;
|
|
20346
20887
|
}
|
|
20347
|
-
const maybeLibDir =
|
|
20348
|
-
if (
|
|
20349
|
-
return
|
|
20888
|
+
const maybeLibDir = path21.dirname(nodeModulesDir);
|
|
20889
|
+
if (path21.basename(maybeLibDir) === "lib") {
|
|
20890
|
+
return path21.dirname(maybeLibDir);
|
|
20350
20891
|
}
|
|
20351
20892
|
return maybeLibDir;
|
|
20352
20893
|
}
|
|
@@ -20382,7 +20923,7 @@ function getNpmExecOptions(platform10 = process.platform) {
|
|
|
20382
20923
|
}
|
|
20383
20924
|
function execNpmCommandSync(args, options = {}, surface) {
|
|
20384
20925
|
const execOptions = surface?.execOptions || getNpmExecOptions();
|
|
20385
|
-
return
|
|
20926
|
+
return execFileSync3(
|
|
20386
20927
|
surface?.npmExecutable || "npm",
|
|
20387
20928
|
[...surface?.npmArgsPrefix || [], ...args],
|
|
20388
20929
|
{
|
|
@@ -20395,7 +20936,7 @@ function execNpmCommandSync(args, options = {}, surface) {
|
|
|
20395
20936
|
function killPid(pid) {
|
|
20396
20937
|
try {
|
|
20397
20938
|
if (process.platform === "win32") {
|
|
20398
|
-
|
|
20939
|
+
execFileSync3("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
|
|
20399
20940
|
} else {
|
|
20400
20941
|
process.kill(pid, "SIGTERM");
|
|
20401
20942
|
}
|
|
@@ -20407,7 +20948,7 @@ function killPid(pid) {
|
|
|
20407
20948
|
function getWindowsProcessCommandLine(pid) {
|
|
20408
20949
|
const pidFilter = `ProcessId=${pid}`;
|
|
20409
20950
|
try {
|
|
20410
|
-
const psOut =
|
|
20951
|
+
const psOut = execFileSync3("powershell.exe", [
|
|
20411
20952
|
"-NoProfile",
|
|
20412
20953
|
"-NonInteractive",
|
|
20413
20954
|
"-ExecutionPolicy",
|
|
@@ -20419,7 +20960,7 @@ function getWindowsProcessCommandLine(pid) {
|
|
|
20419
20960
|
} catch {
|
|
20420
20961
|
}
|
|
20421
20962
|
try {
|
|
20422
|
-
const wmicOut =
|
|
20963
|
+
const wmicOut = execFileSync3("wmic", [
|
|
20423
20964
|
"process",
|
|
20424
20965
|
"where",
|
|
20425
20966
|
pidFilter,
|
|
@@ -20435,7 +20976,7 @@ function getProcessCommandLine(pid) {
|
|
|
20435
20976
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
20436
20977
|
if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
|
|
20437
20978
|
try {
|
|
20438
|
-
const text =
|
|
20979
|
+
const text = execFileSync3("ps", ["-o", "command=", "-p", String(pid)], {
|
|
20439
20980
|
encoding: "utf8",
|
|
20440
20981
|
timeout: 3e3,
|
|
20441
20982
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -20461,7 +21002,7 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
20461
21002
|
}
|
|
20462
21003
|
}
|
|
20463
21004
|
function stopSessionHostProcesses(appName) {
|
|
20464
|
-
const pidFile =
|
|
21005
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
20465
21006
|
try {
|
|
20466
21007
|
if (fs9.existsSync(pidFile)) {
|
|
20467
21008
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -20478,7 +21019,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
20478
21019
|
}
|
|
20479
21020
|
}
|
|
20480
21021
|
function removeDaemonPidFile() {
|
|
20481
|
-
const pidFile =
|
|
21022
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
20482
21023
|
try {
|
|
20483
21024
|
fs9.unlinkSync(pidFile);
|
|
20484
21025
|
} catch {
|
|
@@ -20489,7 +21030,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20489
21030
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20490
21031
|
if (!npmRoot) return;
|
|
20491
21032
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20492
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
21033
|
+
const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
|
|
20493
21034
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
20494
21035
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
20495
21036
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -20497,25 +21038,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20497
21038
|
}
|
|
20498
21039
|
if (pkgName.startsWith("@")) {
|
|
20499
21040
|
const [scope, name] = pkgName.split("/");
|
|
20500
|
-
const scopeDir =
|
|
21041
|
+
const scopeDir = path21.join(npmRoot, scope);
|
|
20501
21042
|
if (!fs9.existsSync(scopeDir)) return;
|
|
20502
21043
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
20503
21044
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
20504
|
-
fs9.rmSync(
|
|
20505
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
21045
|
+
fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
|
|
21046
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
|
|
20506
21047
|
}
|
|
20507
21048
|
} else {
|
|
20508
21049
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
20509
21050
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
20510
|
-
fs9.rmSync(
|
|
20511
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
21051
|
+
fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
|
|
21052
|
+
appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
|
|
20512
21053
|
}
|
|
20513
21054
|
}
|
|
20514
21055
|
if (fs9.existsSync(binDir)) {
|
|
20515
21056
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
20516
21057
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
20517
|
-
fs9.rmSync(
|
|
20518
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
21058
|
+
fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
|
|
21059
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
|
|
20519
21060
|
}
|
|
20520
21061
|
}
|
|
20521
21062
|
}
|
|
@@ -20551,7 +21092,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
20551
21092
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
20552
21093
|
const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
|
|
20553
21094
|
appendUpgradeLog(`Installing ${spec}`);
|
|
20554
|
-
const installOutput =
|
|
21095
|
+
const installOutput = execFileSync3(
|
|
20555
21096
|
installCommand.command,
|
|
20556
21097
|
installCommand.args,
|
|
20557
21098
|
{
|
|
@@ -20616,6 +21157,56 @@ function normalizeReleaseChannel(value) {
|
|
|
20616
21157
|
function resolveUpgradeChannel(args) {
|
|
20617
21158
|
return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
|
|
20618
21159
|
}
|
|
21160
|
+
function readProviderPriorityFromPolicy(policy) {
|
|
21161
|
+
const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
|
|
21162
|
+
const raw = record.providerPriority;
|
|
21163
|
+
if (!Array.isArray(raw)) return [];
|
|
21164
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21165
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
21166
|
+
if (seen.has(type)) return false;
|
|
21167
|
+
seen.add(type);
|
|
21168
|
+
return true;
|
|
21169
|
+
});
|
|
21170
|
+
}
|
|
21171
|
+
async function resolveProviderTypeFromPriority(args) {
|
|
21172
|
+
if (!args.providerPriority.length) {
|
|
21173
|
+
return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
|
|
21174
|
+
}
|
|
21175
|
+
const failed = [];
|
|
21176
|
+
for (const requestedType of args.providerPriority) {
|
|
21177
|
+
const normalizedType = args.providerLoader.resolveAlias(requestedType);
|
|
21178
|
+
if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
21179
|
+
failed.push(`${requestedType}: disabled`);
|
|
21180
|
+
continue;
|
|
21181
|
+
}
|
|
21182
|
+
const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
|
|
21183
|
+
args.providerLoader.setCliDetectionResults([{
|
|
21184
|
+
id: normalizedType,
|
|
21185
|
+
installed: !!detected,
|
|
21186
|
+
path: detected?.path
|
|
21187
|
+
}], false);
|
|
21188
|
+
args.onStatusChange?.();
|
|
21189
|
+
if (detected) return { providerType: normalizedType };
|
|
21190
|
+
failed.push(`${requestedType}: not detected`);
|
|
21191
|
+
}
|
|
21192
|
+
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
21193
|
+
}
|
|
21194
|
+
function loadYamlModule() {
|
|
21195
|
+
return yaml;
|
|
21196
|
+
}
|
|
21197
|
+
function getMcpServersKey(format) {
|
|
21198
|
+
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
21199
|
+
}
|
|
21200
|
+
function parseMeshCoordinatorMcpConfig(text, format) {
|
|
21201
|
+
if (!text.trim()) return {};
|
|
21202
|
+
if (format === "claude_mcp_json") return JSON.parse(text);
|
|
21203
|
+
const parsed = loadYamlModule().load(text);
|
|
21204
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
21205
|
+
}
|
|
21206
|
+
function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
21207
|
+
if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
|
|
21208
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
21209
|
+
}
|
|
20619
21210
|
var CHAT_COMMANDS = [
|
|
20620
21211
|
"send_chat",
|
|
20621
21212
|
"new_chat",
|
|
@@ -20714,6 +21305,154 @@ var DaemonCommandRouter = class {
|
|
|
20714
21305
|
constructor(deps) {
|
|
20715
21306
|
this.deps = deps;
|
|
20716
21307
|
}
|
|
21308
|
+
getCachedInlineMesh(meshId, inlineMesh) {
|
|
21309
|
+
if (inlineMesh && typeof inlineMesh === "object") {
|
|
21310
|
+
this.inlineMeshCache.set(meshId, inlineMesh);
|
|
21311
|
+
return inlineMesh;
|
|
21312
|
+
}
|
|
21313
|
+
return this.inlineMeshCache.get(meshId);
|
|
21314
|
+
}
|
|
21315
|
+
async getMeshForCommand(meshId, inlineMesh) {
|
|
21316
|
+
try {
|
|
21317
|
+
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21318
|
+
const mesh = getMesh3(meshId);
|
|
21319
|
+
if (mesh) return { mesh, inline: false };
|
|
21320
|
+
} catch {
|
|
21321
|
+
}
|
|
21322
|
+
const cached = this.getCachedInlineMesh(meshId, inlineMesh);
|
|
21323
|
+
return cached ? { mesh: cached, inline: true } : null;
|
|
21324
|
+
}
|
|
21325
|
+
updateInlineMeshNode(meshId, mesh, node) {
|
|
21326
|
+
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
21327
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
21328
|
+
if (idx >= 0) mesh.nodes[idx] = node;
|
|
21329
|
+
else mesh.nodes.push(node);
|
|
21330
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21331
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21332
|
+
}
|
|
21333
|
+
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
21334
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
21335
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
|
|
21336
|
+
if (idx === -1) return false;
|
|
21337
|
+
mesh.nodes.splice(idx, 1);
|
|
21338
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21339
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21340
|
+
return true;
|
|
21341
|
+
}
|
|
21342
|
+
normalizeMeshSessionCleanupMode(value) {
|
|
21343
|
+
return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
|
|
21344
|
+
}
|
|
21345
|
+
sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
|
|
21346
|
+
const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
|
|
21347
|
+
if (!sessionId) return false;
|
|
21348
|
+
if (sessionIds?.size) return sessionIds.has(sessionId);
|
|
21349
|
+
const workspace = typeof node?.workspace === "string" ? node.workspace : "";
|
|
21350
|
+
if (workspace && record?.workspace === workspace) return true;
|
|
21351
|
+
if (record?.meta?.meshNodeId === nodeId) return true;
|
|
21352
|
+
return false;
|
|
21353
|
+
}
|
|
21354
|
+
isCompletedHostedSession(record) {
|
|
21355
|
+
return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
|
|
21356
|
+
}
|
|
21357
|
+
async cleanupMeshSessions(args) {
|
|
21358
|
+
if (args.mode === "preserve") {
|
|
21359
|
+
return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
|
|
21360
|
+
}
|
|
21361
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
21362
|
+
const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
|
|
21363
|
+
const sessions = await this.deps.sessionHostControl.listSessions();
|
|
21364
|
+
const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
|
|
21365
|
+
const hasExplicitSessionIds = !!requestedSessionIds?.size;
|
|
21366
|
+
const stoppedSessionIds = [];
|
|
21367
|
+
const deletedSessionIds = [];
|
|
21368
|
+
const skippedSessionIds = [];
|
|
21369
|
+
const skippedLiveSessionIds = [];
|
|
21370
|
+
const deleteUnsupportedSessionIds = [];
|
|
21371
|
+
const recordsRemainSessionIds = [];
|
|
21372
|
+
const errors = [];
|
|
21373
|
+
const matchedBySurfaceKind = {
|
|
21374
|
+
live_runtime: 0,
|
|
21375
|
+
recovery_snapshot: 0,
|
|
21376
|
+
inactive_record: 0
|
|
21377
|
+
};
|
|
21378
|
+
for (const record of matched) {
|
|
21379
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21380
|
+
matchedBySurfaceKind[surfaceKind] += 1;
|
|
21381
|
+
}
|
|
21382
|
+
for (const record of matched) {
|
|
21383
|
+
const sessionId = String(record.sessionId);
|
|
21384
|
+
const completed = this.isCompletedHostedSession(record);
|
|
21385
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21386
|
+
const liveRuntime = surfaceKind === "live_runtime";
|
|
21387
|
+
if (!hasExplicitSessionIds && liveRuntime) {
|
|
21388
|
+
skippedSessionIds.push(sessionId);
|
|
21389
|
+
skippedLiveSessionIds.push(sessionId);
|
|
21390
|
+
continue;
|
|
21391
|
+
}
|
|
21392
|
+
try {
|
|
21393
|
+
if (args.mode === "stop") {
|
|
21394
|
+
if (!completed) {
|
|
21395
|
+
if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21396
|
+
stoppedSessionIds.push(sessionId);
|
|
21397
|
+
} else {
|
|
21398
|
+
skippedSessionIds.push(sessionId);
|
|
21399
|
+
}
|
|
21400
|
+
continue;
|
|
21401
|
+
}
|
|
21402
|
+
if (args.mode === "delete_stopped") {
|
|
21403
|
+
if (completed) {
|
|
21404
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
|
|
21405
|
+
deletedSessionIds.push(sessionId);
|
|
21406
|
+
} else {
|
|
21407
|
+
skippedSessionIds.push(sessionId);
|
|
21408
|
+
}
|
|
21409
|
+
continue;
|
|
21410
|
+
}
|
|
21411
|
+
if (args.mode === "stop_and_delete") {
|
|
21412
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
|
|
21413
|
+
deletedSessionIds.push(sessionId);
|
|
21414
|
+
continue;
|
|
21415
|
+
}
|
|
21416
|
+
} catch (e) {
|
|
21417
|
+
const message = e?.message || String(e);
|
|
21418
|
+
if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
|
|
21419
|
+
deleteUnsupportedSessionIds.push(sessionId);
|
|
21420
|
+
recordsRemainSessionIds.push(sessionId);
|
|
21421
|
+
if (args.mode === "stop_and_delete" && !completed) {
|
|
21422
|
+
try {
|
|
21423
|
+
await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21424
|
+
stoppedSessionIds.push(sessionId);
|
|
21425
|
+
} catch (stopError) {
|
|
21426
|
+
errors.push({ sessionId, error: stopError?.message || String(stopError) });
|
|
21427
|
+
continue;
|
|
21428
|
+
}
|
|
21429
|
+
}
|
|
21430
|
+
skippedSessionIds.push(sessionId);
|
|
21431
|
+
continue;
|
|
21432
|
+
}
|
|
21433
|
+
errors.push({ sessionId, error: message });
|
|
21434
|
+
}
|
|
21435
|
+
}
|
|
21436
|
+
const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
|
|
21437
|
+
return {
|
|
21438
|
+
success: errors.length === 0,
|
|
21439
|
+
mode: args.mode,
|
|
21440
|
+
dryRun: args.dryRun === true,
|
|
21441
|
+
matchedCount: matched.length,
|
|
21442
|
+
matchedBySurfaceKind,
|
|
21443
|
+
stoppedSessionIds,
|
|
21444
|
+
deletedSessionIds,
|
|
21445
|
+
skippedSessionIds,
|
|
21446
|
+
skippedLiveSessionIds,
|
|
21447
|
+
...deleteUnsupported ? {
|
|
21448
|
+
deleteUnsupported: true,
|
|
21449
|
+
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
21450
|
+
deleteUnsupportedSessionIds,
|
|
21451
|
+
recordsRemainSessionIds
|
|
21452
|
+
} : {},
|
|
21453
|
+
...errors.length ? { errors } : {}
|
|
21454
|
+
};
|
|
21455
|
+
}
|
|
20717
21456
|
async traceSessionHostAction(action, args, run, summarizeResult) {
|
|
20718
21457
|
const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
|
|
20719
21458
|
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -20833,6 +21572,9 @@ var DaemonCommandRouter = class {
|
|
|
20833
21572
|
async executeDaemonCommand(cmd, args) {
|
|
20834
21573
|
switch (cmd) {
|
|
20835
21574
|
// ─── CLI / ACP commands ───
|
|
21575
|
+
case "mesh_forward_event": {
|
|
21576
|
+
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
21577
|
+
}
|
|
20836
21578
|
case "launch_cli":
|
|
20837
21579
|
case "stop_cli":
|
|
20838
21580
|
case "set_cli_view_mode":
|
|
@@ -21377,7 +22119,26 @@ var DaemonCommandRouter = class {
|
|
|
21377
22119
|
if (!name) return { success: false, error: "name required" };
|
|
21378
22120
|
try {
|
|
21379
22121
|
const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21380
|
-
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
|
|
22122
|
+
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
|
|
22123
|
+
return { success: true, mesh };
|
|
22124
|
+
} catch (e) {
|
|
22125
|
+
return { success: false, error: e.message };
|
|
22126
|
+
}
|
|
22127
|
+
}
|
|
22128
|
+
case "update_mesh": {
|
|
22129
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22130
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22131
|
+
try {
|
|
22132
|
+
const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22133
|
+
const patch = {};
|
|
22134
|
+
if (typeof args?.name === "string") patch.name = args.name;
|
|
22135
|
+
if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
|
|
22136
|
+
if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
|
|
22137
|
+
if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
|
|
22138
|
+
if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
|
|
22139
|
+
const mesh = updateMesh2(meshId, patch);
|
|
22140
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22141
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21381
22142
|
return { success: true, mesh };
|
|
21382
22143
|
} catch (e) {
|
|
21383
22144
|
return { success: false, error: e.message };
|
|
@@ -21401,21 +22162,164 @@ var DaemonCommandRouter = class {
|
|
|
21401
22162
|
if (!workspace) return { success: false, error: "workspace required" };
|
|
21402
22163
|
try {
|
|
21403
22164
|
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21404
|
-
const
|
|
22165
|
+
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
22166
|
+
const readOnly = args?.readOnly === true;
|
|
22167
|
+
const policy = {
|
|
22168
|
+
...readOnly ? { readOnly: true } : {},
|
|
22169
|
+
...providerPriority.length ? { providerPriority } : {}
|
|
22170
|
+
};
|
|
22171
|
+
const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
|
|
21405
22172
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
21406
22173
|
return { success: true, node };
|
|
21407
22174
|
} catch (e) {
|
|
21408
22175
|
return { success: false, error: e.message };
|
|
21409
22176
|
}
|
|
21410
22177
|
}
|
|
22178
|
+
case "update_mesh_node": {
|
|
22179
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22180
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22181
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22182
|
+
try {
|
|
22183
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22184
|
+
const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
|
|
22185
|
+
if (Array.isArray(args?.providerPriority)) {
|
|
22186
|
+
const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
|
|
22187
|
+
delete policy.provider_priority;
|
|
22188
|
+
if (providerPriority.length) {
|
|
22189
|
+
policy.providerPriority = providerPriority;
|
|
22190
|
+
} else {
|
|
22191
|
+
delete policy.providerPriority;
|
|
22192
|
+
}
|
|
22193
|
+
}
|
|
22194
|
+
const node = updateNode2(meshId, nodeId, { policy });
|
|
22195
|
+
if (!node) return { success: false, error: "Mesh node not found" };
|
|
22196
|
+
return { success: true, node };
|
|
22197
|
+
} catch (e) {
|
|
22198
|
+
return { success: false, error: e.message };
|
|
22199
|
+
}
|
|
22200
|
+
}
|
|
22201
|
+
case "cleanup_mesh_sessions": {
|
|
22202
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22203
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22204
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22205
|
+
try {
|
|
22206
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22207
|
+
const mesh = meshRecord?.mesh;
|
|
22208
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22209
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22210
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
22211
|
+
const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
|
|
22212
|
+
const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
|
|
22213
|
+
const result = await this.cleanupMeshSessions({
|
|
22214
|
+
meshId,
|
|
22215
|
+
nodeId,
|
|
22216
|
+
node,
|
|
22217
|
+
mode,
|
|
22218
|
+
sessionIds,
|
|
22219
|
+
dryRun: args?.dryRun === true
|
|
22220
|
+
});
|
|
22221
|
+
return result;
|
|
22222
|
+
} catch (e) {
|
|
22223
|
+
return { success: false, error: e.message };
|
|
22224
|
+
}
|
|
22225
|
+
}
|
|
21411
22226
|
case "remove_mesh_node": {
|
|
21412
22227
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21413
22228
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
21414
22229
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
21415
22230
|
try {
|
|
21416
|
-
const
|
|
21417
|
-
const
|
|
21418
|
-
|
|
22231
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22232
|
+
const mesh = meshRecord?.mesh;
|
|
22233
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22234
|
+
const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
|
|
22235
|
+
args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
|
|
22236
|
+
);
|
|
22237
|
+
let sessionCleanup;
|
|
22238
|
+
if (node && sessionCleanupMode !== "preserve") {
|
|
22239
|
+
sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
|
|
22240
|
+
if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
|
|
22241
|
+
}
|
|
22242
|
+
if (node?.isLocalWorktree && node.workspace) {
|
|
22243
|
+
try {
|
|
22244
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
22245
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
22246
|
+
if (repoRoot) {
|
|
22247
|
+
const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22248
|
+
await removeWorktree2(repoRoot, node.workspace);
|
|
22249
|
+
}
|
|
22250
|
+
} catch (e) {
|
|
22251
|
+
LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
|
|
22252
|
+
}
|
|
22253
|
+
}
|
|
22254
|
+
let removed = false;
|
|
22255
|
+
if (meshRecord?.inline) {
|
|
22256
|
+
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
22257
|
+
} else {
|
|
22258
|
+
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22259
|
+
removed = removeNode3(meshId, nodeId);
|
|
22260
|
+
}
|
|
22261
|
+
return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
|
|
22262
|
+
} catch (e) {
|
|
22263
|
+
return { success: false, error: e.message };
|
|
22264
|
+
}
|
|
22265
|
+
}
|
|
22266
|
+
case "clone_mesh_node": {
|
|
22267
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22268
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
22269
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
22270
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
22271
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22272
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
22273
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
22274
|
+
try {
|
|
22275
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22276
|
+
const mesh = meshRecord?.mesh;
|
|
22277
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22278
|
+
const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
|
|
22279
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
22280
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
22281
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22282
|
+
const result = await createWorktree2({
|
|
22283
|
+
repoRoot,
|
|
22284
|
+
branch,
|
|
22285
|
+
baseBranch,
|
|
22286
|
+
meshName: mesh.name
|
|
22287
|
+
});
|
|
22288
|
+
let node;
|
|
22289
|
+
if (meshRecord.inline) {
|
|
22290
|
+
const { randomUUID: randomUUID8 } = await import("crypto");
|
|
22291
|
+
node = {
|
|
22292
|
+
id: `node_${randomUUID8().replace(/-/g, "")}`,
|
|
22293
|
+
workspace: result.worktreePath,
|
|
22294
|
+
repoRoot: result.worktreePath,
|
|
22295
|
+
daemonId: sourceNode.daemonId,
|
|
22296
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22297
|
+
policy: { ...sourceNode.policy || {} },
|
|
22298
|
+
isLocalWorktree: true,
|
|
22299
|
+
worktreeBranch: result.branch,
|
|
22300
|
+
clonedFromNodeId: sourceNodeId
|
|
22301
|
+
};
|
|
22302
|
+
this.updateInlineMeshNode(meshId, mesh, node);
|
|
22303
|
+
} else {
|
|
22304
|
+
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22305
|
+
node = addNode3(meshId, {
|
|
22306
|
+
workspace: result.worktreePath,
|
|
22307
|
+
repoRoot: result.worktreePath,
|
|
22308
|
+
daemonId: sourceNode.daemonId,
|
|
22309
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22310
|
+
isLocalWorktree: true,
|
|
22311
|
+
worktreeBranch: result.branch,
|
|
22312
|
+
clonedFromNodeId: sourceNodeId,
|
|
22313
|
+
policy: { ...sourceNode.policy || {} }
|
|
22314
|
+
});
|
|
22315
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
22316
|
+
}
|
|
22317
|
+
return {
|
|
22318
|
+
success: true,
|
|
22319
|
+
node,
|
|
22320
|
+
worktreePath: result.worktreePath,
|
|
22321
|
+
branch: result.branch
|
|
22322
|
+
};
|
|
21419
22323
|
} catch (e) {
|
|
21420
22324
|
return { success: false, error: e.message };
|
|
21421
22325
|
}
|
|
@@ -21423,7 +22327,7 @@ var DaemonCommandRouter = class {
|
|
|
21423
22327
|
// ─── Mesh Coordinator Launch ───
|
|
21424
22328
|
case "launch_mesh_coordinator": {
|
|
21425
22329
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21426
|
-
|
|
22330
|
+
let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
|
|
21427
22331
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
21428
22332
|
try {
|
|
21429
22333
|
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
@@ -21451,9 +22355,29 @@ var DaemonCommandRouter = class {
|
|
|
21451
22355
|
}
|
|
21452
22356
|
const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
|
|
21453
22357
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
22358
|
+
if (!cliType) {
|
|
22359
|
+
const resolved = await resolveProviderTypeFromPriority({
|
|
22360
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
|
|
22361
|
+
providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
|
|
22362
|
+
providerLoader: this.deps.providerLoader,
|
|
22363
|
+
onStatusChange: this.deps.onStatusChange
|
|
22364
|
+
});
|
|
22365
|
+
if (!resolved.providerType) {
|
|
22366
|
+
return {
|
|
22367
|
+
success: false,
|
|
22368
|
+
code: "mesh_coordinator_provider_priority_unusable",
|
|
22369
|
+
error: resolved.error || "No usable provider found from node providerPriority",
|
|
22370
|
+
meshId,
|
|
22371
|
+
cliType,
|
|
22372
|
+
workspace
|
|
22373
|
+
};
|
|
22374
|
+
}
|
|
22375
|
+
cliType = resolved.providerType;
|
|
22376
|
+
}
|
|
21454
22377
|
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
21455
22378
|
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
21456
22379
|
provider: providerMeta,
|
|
22380
|
+
cliType,
|
|
21457
22381
|
meshId,
|
|
21458
22382
|
workspace
|
|
21459
22383
|
});
|
|
@@ -21478,7 +22402,8 @@ var DaemonCommandRouter = class {
|
|
|
21478
22402
|
meshCoordinatorSetup: coordinatorSetup
|
|
21479
22403
|
};
|
|
21480
22404
|
}
|
|
21481
|
-
|
|
22405
|
+
const configFormat = coordinatorSetup.configFormat;
|
|
22406
|
+
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
21482
22407
|
return {
|
|
21483
22408
|
success: false,
|
|
21484
22409
|
code: "mesh_coordinator_unsupported",
|
|
@@ -21488,44 +22413,93 @@ var DaemonCommandRouter = class {
|
|
|
21488
22413
|
workspace
|
|
21489
22414
|
};
|
|
21490
22415
|
}
|
|
21491
|
-
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
|
|
22416
|
+
let systemPrompt = "";
|
|
22417
|
+
try {
|
|
22418
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
22419
|
+
} catch (error) {
|
|
22420
|
+
const message = error?.message || String(error);
|
|
22421
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
22422
|
+
return {
|
|
22423
|
+
success: false,
|
|
22424
|
+
code: "mesh_coordinator_prompt_failed",
|
|
22425
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
22426
|
+
meshId,
|
|
22427
|
+
cliType,
|
|
22428
|
+
workspace
|
|
22429
|
+
};
|
|
21501
22430
|
}
|
|
22431
|
+
const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
|
|
22432
|
+
const { dirname: dirname9 } = await import("path");
|
|
22433
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
22434
|
+
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
22435
|
+
const returnManualFallback = (message) => ({
|
|
22436
|
+
success: false,
|
|
22437
|
+
code: "mesh_coordinator_manual_mcp_setup_required",
|
|
22438
|
+
error: message,
|
|
22439
|
+
meshId,
|
|
22440
|
+
cliType,
|
|
22441
|
+
workspace,
|
|
22442
|
+
meshCoordinatorSetup: hermesManualFallback
|
|
22443
|
+
});
|
|
21502
22444
|
const mcpServerEntry = {
|
|
21503
22445
|
command: coordinatorSetup.mcpServer.command,
|
|
21504
22446
|
args: coordinatorSetup.mcpServer.args
|
|
21505
22447
|
};
|
|
21506
22448
|
if (args?.inlineMesh) {
|
|
21507
22449
|
mcpServerEntry.env = {
|
|
21508
|
-
ADHDEV_INLINE_MESH: JSON.stringify(mesh)
|
|
22450
|
+
ADHDEV_INLINE_MESH: JSON.stringify(mesh),
|
|
22451
|
+
ADHDEV_MCP_TRANSPORT: "ipc"
|
|
21509
22452
|
};
|
|
21510
22453
|
}
|
|
22454
|
+
try {
|
|
22455
|
+
mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
|
|
22456
|
+
} catch (error) {
|
|
22457
|
+
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
22458
|
+
LOG.error("MeshCoordinator", message);
|
|
22459
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22460
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
22461
|
+
}
|
|
22462
|
+
const hadExistingMcpConfig = existsSync23(mcpConfigPath);
|
|
22463
|
+
let existingMcpConfig = {};
|
|
22464
|
+
if (hadExistingMcpConfig) {
|
|
22465
|
+
try {
|
|
22466
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
|
|
22467
|
+
copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
|
|
22468
|
+
} catch (error) {
|
|
22469
|
+
LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
22470
|
+
return {
|
|
22471
|
+
success: false,
|
|
22472
|
+
code: "mesh_coordinator_config_parse_failed",
|
|
22473
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`
|
|
22474
|
+
};
|
|
22475
|
+
}
|
|
22476
|
+
}
|
|
22477
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
22478
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
21511
22479
|
const mcpConfig = {
|
|
21512
22480
|
...existingMcpConfig,
|
|
21513
|
-
|
|
21514
|
-
...
|
|
22481
|
+
[mcpServersKey]: {
|
|
22482
|
+
...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
|
|
21515
22483
|
[coordinatorSetup.serverName]: mcpServerEntry
|
|
21516
22484
|
}
|
|
21517
22485
|
};
|
|
21518
|
-
writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
21519
|
-
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21520
|
-
let systemPrompt = "";
|
|
21521
22486
|
try {
|
|
21522
|
-
|
|
21523
|
-
} catch {
|
|
21524
|
-
|
|
22487
|
+
writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
22488
|
+
} catch (error) {
|
|
22489
|
+
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
22490
|
+
LOG.error("MeshCoordinator", message);
|
|
22491
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22492
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21525
22493
|
}
|
|
22494
|
+
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21526
22495
|
const cliArgs = [];
|
|
22496
|
+
const launchEnv = {};
|
|
21527
22497
|
if (systemPrompt) {
|
|
21528
|
-
|
|
22498
|
+
if (configFormat === "hermes_config_yaml") {
|
|
22499
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
22500
|
+
} else {
|
|
22501
|
+
cliArgs.push("--append-system-prompt", systemPrompt);
|
|
22502
|
+
}
|
|
21529
22503
|
}
|
|
21530
22504
|
if (cliType === "claude-cli") {
|
|
21531
22505
|
cliArgs.push("--mcp-config", coordinatorSetup.configPath);
|
|
@@ -21534,6 +22508,7 @@ var DaemonCommandRouter = class {
|
|
|
21534
22508
|
cliType,
|
|
21535
22509
|
dir: workspace,
|
|
21536
22510
|
cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
|
|
22511
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
21537
22512
|
settings: {
|
|
21538
22513
|
meshCoordinatorFor: meshId
|
|
21539
22514
|
}
|
|
@@ -21713,6 +22688,12 @@ var DaemonStatusReporter = class {
|
|
|
21713
22688
|
if (providerType) {
|
|
21714
22689
|
payload.providerType = providerType;
|
|
21715
22690
|
}
|
|
22691
|
+
if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
|
|
22692
|
+
payload.providerSessionId = event.providerSessionId.trim();
|
|
22693
|
+
}
|
|
22694
|
+
if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
|
|
22695
|
+
payload.workspaceName = event.workspaceName.trim();
|
|
22696
|
+
}
|
|
21716
22697
|
if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
|
|
21717
22698
|
payload.duration = event.duration;
|
|
21718
22699
|
}
|
|
@@ -22960,7 +23941,10 @@ var ProviderInstanceManager = class {
|
|
|
22960
23941
|
this.instances.get(id).dispose();
|
|
22961
23942
|
}
|
|
22962
23943
|
this.instances.set(id, instance);
|
|
22963
|
-
await instance.init(
|
|
23944
|
+
await instance.init({
|
|
23945
|
+
...context,
|
|
23946
|
+
emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
|
|
23947
|
+
});
|
|
22964
23948
|
}
|
|
22965
23949
|
/**
|
|
22966
23950
|
* Instance remove
|
|
@@ -23122,6 +24106,17 @@ var ProviderInstanceManager = class {
|
|
|
23122
24106
|
onEvent(listener) {
|
|
23123
24107
|
this.eventListeners.push(listener);
|
|
23124
24108
|
}
|
|
24109
|
+
emitProviderEvent(providerType, instanceId, event) {
|
|
24110
|
+
const payload = {
|
|
24111
|
+
...event,
|
|
24112
|
+
providerType,
|
|
24113
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
|
|
24114
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
|
|
24115
|
+
};
|
|
24116
|
+
for (const listener of this.eventListeners) {
|
|
24117
|
+
listener(payload);
|
|
24118
|
+
}
|
|
24119
|
+
}
|
|
23125
24120
|
emitPendingEvents(providerType, state, extra = {}) {
|
|
23126
24121
|
for (const event of state.pendingEvents) {
|
|
23127
24122
|
for (const listener of this.eventListeners) {
|
|
@@ -23194,11 +24189,11 @@ var ProviderInstanceManager = class {
|
|
|
23194
24189
|
|
|
23195
24190
|
// src/providers/version-archive.ts
|
|
23196
24191
|
import * as fs11 from "fs";
|
|
23197
|
-
import * as
|
|
23198
|
-
import * as
|
|
24192
|
+
import * as path22 from "path";
|
|
24193
|
+
import * as os20 from "os";
|
|
23199
24194
|
import { execSync as execSync5 } from "child_process";
|
|
23200
24195
|
import { platform as platform8 } from "os";
|
|
23201
|
-
var ARCHIVE_PATH =
|
|
24196
|
+
var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
|
|
23202
24197
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
23203
24198
|
var VersionArchive = class {
|
|
23204
24199
|
history = {};
|
|
@@ -23245,7 +24240,7 @@ var VersionArchive = class {
|
|
|
23245
24240
|
}
|
|
23246
24241
|
save() {
|
|
23247
24242
|
try {
|
|
23248
|
-
fs11.mkdirSync(
|
|
24243
|
+
fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
|
|
23249
24244
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
23250
24245
|
} catch {
|
|
23251
24246
|
}
|
|
@@ -23301,8 +24296,8 @@ function getVersion(binary, versionCommand) {
|
|
|
23301
24296
|
function checkPathExists2(paths) {
|
|
23302
24297
|
for (const p of paths) {
|
|
23303
24298
|
if (p.includes("*")) {
|
|
23304
|
-
const home =
|
|
23305
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
24299
|
+
const home = os20.homedir();
|
|
24300
|
+
const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
|
|
23306
24301
|
if (fs11.existsSync(resolved)) return resolved;
|
|
23307
24302
|
} else {
|
|
23308
24303
|
if (fs11.existsSync(p)) return p;
|
|
@@ -23312,7 +24307,7 @@ function checkPathExists2(paths) {
|
|
|
23312
24307
|
}
|
|
23313
24308
|
function getMacAppVersion(appPath) {
|
|
23314
24309
|
if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
23315
|
-
const plistPath =
|
|
24310
|
+
const plistPath = path22.join(appPath, "Contents", "Info.plist");
|
|
23316
24311
|
if (!fs11.existsSync(plistPath)) return null;
|
|
23317
24312
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
23318
24313
|
return raw || null;
|
|
@@ -23338,7 +24333,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23338
24333
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
23339
24334
|
let resolvedBin = cliBin;
|
|
23340
24335
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
23341
|
-
const bundled =
|
|
24336
|
+
const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
23342
24337
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
23343
24338
|
}
|
|
23344
24339
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -23379,7 +24374,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23379
24374
|
// src/daemon/dev-server.ts
|
|
23380
24375
|
import * as http2 from "http";
|
|
23381
24376
|
import * as fs15 from "fs";
|
|
23382
|
-
import * as
|
|
24377
|
+
import * as path26 from "path";
|
|
23383
24378
|
init_config();
|
|
23384
24379
|
|
|
23385
24380
|
// src/daemon/scaffold-template.ts
|
|
@@ -23731,7 +24726,7 @@ init_logger();
|
|
|
23731
24726
|
// src/daemon/dev-cdp-handlers.ts
|
|
23732
24727
|
init_logger();
|
|
23733
24728
|
import * as fs12 from "fs";
|
|
23734
|
-
import * as
|
|
24729
|
+
import * as path23 from "path";
|
|
23735
24730
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
23736
24731
|
const body = await ctx.readBody(req);
|
|
23737
24732
|
const { expression, timeout, ideType } = body;
|
|
@@ -23909,17 +24904,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
23909
24904
|
return;
|
|
23910
24905
|
}
|
|
23911
24906
|
let scriptsPath = "";
|
|
23912
|
-
const directScripts =
|
|
24907
|
+
const directScripts = path23.join(dir, "scripts.js");
|
|
23913
24908
|
if (fs12.existsSync(directScripts)) {
|
|
23914
24909
|
scriptsPath = directScripts;
|
|
23915
24910
|
} else {
|
|
23916
|
-
const scriptsDir =
|
|
24911
|
+
const scriptsDir = path23.join(dir, "scripts");
|
|
23917
24912
|
if (fs12.existsSync(scriptsDir)) {
|
|
23918
24913
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
23919
|
-
return fs12.statSync(
|
|
24914
|
+
return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
|
|
23920
24915
|
}).sort().reverse();
|
|
23921
24916
|
for (const ver of versions) {
|
|
23922
|
-
const p =
|
|
24917
|
+
const p = path23.join(scriptsDir, ver, "scripts.js");
|
|
23923
24918
|
if (fs12.existsSync(p)) {
|
|
23924
24919
|
scriptsPath = p;
|
|
23925
24920
|
break;
|
|
@@ -24748,7 +25743,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
24748
25743
|
|
|
24749
25744
|
// src/daemon/dev-cli-debug.ts
|
|
24750
25745
|
import * as fs13 from "fs";
|
|
24751
|
-
import * as
|
|
25746
|
+
import * as path24 from "path";
|
|
24752
25747
|
function slugifyFixtureName(value) {
|
|
24753
25748
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24754
25749
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -24758,11 +25753,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
24758
25753
|
if (!providerDir) {
|
|
24759
25754
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
24760
25755
|
}
|
|
24761
|
-
return
|
|
25756
|
+
return path24.join(providerDir, "fixtures");
|
|
24762
25757
|
}
|
|
24763
25758
|
function readCliFixture(ctx, type, name) {
|
|
24764
25759
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
24765
|
-
const filePath =
|
|
25760
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
24766
25761
|
if (!fs13.existsSync(filePath)) {
|
|
24767
25762
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
24768
25763
|
}
|
|
@@ -24930,7 +25925,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
|
|
|
24930
25925
|
if (!adapter) return null;
|
|
24931
25926
|
return { target, instance, adapter };
|
|
24932
25927
|
}
|
|
24933
|
-
function
|
|
25928
|
+
function sleep2(ms) {
|
|
24934
25929
|
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
24935
25930
|
}
|
|
24936
25931
|
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
@@ -24947,7 +25942,7 @@ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
|
24947
25942
|
return bundle;
|
|
24948
25943
|
}
|
|
24949
25944
|
}
|
|
24950
|
-
await
|
|
25945
|
+
await sleep2(100);
|
|
24951
25946
|
}
|
|
24952
25947
|
return getCliTargetBundle(ctx, type, instanceId);
|
|
24953
25948
|
}
|
|
@@ -25003,7 +25998,7 @@ async function runCliExerciseInternal(ctx, body) {
|
|
|
25003
25998
|
const message = String(lastLaunchError.message || "");
|
|
25004
25999
|
const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
|
|
25005
26000
|
if (!retryable || attempt === 2) break;
|
|
25006
|
-
await
|
|
26001
|
+
await sleep2(1e3);
|
|
25007
26002
|
}
|
|
25008
26003
|
}
|
|
25009
26004
|
if (!launched) {
|
|
@@ -25066,16 +26061,16 @@ async function runCliExerciseInternal(ctx, body) {
|
|
|
25066
26061
|
const modal = debug?.activeModal || trace?.activeModal || null;
|
|
25067
26062
|
noteStatus(status);
|
|
25068
26063
|
if (resolveActiveModalIfNeeded(status, modal)) {
|
|
25069
|
-
await
|
|
26064
|
+
await sleep2(150);
|
|
25070
26065
|
continue;
|
|
25071
26066
|
}
|
|
25072
26067
|
const startupParseGate = !!debug?.startupParseGate;
|
|
25073
26068
|
if (status === "idle" && !startupParseGate) break;
|
|
25074
|
-
await
|
|
26069
|
+
await sleep2(150);
|
|
25075
26070
|
}
|
|
25076
26071
|
ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
|
|
25077
26072
|
while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
|
|
25078
|
-
await
|
|
26073
|
+
await sleep2(150);
|
|
25079
26074
|
bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
|
|
25080
26075
|
if (!bundle) {
|
|
25081
26076
|
throw new Error("CLI instance disappeared during exercise");
|
|
@@ -25529,7 +26524,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
25529
26524
|
},
|
|
25530
26525
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
25531
26526
|
};
|
|
25532
|
-
const filePath =
|
|
26527
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
25533
26528
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
25534
26529
|
ctx.json(res, 200, {
|
|
25535
26530
|
saved: true,
|
|
@@ -25553,7 +26548,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
25553
26548
|
return;
|
|
25554
26549
|
}
|
|
25555
26550
|
const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
25556
|
-
const fullPath =
|
|
26551
|
+
const fullPath = path24.join(fixtureDir, file);
|
|
25557
26552
|
try {
|
|
25558
26553
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
25559
26554
|
return {
|
|
@@ -25689,8 +26684,8 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
25689
26684
|
|
|
25690
26685
|
// src/daemon/dev-auto-implement.ts
|
|
25691
26686
|
import * as fs14 from "fs";
|
|
25692
|
-
import * as
|
|
25693
|
-
import * as
|
|
26687
|
+
import * as path25 from "path";
|
|
26688
|
+
import * as os21 from "os";
|
|
25694
26689
|
function getAutoImplPid(ctx) {
|
|
25695
26690
|
const pid = ctx.autoImplProcess?.pid;
|
|
25696
26691
|
return typeof pid === "number" && pid > 0 ? pid : null;
|
|
@@ -25739,22 +26734,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
25739
26734
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
25740
26735
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
25741
26736
|
try {
|
|
25742
|
-
return fs14.statSync(
|
|
26737
|
+
return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
25743
26738
|
} catch {
|
|
25744
26739
|
return false;
|
|
25745
26740
|
}
|
|
25746
26741
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
25747
26742
|
if (versions.length === 0) return null;
|
|
25748
|
-
return
|
|
26743
|
+
return path25.join(scriptsDir, versions[0]);
|
|
25749
26744
|
}
|
|
25750
26745
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
25751
|
-
const canonicalUserDir =
|
|
25752
|
-
const desiredDir = requestedDir ?
|
|
25753
|
-
const upstreamRoot =
|
|
25754
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
26746
|
+
const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
26747
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
26748
|
+
const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
|
|
26749
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
25755
26750
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
25756
26751
|
}
|
|
25757
|
-
if (
|
|
26752
|
+
if (path25.basename(desiredDir) !== type) {
|
|
25758
26753
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
25759
26754
|
}
|
|
25760
26755
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -25762,11 +26757,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
25762
26757
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
25763
26758
|
}
|
|
25764
26759
|
if (!fs14.existsSync(desiredDir)) {
|
|
25765
|
-
fs14.mkdirSync(
|
|
26760
|
+
fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
25766
26761
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
25767
26762
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
25768
26763
|
}
|
|
25769
|
-
const providerJson =
|
|
26764
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
25770
26765
|
if (!fs14.existsSync(providerJson)) {
|
|
25771
26766
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
25772
26767
|
}
|
|
@@ -25777,13 +26772,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
25777
26772
|
const refDir = ctx.findProviderDir(referenceType);
|
|
25778
26773
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
25779
26774
|
const referenceScripts = {};
|
|
25780
|
-
const scriptsDir =
|
|
26775
|
+
const scriptsDir = path25.join(refDir, "scripts");
|
|
25781
26776
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
25782
26777
|
if (!latestDir) return referenceScripts;
|
|
25783
26778
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
25784
26779
|
if (!file.endsWith(".js")) continue;
|
|
25785
26780
|
try {
|
|
25786
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
26781
|
+
referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
|
|
25787
26782
|
} catch {
|
|
25788
26783
|
}
|
|
25789
26784
|
}
|
|
@@ -25891,9 +26886,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
25891
26886
|
});
|
|
25892
26887
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
25893
26888
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
25894
|
-
const tmpDir =
|
|
26889
|
+
const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
|
|
25895
26890
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
25896
|
-
const promptFile =
|
|
26891
|
+
const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
25897
26892
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
25898
26893
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
25899
26894
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -26046,7 +27041,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26046
27041
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
26047
27042
|
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
26048
27043
|
let shellCmd;
|
|
26049
|
-
const isWin =
|
|
27044
|
+
const isWin = os21.platform() === "win32";
|
|
26050
27045
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
26051
27046
|
const promptMode = autoImpl?.promptMode ?? "stdin";
|
|
26052
27047
|
const extraArgs = autoImpl?.extraArgs ?? [];
|
|
@@ -26085,7 +27080,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26085
27080
|
try {
|
|
26086
27081
|
const pty = __require("node-pty");
|
|
26087
27082
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
26088
|
-
const isWin2 =
|
|
27083
|
+
const isWin2 = os21.platform() === "win32";
|
|
26089
27084
|
child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
26090
27085
|
name: "xterm-256color",
|
|
26091
27086
|
cols: 120,
|
|
@@ -26325,7 +27320,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26325
27320
|
setMode: "set_mode.js"
|
|
26326
27321
|
};
|
|
26327
27322
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26328
|
-
const scriptsDir =
|
|
27323
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26329
27324
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26330
27325
|
if (latestScriptsDir) {
|
|
26331
27326
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26336,7 +27331,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26336
27331
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
26337
27332
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26338
27333
|
try {
|
|
26339
|
-
const content = fs14.readFileSync(
|
|
27334
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26340
27335
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26341
27336
|
lines.push("```javascript");
|
|
26342
27337
|
lines.push(content);
|
|
@@ -26353,7 +27348,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26353
27348
|
lines.push("");
|
|
26354
27349
|
for (const file of refFiles) {
|
|
26355
27350
|
try {
|
|
26356
|
-
const content = fs14.readFileSync(
|
|
27351
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26357
27352
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26358
27353
|
lines.push("```javascript");
|
|
26359
27354
|
lines.push(content);
|
|
@@ -26394,10 +27389,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26394
27389
|
lines.push("");
|
|
26395
27390
|
}
|
|
26396
27391
|
}
|
|
26397
|
-
const docsDir =
|
|
27392
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26398
27393
|
const loadGuide = (name) => {
|
|
26399
27394
|
try {
|
|
26400
|
-
const p =
|
|
27395
|
+
const p = path25.join(docsDir, name);
|
|
26401
27396
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26402
27397
|
} catch {
|
|
26403
27398
|
}
|
|
@@ -26634,7 +27629,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26634
27629
|
parseApproval: "parse_approval.js"
|
|
26635
27630
|
};
|
|
26636
27631
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26637
|
-
const scriptsDir =
|
|
27632
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26638
27633
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26639
27634
|
if (latestScriptsDir) {
|
|
26640
27635
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26646,7 +27641,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26646
27641
|
if (!file.endsWith(".js")) continue;
|
|
26647
27642
|
if (!targetFileNames.has(file)) continue;
|
|
26648
27643
|
try {
|
|
26649
|
-
const content = fs14.readFileSync(
|
|
27644
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26650
27645
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26651
27646
|
lines.push("```javascript");
|
|
26652
27647
|
lines.push(content);
|
|
@@ -26662,7 +27657,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26662
27657
|
lines.push("");
|
|
26663
27658
|
for (const file of refFiles) {
|
|
26664
27659
|
try {
|
|
26665
|
-
const content = fs14.readFileSync(
|
|
27660
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26666
27661
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26667
27662
|
lines.push("```javascript");
|
|
26668
27663
|
lines.push(content);
|
|
@@ -26695,10 +27690,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26695
27690
|
lines.push("");
|
|
26696
27691
|
}
|
|
26697
27692
|
}
|
|
26698
|
-
const docsDir =
|
|
27693
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26699
27694
|
const loadGuide = (name) => {
|
|
26700
27695
|
try {
|
|
26701
|
-
const p =
|
|
27696
|
+
const p = path25.join(docsDir, name);
|
|
26702
27697
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26703
27698
|
} catch {
|
|
26704
27699
|
}
|
|
@@ -27145,8 +28140,8 @@ var DevServer = class _DevServer {
|
|
|
27145
28140
|
}
|
|
27146
28141
|
getEndpointList() {
|
|
27147
28142
|
return this.routes.map((r) => {
|
|
27148
|
-
const
|
|
27149
|
-
return `${r.method.padEnd(5)} ${
|
|
28143
|
+
const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
28144
|
+
return `${r.method.padEnd(5)} ${path27}`;
|
|
27150
28145
|
});
|
|
27151
28146
|
}
|
|
27152
28147
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -27434,12 +28429,12 @@ var DevServer = class _DevServer {
|
|
|
27434
28429
|
// ─── DevConsole SPA ───
|
|
27435
28430
|
getConsoleDistDir() {
|
|
27436
28431
|
const candidates = [
|
|
27437
|
-
|
|
27438
|
-
|
|
27439
|
-
|
|
28432
|
+
path26.resolve(__dirname, "../../web-devconsole/dist"),
|
|
28433
|
+
path26.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
28434
|
+
path26.join(process.cwd(), "packages/web-devconsole/dist")
|
|
27440
28435
|
];
|
|
27441
28436
|
for (const dir of candidates) {
|
|
27442
|
-
if (fs15.existsSync(
|
|
28437
|
+
if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
|
|
27443
28438
|
}
|
|
27444
28439
|
return null;
|
|
27445
28440
|
}
|
|
@@ -27449,7 +28444,7 @@ var DevServer = class _DevServer {
|
|
|
27449
28444
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
27450
28445
|
return;
|
|
27451
28446
|
}
|
|
27452
|
-
const htmlPath =
|
|
28447
|
+
const htmlPath = path26.join(distDir, "index.html");
|
|
27453
28448
|
try {
|
|
27454
28449
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
27455
28450
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -27474,15 +28469,15 @@ var DevServer = class _DevServer {
|
|
|
27474
28469
|
this.json(res, 404, { error: "Not found" });
|
|
27475
28470
|
return;
|
|
27476
28471
|
}
|
|
27477
|
-
const safePath =
|
|
27478
|
-
const filePath =
|
|
28472
|
+
const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
|
|
28473
|
+
const filePath = path26.join(distDir, safePath);
|
|
27479
28474
|
if (!filePath.startsWith(distDir)) {
|
|
27480
28475
|
this.json(res, 403, { error: "Forbidden" });
|
|
27481
28476
|
return;
|
|
27482
28477
|
}
|
|
27483
28478
|
try {
|
|
27484
28479
|
const content = fs15.readFileSync(filePath);
|
|
27485
|
-
const ext =
|
|
28480
|
+
const ext = path26.extname(filePath);
|
|
27486
28481
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
27487
28482
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
27488
28483
|
res.end(content);
|
|
@@ -27595,9 +28590,9 @@ var DevServer = class _DevServer {
|
|
|
27595
28590
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27596
28591
|
if (entry.isDirectory()) {
|
|
27597
28592
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
27598
|
-
scan(
|
|
28593
|
+
scan(path26.join(d, entry.name), rel);
|
|
27599
28594
|
} else {
|
|
27600
|
-
const stat2 = fs15.statSync(
|
|
28595
|
+
const stat2 = fs15.statSync(path26.join(d, entry.name));
|
|
27601
28596
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
27602
28597
|
}
|
|
27603
28598
|
}
|
|
@@ -27620,7 +28615,7 @@ var DevServer = class _DevServer {
|
|
|
27620
28615
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27621
28616
|
return;
|
|
27622
28617
|
}
|
|
27623
|
-
const fullPath =
|
|
28618
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27624
28619
|
if (!fullPath.startsWith(dir)) {
|
|
27625
28620
|
this.json(res, 403, { error: "Forbidden" });
|
|
27626
28621
|
return;
|
|
@@ -27645,14 +28640,14 @@ var DevServer = class _DevServer {
|
|
|
27645
28640
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27646
28641
|
return;
|
|
27647
28642
|
}
|
|
27648
|
-
const fullPath =
|
|
28643
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27649
28644
|
if (!fullPath.startsWith(dir)) {
|
|
27650
28645
|
this.json(res, 403, { error: "Forbidden" });
|
|
27651
28646
|
return;
|
|
27652
28647
|
}
|
|
27653
28648
|
try {
|
|
27654
28649
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
27655
|
-
fs15.mkdirSync(
|
|
28650
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27656
28651
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27657
28652
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
27658
28653
|
this.providerLoader.reload();
|
|
@@ -27669,7 +28664,7 @@ var DevServer = class _DevServer {
|
|
|
27669
28664
|
return;
|
|
27670
28665
|
}
|
|
27671
28666
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
27672
|
-
const p =
|
|
28667
|
+
const p = path26.join(dir, name);
|
|
27673
28668
|
if (fs15.existsSync(p)) {
|
|
27674
28669
|
const source = fs15.readFileSync(p, "utf-8");
|
|
27675
28670
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -27690,8 +28685,8 @@ var DevServer = class _DevServer {
|
|
|
27690
28685
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
27691
28686
|
return;
|
|
27692
28687
|
}
|
|
27693
|
-
const target = fs15.existsSync(
|
|
27694
|
-
const targetPath =
|
|
28688
|
+
const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
28689
|
+
const targetPath = path26.join(dir, target);
|
|
27695
28690
|
try {
|
|
27696
28691
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
27697
28692
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -27838,7 +28833,7 @@ var DevServer = class _DevServer {
|
|
|
27838
28833
|
}
|
|
27839
28834
|
let targetDir;
|
|
27840
28835
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
27841
|
-
const jsonPath =
|
|
28836
|
+
const jsonPath = path26.join(targetDir, "provider.json");
|
|
27842
28837
|
if (fs15.existsSync(jsonPath)) {
|
|
27843
28838
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
27844
28839
|
return;
|
|
@@ -27850,8 +28845,8 @@ var DevServer = class _DevServer {
|
|
|
27850
28845
|
const createdFiles = ["provider.json"];
|
|
27851
28846
|
if (result.files) {
|
|
27852
28847
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
27853
|
-
const fullPath =
|
|
27854
|
-
fs15.mkdirSync(
|
|
28848
|
+
const fullPath = path26.join(targetDir, relPath);
|
|
28849
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27855
28850
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27856
28851
|
createdFiles.push(relPath);
|
|
27857
28852
|
}
|
|
@@ -27904,22 +28899,22 @@ var DevServer = class _DevServer {
|
|
|
27904
28899
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
27905
28900
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
27906
28901
|
try {
|
|
27907
|
-
return fs15.statSync(
|
|
28902
|
+
return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
|
|
27908
28903
|
} catch {
|
|
27909
28904
|
return false;
|
|
27910
28905
|
}
|
|
27911
28906
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
27912
28907
|
if (versions.length === 0) return null;
|
|
27913
|
-
return
|
|
28908
|
+
return path26.join(scriptsDir, versions[0]);
|
|
27914
28909
|
}
|
|
27915
28910
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
27916
|
-
const canonicalUserDir =
|
|
27917
|
-
const desiredDir = requestedDir ?
|
|
27918
|
-
const upstreamRoot =
|
|
27919
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
28911
|
+
const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
28912
|
+
const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
|
|
28913
|
+
const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
|
|
28914
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
|
|
27920
28915
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
27921
28916
|
}
|
|
27922
|
-
if (
|
|
28917
|
+
if (path26.basename(desiredDir) !== type) {
|
|
27923
28918
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
27924
28919
|
}
|
|
27925
28920
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -27927,11 +28922,11 @@ var DevServer = class _DevServer {
|
|
|
27927
28922
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
27928
28923
|
}
|
|
27929
28924
|
if (!fs15.existsSync(desiredDir)) {
|
|
27930
|
-
fs15.mkdirSync(
|
|
28925
|
+
fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
|
|
27931
28926
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
27932
28927
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
27933
28928
|
}
|
|
27934
|
-
const providerJson =
|
|
28929
|
+
const providerJson = path26.join(desiredDir, "provider.json");
|
|
27935
28930
|
if (!fs15.existsSync(providerJson)) {
|
|
27936
28931
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
27937
28932
|
}
|
|
@@ -27967,7 +28962,7 @@ var DevServer = class _DevServer {
|
|
|
27967
28962
|
setMode: "set_mode.js"
|
|
27968
28963
|
};
|
|
27969
28964
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
27970
|
-
const scriptsDir =
|
|
28965
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
27971
28966
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
27972
28967
|
if (latestScriptsDir) {
|
|
27973
28968
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -27978,7 +28973,7 @@ var DevServer = class _DevServer {
|
|
|
27978
28973
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
27979
28974
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
27980
28975
|
try {
|
|
27981
|
-
const content = fs15.readFileSync(
|
|
28976
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
27982
28977
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
27983
28978
|
lines.push("```javascript");
|
|
27984
28979
|
lines.push(content);
|
|
@@ -27995,7 +28990,7 @@ var DevServer = class _DevServer {
|
|
|
27995
28990
|
lines.push("");
|
|
27996
28991
|
for (const file of refFiles) {
|
|
27997
28992
|
try {
|
|
27998
|
-
const content = fs15.readFileSync(
|
|
28993
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
27999
28994
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28000
28995
|
lines.push("```javascript");
|
|
28001
28996
|
lines.push(content);
|
|
@@ -28036,10 +29031,10 @@ var DevServer = class _DevServer {
|
|
|
28036
29031
|
lines.push("");
|
|
28037
29032
|
}
|
|
28038
29033
|
}
|
|
28039
|
-
const docsDir =
|
|
29034
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28040
29035
|
const loadGuide = (name) => {
|
|
28041
29036
|
try {
|
|
28042
|
-
const p =
|
|
29037
|
+
const p = path26.join(docsDir, name);
|
|
28043
29038
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28044
29039
|
} catch {
|
|
28045
29040
|
}
|
|
@@ -28213,7 +29208,7 @@ var DevServer = class _DevServer {
|
|
|
28213
29208
|
parseApproval: "parse_approval.js"
|
|
28214
29209
|
};
|
|
28215
29210
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28216
|
-
const scriptsDir =
|
|
29211
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28217
29212
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28218
29213
|
if (latestScriptsDir) {
|
|
28219
29214
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28225,7 +29220,7 @@ var DevServer = class _DevServer {
|
|
|
28225
29220
|
if (!file.endsWith(".js")) continue;
|
|
28226
29221
|
if (!targetFileNames.has(file)) continue;
|
|
28227
29222
|
try {
|
|
28228
|
-
const content = fs15.readFileSync(
|
|
29223
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28229
29224
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28230
29225
|
lines.push("```javascript");
|
|
28231
29226
|
lines.push(content);
|
|
@@ -28241,7 +29236,7 @@ var DevServer = class _DevServer {
|
|
|
28241
29236
|
lines.push("");
|
|
28242
29237
|
for (const file of refFiles) {
|
|
28243
29238
|
try {
|
|
28244
|
-
const content = fs15.readFileSync(
|
|
29239
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28245
29240
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28246
29241
|
lines.push("```javascript");
|
|
28247
29242
|
lines.push(content);
|
|
@@ -28274,10 +29269,10 @@ var DevServer = class _DevServer {
|
|
|
28274
29269
|
lines.push("");
|
|
28275
29270
|
}
|
|
28276
29271
|
}
|
|
28277
|
-
const docsDir =
|
|
29272
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28278
29273
|
const loadGuide = (name) => {
|
|
28279
29274
|
try {
|
|
28280
|
-
const p =
|
|
29275
|
+
const p = path26.join(docsDir, name);
|
|
28281
29276
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28282
29277
|
} catch {
|
|
28283
29278
|
}
|
|
@@ -29282,48 +30277,6 @@ var SessionRegistry = class {
|
|
|
29282
30277
|
// src/boot/daemon-lifecycle.ts
|
|
29283
30278
|
init_logger();
|
|
29284
30279
|
init_config();
|
|
29285
|
-
|
|
29286
|
-
// src/mesh/mesh-events.ts
|
|
29287
|
-
init_mesh_config();
|
|
29288
|
-
init_logger();
|
|
29289
|
-
function setupMeshEventForwarding(components) {
|
|
29290
|
-
components.instanceManager.onEvent((event) => {
|
|
29291
|
-
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
29292
|
-
const instanceId = event.instanceId;
|
|
29293
|
-
if (!instanceId) return;
|
|
29294
|
-
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
29295
|
-
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
29296
|
-
const state = sourceInstance.getState();
|
|
29297
|
-
const workspace = state.workspace;
|
|
29298
|
-
if (!workspace) return;
|
|
29299
|
-
const mesh = getMeshByRepo(workspace);
|
|
29300
|
-
if (!mesh) return;
|
|
29301
|
-
const allInstances = components.instanceManager.getByCategory("cli");
|
|
29302
|
-
const coordinatorInstances = allInstances.filter((inst) => {
|
|
29303
|
-
const instState = inst.getState();
|
|
29304
|
-
if (instState.settings?.meshCoordinatorFor !== mesh.id) return false;
|
|
29305
|
-
if (instState.instanceId === instanceId) return false;
|
|
29306
|
-
return true;
|
|
29307
|
-
});
|
|
29308
|
-
if (coordinatorInstances.length === 0) return;
|
|
29309
|
-
const targetNode = mesh.nodes.find((n) => n.workspace === workspace);
|
|
29310
|
-
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : `Agent at ${workspace}`;
|
|
29311
|
-
let messageText = "";
|
|
29312
|
-
if (event.event === "agent:generating_completed") {
|
|
29313
|
-
messageText = `[System] ${nodeLabel} has completed its task and is now idle. You may use mesh_read_chat to review its progress.`;
|
|
29314
|
-
} else if (event.event === "agent:waiting_approval") {
|
|
29315
|
-
messageText = `[System] ${nodeLabel} is waiting for approval to proceed. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
29316
|
-
}
|
|
29317
|
-
if (!messageText) return;
|
|
29318
|
-
for (const coord of coordinatorInstances) {
|
|
29319
|
-
const coordState = coord.getState();
|
|
29320
|
-
LOG.info("MeshEvents", `Forwarding event from ${workspace} to coordinator ${coordState.instanceId}`);
|
|
29321
|
-
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
29322
|
-
}
|
|
29323
|
-
});
|
|
29324
|
-
}
|
|
29325
|
-
|
|
29326
|
-
// src/boot/daemon-lifecycle.ts
|
|
29327
30280
|
async function initDaemonComponents(config) {
|
|
29328
30281
|
installGlobalInterceptor();
|
|
29329
30282
|
const appConfig = loadConfig();
|
|
@@ -29629,6 +30582,7 @@ export {
|
|
|
29629
30582
|
createGitWorkspaceMonitor,
|
|
29630
30583
|
createInteractionId,
|
|
29631
30584
|
createMesh,
|
|
30585
|
+
createWorktree,
|
|
29632
30586
|
deleteMesh,
|
|
29633
30587
|
detectAllVersions,
|
|
29634
30588
|
detectCLIs,
|
|
@@ -29681,6 +30635,7 @@ export {
|
|
|
29681
30635
|
launchWithCdp,
|
|
29682
30636
|
listHostedCliRuntimes,
|
|
29683
30637
|
listMeshes,
|
|
30638
|
+
listWorktrees,
|
|
29684
30639
|
loadConfig,
|
|
29685
30640
|
loadState,
|
|
29686
30641
|
logCommand,
|
|
@@ -29700,6 +30655,7 @@ export {
|
|
|
29700
30655
|
normalizeSessionModalFields,
|
|
29701
30656
|
parsePorcelainV2Status,
|
|
29702
30657
|
parseProviderSourceConfigUpdate,
|
|
30658
|
+
parseWorktreeListOutput,
|
|
29703
30659
|
partitionSessionHostDiagnosticsSessions,
|
|
29704
30660
|
partitionSessionHostRecords,
|
|
29705
30661
|
prepareSessionChatTailUpdate,
|
|
@@ -29709,6 +30665,7 @@ export {
|
|
|
29709
30665
|
recordDebugTrace,
|
|
29710
30666
|
registerExtensionProviders,
|
|
29711
30667
|
removeNode,
|
|
30668
|
+
removeWorktree,
|
|
29712
30669
|
resetConfig,
|
|
29713
30670
|
resetDebugRuntimeConfig,
|
|
29714
30671
|
resetState,
|
|
@@ -29718,6 +30675,7 @@ export {
|
|
|
29718
30675
|
resolveGitRepository,
|
|
29719
30676
|
resolveSessionHostAppName,
|
|
29720
30677
|
resolveSessionHostAppNameResolution,
|
|
30678
|
+
resolveWorktreePath,
|
|
29721
30679
|
runAsyncBatch,
|
|
29722
30680
|
runGit,
|
|
29723
30681
|
saveConfig,
|