@adhdev/daemon-core 0.9.76-rc.4 → 0.9.76-rc.40
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 +1318 -426
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1345 -457
- 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 +22 -1
- package/package.json +3 -4
- package/src/cli-adapters/provider-cli-adapter.ts +13 -6
- package/src/cli-adapters/provider-cli-runtime.ts +3 -2
- package/src/commands/chat-commands.ts +76 -5
- 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 +505 -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 +55 -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 +24 -1
- 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}`);
|
|
@@ -4547,6 +4707,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
|
4547
4707
|
"dirty_index_required",
|
|
4548
4708
|
"conflict",
|
|
4549
4709
|
"invalid_args",
|
|
4710
|
+
"nothing_to_commit",
|
|
4550
4711
|
"git_command_failed"
|
|
4551
4712
|
]);
|
|
4552
4713
|
function failure(reason, error) {
|
|
@@ -4791,7 +4952,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
|
4791
4952
|
} catch (err) {
|
|
4792
4953
|
const output = (err?.stdout || "") + (err?.stderr || "");
|
|
4793
4954
|
if (/nothing to commit/i.test(output)) {
|
|
4794
|
-
throw new GitCommandError("
|
|
4955
|
+
throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
|
|
4956
|
+
stdout: err?.stdout,
|
|
4957
|
+
stderr: err?.stderr
|
|
4958
|
+
});
|
|
4795
4959
|
}
|
|
4796
4960
|
throw err;
|
|
4797
4961
|
}
|
|
@@ -4983,20 +5147,23 @@ var TurnSnapshotTracker = class {
|
|
|
4983
5147
|
}
|
|
4984
5148
|
};
|
|
4985
5149
|
|
|
5150
|
+
// src/git/index.ts
|
|
5151
|
+
init_git_worktree();
|
|
5152
|
+
|
|
4986
5153
|
// src/index.ts
|
|
4987
5154
|
init_config();
|
|
4988
5155
|
|
|
4989
5156
|
// src/config/workspaces.ts
|
|
4990
5157
|
import * as fs from "fs";
|
|
4991
5158
|
import * as os from "os";
|
|
4992
|
-
import * as
|
|
5159
|
+
import * as path5 from "path";
|
|
4993
5160
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4994
5161
|
var MAX_WORKSPACES = 50;
|
|
4995
5162
|
function expandPath(p) {
|
|
4996
5163
|
const t = (p || "").trim();
|
|
4997
5164
|
if (!t) return "";
|
|
4998
|
-
if (t.startsWith("~")) return
|
|
4999
|
-
return
|
|
5165
|
+
if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5166
|
+
return path5.resolve(t);
|
|
5000
5167
|
}
|
|
5001
5168
|
function validateWorkspacePath(absPath) {
|
|
5002
5169
|
try {
|
|
@@ -5010,7 +5177,7 @@ function validateWorkspacePath(absPath) {
|
|
|
5010
5177
|
}
|
|
5011
5178
|
}
|
|
5012
5179
|
function defaultWorkspaceLabel(absPath) {
|
|
5013
|
-
const base =
|
|
5180
|
+
const base = path5.basename(absPath) || absPath;
|
|
5014
5181
|
return base;
|
|
5015
5182
|
}
|
|
5016
5183
|
function getDefaultWorkspacePath(config) {
|
|
@@ -5101,9 +5268,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
5101
5268
|
return getDefaultWorkspacePath(config) || void 0;
|
|
5102
5269
|
}
|
|
5103
5270
|
function findWorkspaceByPath(config, rawPath) {
|
|
5104
|
-
const abs =
|
|
5271
|
+
const abs = path5.resolve(expandPath(rawPath));
|
|
5105
5272
|
if (!abs) return void 0;
|
|
5106
|
-
return (config.workspaces || []).find((w) =>
|
|
5273
|
+
return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
|
|
5107
5274
|
}
|
|
5108
5275
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
5109
5276
|
const abs = expandPath(rawPath);
|
|
@@ -5119,7 +5286,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
5119
5286
|
const v = validateWorkspacePath(abs);
|
|
5120
5287
|
if (!v.ok) return { error: v.error };
|
|
5121
5288
|
const list = [...config.workspaces || []];
|
|
5122
|
-
if (list.some((w) =>
|
|
5289
|
+
if (list.some((w) => path5.resolve(w.path) === abs)) {
|
|
5123
5290
|
return { error: "Workspace already in list" };
|
|
5124
5291
|
}
|
|
5125
5292
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -5153,7 +5320,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
5153
5320
|
}
|
|
5154
5321
|
|
|
5155
5322
|
// src/config/recent-activity.ts
|
|
5156
|
-
import * as
|
|
5323
|
+
import * as path6 from "path";
|
|
5157
5324
|
|
|
5158
5325
|
// src/providers/summary-metadata.ts
|
|
5159
5326
|
function normalizeSummaryItem(item) {
|
|
@@ -5222,9 +5389,9 @@ var MAX_ACTIVITY = 30;
|
|
|
5222
5389
|
function normalizeWorkspace(workspace) {
|
|
5223
5390
|
if (!workspace) return "";
|
|
5224
5391
|
try {
|
|
5225
|
-
return
|
|
5392
|
+
return path6.resolve(expandPath(workspace));
|
|
5226
5393
|
} catch {
|
|
5227
|
-
return
|
|
5394
|
+
return path6.resolve(workspace);
|
|
5228
5395
|
}
|
|
5229
5396
|
}
|
|
5230
5397
|
function buildRecentActivityKey(entry) {
|
|
@@ -5392,14 +5559,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5392
5559
|
}
|
|
5393
5560
|
|
|
5394
5561
|
// src/config/saved-sessions.ts
|
|
5395
|
-
import * as
|
|
5562
|
+
import * as path7 from "path";
|
|
5396
5563
|
var MAX_SAVED_SESSIONS = 500;
|
|
5397
5564
|
function normalizeWorkspace2(workspace) {
|
|
5398
5565
|
if (!workspace) return "";
|
|
5399
5566
|
try {
|
|
5400
|
-
return
|
|
5567
|
+
return path7.resolve(expandPath(workspace));
|
|
5401
5568
|
} catch {
|
|
5402
|
-
return
|
|
5569
|
+
return path7.resolve(workspace);
|
|
5403
5570
|
}
|
|
5404
5571
|
}
|
|
5405
5572
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5505,8 +5672,8 @@ async function syncMeshes(transport) {
|
|
|
5505
5672
|
|
|
5506
5673
|
// src/config/state-store.ts
|
|
5507
5674
|
init_config();
|
|
5508
|
-
import { existsSync as
|
|
5509
|
-
import { join as
|
|
5675
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5676
|
+
import { join as join5 } from "path";
|
|
5510
5677
|
var DEFAULT_STATE = {
|
|
5511
5678
|
recentActivity: [],
|
|
5512
5679
|
savedProviderSessions: [],
|
|
@@ -5519,7 +5686,7 @@ function isPlainObject2(value) {
|
|
|
5519
5686
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5520
5687
|
}
|
|
5521
5688
|
function getStatePath() {
|
|
5522
|
-
return
|
|
5689
|
+
return join5(getConfigDir(), "state.json");
|
|
5523
5690
|
}
|
|
5524
5691
|
function normalizeState(raw) {
|
|
5525
5692
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -5555,7 +5722,7 @@ function normalizeState(raw) {
|
|
|
5555
5722
|
}
|
|
5556
5723
|
function loadState() {
|
|
5557
5724
|
const statePath = getStatePath();
|
|
5558
|
-
if (!
|
|
5725
|
+
if (!existsSync5(statePath)) {
|
|
5559
5726
|
return { ...DEFAULT_STATE };
|
|
5560
5727
|
}
|
|
5561
5728
|
try {
|
|
@@ -5576,9 +5743,9 @@ function resetState() {
|
|
|
5576
5743
|
|
|
5577
5744
|
// src/detection/ide-detector.ts
|
|
5578
5745
|
import { execSync } from "child_process";
|
|
5579
|
-
import { existsSync as
|
|
5746
|
+
import { existsSync as existsSync6 } from "fs";
|
|
5580
5747
|
import { platform, homedir as homedir3 } from "os";
|
|
5581
|
-
import * as
|
|
5748
|
+
import * as path8 from "path";
|
|
5582
5749
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5583
5750
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5584
5751
|
function registerIDEDefinition(def) {
|
|
@@ -5597,10 +5764,10 @@ function getMergedDefinitions() {
|
|
|
5597
5764
|
function findCliCommand(command) {
|
|
5598
5765
|
const trimmed = String(command || "").trim();
|
|
5599
5766
|
if (!trimmed) return null;
|
|
5600
|
-
if (
|
|
5601
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5602
|
-
const resolved =
|
|
5603
|
-
return
|
|
5767
|
+
if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
5768
|
+
const candidate = trimmed.startsWith("~") ? path8.join(homedir3(), trimmed.slice(1)) : trimmed;
|
|
5769
|
+
const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
|
|
5770
|
+
return existsSync6(resolved) ? resolved : null;
|
|
5604
5771
|
}
|
|
5605
5772
|
try {
|
|
5606
5773
|
const result = execSync(
|
|
@@ -5627,31 +5794,31 @@ function getIdeVersion(cliCommand) {
|
|
|
5627
5794
|
function checkPathExists(paths) {
|
|
5628
5795
|
const home = homedir3();
|
|
5629
5796
|
for (const p of paths) {
|
|
5630
|
-
const normalized = p.startsWith("~") ?
|
|
5797
|
+
const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
|
|
5631
5798
|
if (normalized.includes("*")) {
|
|
5632
5799
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5633
5800
|
const resolved = normalized.replace("*", username);
|
|
5634
|
-
if (
|
|
5801
|
+
if (existsSync6(resolved)) return resolved;
|
|
5635
5802
|
} else {
|
|
5636
|
-
if (
|
|
5803
|
+
if (existsSync6(normalized)) return normalized;
|
|
5637
5804
|
}
|
|
5638
5805
|
}
|
|
5639
5806
|
return null;
|
|
5640
5807
|
}
|
|
5641
5808
|
async function detectIDEs(providerLoader) {
|
|
5642
|
-
const
|
|
5809
|
+
const os22 = platform();
|
|
5643
5810
|
const results = [];
|
|
5644
5811
|
for (const def of getMergedDefinitions()) {
|
|
5645
5812
|
const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
|
|
5646
|
-
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[
|
|
5813
|
+
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
|
|
5647
5814
|
let resolvedCli = cliPath;
|
|
5648
|
-
if (!resolvedCli && appPath &&
|
|
5815
|
+
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
5649
5816
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
5650
|
-
if (
|
|
5817
|
+
if (existsSync6(bundledCli)) resolvedCli = bundledCli;
|
|
5651
5818
|
}
|
|
5652
|
-
if (!resolvedCli && appPath &&
|
|
5653
|
-
const { dirname:
|
|
5654
|
-
const appDir =
|
|
5819
|
+
if (!resolvedCli && appPath && os22 === "win32") {
|
|
5820
|
+
const { dirname: dirname9 } = await import("path");
|
|
5821
|
+
const appDir = dirname9(appPath);
|
|
5655
5822
|
const candidates = [
|
|
5656
5823
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
5657
5824
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -5660,13 +5827,13 @@ async function detectIDEs(providerLoader) {
|
|
|
5660
5827
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
5661
5828
|
];
|
|
5662
5829
|
for (const c of candidates) {
|
|
5663
|
-
if (
|
|
5830
|
+
if (existsSync6(c)) {
|
|
5664
5831
|
resolvedCli = c;
|
|
5665
5832
|
break;
|
|
5666
5833
|
}
|
|
5667
5834
|
}
|
|
5668
5835
|
}
|
|
5669
|
-
const installed =
|
|
5836
|
+
const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
|
|
5670
5837
|
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
5671
5838
|
results.push({
|
|
5672
5839
|
id: def.id,
|
|
@@ -5685,8 +5852,8 @@ async function detectIDEs(providerLoader) {
|
|
|
5685
5852
|
// src/detection/cli-detector.ts
|
|
5686
5853
|
import { exec } from "child_process";
|
|
5687
5854
|
import * as os2 from "os";
|
|
5688
|
-
import * as
|
|
5689
|
-
import { existsSync as
|
|
5855
|
+
import * as path9 from "path";
|
|
5856
|
+
import { existsSync as existsSync7 } from "fs";
|
|
5690
5857
|
function parseVersion(raw) {
|
|
5691
5858
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
5692
5859
|
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
@@ -5698,19 +5865,19 @@ function shellQuote(value) {
|
|
|
5698
5865
|
function expandHome(value) {
|
|
5699
5866
|
const trimmed = value.trim();
|
|
5700
5867
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5701
|
-
return
|
|
5868
|
+
return path9.join(os2.homedir(), trimmed.slice(1));
|
|
5702
5869
|
}
|
|
5703
5870
|
function isExplicitCommandPath(command) {
|
|
5704
5871
|
const trimmed = command.trim();
|
|
5705
|
-
return
|
|
5872
|
+
return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5706
5873
|
}
|
|
5707
5874
|
function resolveCommandPath(command) {
|
|
5708
5875
|
const trimmed = command.trim();
|
|
5709
5876
|
if (!trimmed) return null;
|
|
5710
5877
|
if (isExplicitCommandPath(trimmed)) {
|
|
5711
5878
|
const expanded = expandHome(trimmed);
|
|
5712
|
-
const candidate =
|
|
5713
|
-
return
|
|
5879
|
+
const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
|
|
5880
|
+
return existsSync7(candidate) ? candidate : null;
|
|
5714
5881
|
}
|
|
5715
5882
|
return null;
|
|
5716
5883
|
}
|
|
@@ -7978,9 +8145,9 @@ ${cleanBody}`;
|
|
|
7978
8145
|
|
|
7979
8146
|
// src/config/chat-history.ts
|
|
7980
8147
|
import * as fs3 from "fs";
|
|
7981
|
-
import * as
|
|
8148
|
+
import * as path11 from "path";
|
|
7982
8149
|
import * as os5 from "os";
|
|
7983
|
-
var HISTORY_DIR =
|
|
8150
|
+
var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
|
|
7984
8151
|
var RETAIN_DAYS = 30;
|
|
7985
8152
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
7986
8153
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -8143,7 +8310,7 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
8143
8310
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
8144
8311
|
return new Map(files.map((file) => {
|
|
8145
8312
|
try {
|
|
8146
|
-
const stat2 = fs3.statSync(
|
|
8313
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8147
8314
|
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
8148
8315
|
} catch {
|
|
8149
8316
|
return [file, `${file}:missing`];
|
|
@@ -8154,7 +8321,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
8154
8321
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
8155
8322
|
}
|
|
8156
8323
|
function getSavedHistoryIndexFilePath(dir) {
|
|
8157
|
-
return
|
|
8324
|
+
return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
8158
8325
|
}
|
|
8159
8326
|
function getSavedHistoryIndexLockPath(dir) {
|
|
8160
8327
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -8256,7 +8423,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
8256
8423
|
}
|
|
8257
8424
|
for (const file of Array.from(currentEntries.keys())) {
|
|
8258
8425
|
if (incomingFiles.has(file)) continue;
|
|
8259
|
-
if (!fs3.existsSync(
|
|
8426
|
+
if (!fs3.existsSync(path11.join(dir, file))) {
|
|
8260
8427
|
currentEntries.delete(file);
|
|
8261
8428
|
}
|
|
8262
8429
|
}
|
|
@@ -8282,7 +8449,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8282
8449
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8283
8450
|
const files = listHistoryFiles(dir);
|
|
8284
8451
|
for (const file of files) {
|
|
8285
|
-
const stat2 = fs3.statSync(
|
|
8452
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8286
8453
|
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
8287
8454
|
}
|
|
8288
8455
|
return false;
|
|
@@ -8292,14 +8459,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8292
8459
|
}
|
|
8293
8460
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
8294
8461
|
try {
|
|
8295
|
-
const stat2 = fs3.statSync(
|
|
8462
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8296
8463
|
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
8297
8464
|
} catch {
|
|
8298
8465
|
return `${file}:missing`;
|
|
8299
8466
|
}
|
|
8300
8467
|
}
|
|
8301
8468
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
8302
|
-
const filePath =
|
|
8469
|
+
const filePath = path11.join(dir, file);
|
|
8303
8470
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
8304
8471
|
const currentEntry = entries.get(file) || null;
|
|
8305
8472
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -8372,7 +8539,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
8372
8539
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
8373
8540
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
8374
8541
|
if (!historySessionId) return null;
|
|
8375
|
-
const filePath =
|
|
8542
|
+
const filePath = path11.join(dir, file);
|
|
8376
8543
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8377
8544
|
const lines = content.split("\n").filter(Boolean);
|
|
8378
8545
|
let messageCount = 0;
|
|
@@ -8459,7 +8626,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
8459
8626
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
8460
8627
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
8461
8628
|
for (const file of files.slice().sort()) {
|
|
8462
|
-
const filePath =
|
|
8629
|
+
const filePath = path11.join(dir, file);
|
|
8463
8630
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
8464
8631
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
8465
8632
|
const persisted = persistedEntries.get(file);
|
|
@@ -8579,12 +8746,12 @@ var ChatHistoryWriter = class {
|
|
|
8579
8746
|
});
|
|
8580
8747
|
}
|
|
8581
8748
|
if (newMessages.length === 0) return;
|
|
8582
|
-
const dir =
|
|
8749
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8583
8750
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8584
8751
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8585
8752
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
8586
8753
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
8587
|
-
const filePath =
|
|
8754
|
+
const filePath = path11.join(dir, fileName);
|
|
8588
8755
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
8589
8756
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
8590
8757
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -8675,11 +8842,11 @@ var ChatHistoryWriter = class {
|
|
|
8675
8842
|
const ws = String(workspace || "").trim();
|
|
8676
8843
|
if (!id || !ws) return;
|
|
8677
8844
|
try {
|
|
8678
|
-
const dir =
|
|
8845
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8679
8846
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8680
8847
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8681
8848
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
8682
|
-
const filePath =
|
|
8849
|
+
const filePath = path11.join(dir, fileName);
|
|
8683
8850
|
const record = {
|
|
8684
8851
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8685
8852
|
receivedAt: Date.now(),
|
|
@@ -8725,14 +8892,14 @@ var ChatHistoryWriter = class {
|
|
|
8725
8892
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8726
8893
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8727
8894
|
}
|
|
8728
|
-
const dir =
|
|
8895
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8729
8896
|
if (!fs3.existsSync(dir)) return;
|
|
8730
8897
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8731
8898
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8732
8899
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8733
8900
|
for (const file of files) {
|
|
8734
|
-
const sourcePath =
|
|
8735
|
-
const targetPath =
|
|
8901
|
+
const sourcePath = path11.join(dir, file);
|
|
8902
|
+
const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8736
8903
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8737
8904
|
const rewritten = sourceLines.map((line) => {
|
|
8738
8905
|
try {
|
|
@@ -8766,13 +8933,13 @@ var ChatHistoryWriter = class {
|
|
|
8766
8933
|
const sessionId = String(historySessionId || "").trim();
|
|
8767
8934
|
if (!sessionId) return;
|
|
8768
8935
|
try {
|
|
8769
|
-
const dir =
|
|
8936
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8770
8937
|
if (!fs3.existsSync(dir)) return;
|
|
8771
8938
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8772
8939
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8773
8940
|
const seen = /* @__PURE__ */ new Set();
|
|
8774
8941
|
for (const file of files) {
|
|
8775
|
-
const filePath =
|
|
8942
|
+
const filePath = path11.join(dir, file);
|
|
8776
8943
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8777
8944
|
const next = [];
|
|
8778
8945
|
for (const line of lines) {
|
|
@@ -8826,11 +8993,11 @@ var ChatHistoryWriter = class {
|
|
|
8826
8993
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
8827
8994
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
8828
8995
|
for (const dir of agentDirs) {
|
|
8829
|
-
const dirPath =
|
|
8996
|
+
const dirPath = path11.join(HISTORY_DIR, dir.name);
|
|
8830
8997
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
8831
8998
|
let removedAny = false;
|
|
8832
8999
|
for (const file of files) {
|
|
8833
|
-
const filePath =
|
|
9000
|
+
const filePath = path11.join(dirPath, file);
|
|
8834
9001
|
const stat2 = fs3.statSync(filePath);
|
|
8835
9002
|
if (stat2.mtimeMs < cutoff) {
|
|
8836
9003
|
fs3.unlinkSync(filePath);
|
|
@@ -8880,13 +9047,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8880
9047
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8881
9048
|
try {
|
|
8882
9049
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8883
|
-
const dir =
|
|
9050
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8884
9051
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
8885
9052
|
const files = listHistoryFiles(dir, historySessionId);
|
|
8886
9053
|
const allMessages = [];
|
|
8887
9054
|
const seen = /* @__PURE__ */ new Set();
|
|
8888
9055
|
for (const file of files) {
|
|
8889
|
-
const filePath =
|
|
9056
|
+
const filePath = path11.join(dir, file);
|
|
8890
9057
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8891
9058
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
8892
9059
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8910,7 +9077,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8910
9077
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
8911
9078
|
try {
|
|
8912
9079
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8913
|
-
const dir =
|
|
9080
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8914
9081
|
if (!fs3.existsSync(dir)) {
|
|
8915
9082
|
savedHistorySessionCache.delete(sanitized);
|
|
8916
9083
|
return { sessions: [], hasMore: false };
|
|
@@ -8971,11 +9138,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8971
9138
|
}
|
|
8972
9139
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8973
9140
|
try {
|
|
8974
|
-
const dir =
|
|
9141
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8975
9142
|
if (!fs3.existsSync(dir)) return null;
|
|
8976
9143
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
8977
9144
|
for (const file of files) {
|
|
8978
|
-
const lines = fs3.readFileSync(
|
|
9145
|
+
const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
8979
9146
|
for (const line of lines) {
|
|
8980
9147
|
try {
|
|
8981
9148
|
const parsed = JSON.parse(line);
|
|
@@ -8995,16 +9162,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
8995
9162
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
8996
9163
|
if (records.length === 0) return false;
|
|
8997
9164
|
try {
|
|
8998
|
-
const dir =
|
|
9165
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8999
9166
|
fs3.mkdirSync(dir, { recursive: true });
|
|
9000
9167
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
9001
9168
|
for (const file of fs3.readdirSync(dir)) {
|
|
9002
9169
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
9003
|
-
fs3.unlinkSync(
|
|
9170
|
+
fs3.unlinkSync(path11.join(dir, file));
|
|
9004
9171
|
}
|
|
9005
9172
|
}
|
|
9006
9173
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
9007
|
-
const filePath =
|
|
9174
|
+
const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
9008
9175
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
9009
9176
|
`, "utf-8");
|
|
9010
9177
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -10999,6 +11166,14 @@ function getActiveChatOptions(profile) {
|
|
|
10999
11166
|
if (profile === "full") return {};
|
|
11000
11167
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
11001
11168
|
}
|
|
11169
|
+
function resolveSessionStatus(activeChat, providerStatus) {
|
|
11170
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
11171
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
11172
|
+
if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
|
|
11173
|
+
if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
|
|
11174
|
+
if (topLevelStatus !== "idle") return topLevelStatus;
|
|
11175
|
+
return chatStatus;
|
|
11176
|
+
}
|
|
11002
11177
|
function shouldIncludeSessionControls(profile) {
|
|
11003
11178
|
return profile !== "live";
|
|
11004
11179
|
}
|
|
@@ -11077,9 +11252,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11077
11252
|
providerName: state.name,
|
|
11078
11253
|
kind: "workspace",
|
|
11079
11254
|
transport: "cdp-page",
|
|
11080
|
-
status:
|
|
11081
|
-
activeModal: activeChat?.activeModal || null
|
|
11082
|
-
}),
|
|
11255
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11083
11256
|
title,
|
|
11084
11257
|
workspace,
|
|
11085
11258
|
...git && { git },
|
|
@@ -11114,9 +11287,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11114
11287
|
providerSessionId: ext.providerSessionId,
|
|
11115
11288
|
kind: "agent",
|
|
11116
11289
|
transport: "cdp-webview",
|
|
11117
|
-
status:
|
|
11118
|
-
activeModal: activeChat?.activeModal || null
|
|
11119
|
-
}),
|
|
11290
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
11120
11291
|
title: activeChat?.title || ext.name,
|
|
11121
11292
|
workspace,
|
|
11122
11293
|
...git && { git },
|
|
@@ -11166,9 +11337,7 @@ function buildCliSession(state, options) {
|
|
|
11166
11337
|
providerSessionId: state.providerSessionId,
|
|
11167
11338
|
kind: "agent",
|
|
11168
11339
|
transport: "pty",
|
|
11169
|
-
status:
|
|
11170
|
-
activeModal: activeChat?.activeModal || null
|
|
11171
|
-
}),
|
|
11340
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11172
11341
|
title: activeChat?.title || state.name,
|
|
11173
11342
|
workspace,
|
|
11174
11343
|
...git && { git },
|
|
@@ -11216,9 +11385,7 @@ function buildAcpSession(state, options) {
|
|
|
11216
11385
|
providerName: state.name,
|
|
11217
11386
|
kind: "agent",
|
|
11218
11387
|
transport: "acp",
|
|
11219
|
-
status:
|
|
11220
|
-
activeModal: activeChat?.activeModal || null
|
|
11221
|
-
}),
|
|
11388
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11222
11389
|
title: activeChat?.title || state.name,
|
|
11223
11390
|
workspace,
|
|
11224
11391
|
...git && { git },
|
|
@@ -11341,7 +11508,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
11341
11508
|
// src/commands/chat-commands.ts
|
|
11342
11509
|
import * as fs4 from "fs";
|
|
11343
11510
|
import * as os6 from "os";
|
|
11344
|
-
import * as
|
|
11511
|
+
import * as path12 from "path";
|
|
11345
11512
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
11346
11513
|
|
|
11347
11514
|
// src/providers/provider-input-support.ts
|
|
@@ -11704,6 +11871,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
11704
11871
|
return raw;
|
|
11705
11872
|
}
|
|
11706
11873
|
}
|
|
11874
|
+
function isGeneratingLikeStatus(status) {
|
|
11875
|
+
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
11876
|
+
}
|
|
11877
|
+
function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
11878
|
+
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
11879
|
+
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
11880
|
+
const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
|
|
11881
|
+
if (adapterRawStatus !== "idle") return false;
|
|
11882
|
+
if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
|
|
11883
|
+
return true;
|
|
11884
|
+
}
|
|
11885
|
+
function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
11886
|
+
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
11887
|
+
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
11888
|
+
}
|
|
11889
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
11890
|
+
if (status !== "idle") return messages;
|
|
11891
|
+
return messages.map((message) => {
|
|
11892
|
+
const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
11893
|
+
const hasStreamingMeta = meta?.streaming === true;
|
|
11894
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
11895
|
+
return {
|
|
11896
|
+
...message,
|
|
11897
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
11898
|
+
...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
|
|
11899
|
+
};
|
|
11900
|
+
});
|
|
11901
|
+
}
|
|
11707
11902
|
function buildReadChatCommandResult(payload, args) {
|
|
11708
11903
|
let validatedPayload;
|
|
11709
11904
|
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
@@ -11852,7 +12047,7 @@ function buildDebugBundleText(bundle) {
|
|
|
11852
12047
|
}
|
|
11853
12048
|
function getChatDebugBundleDir() {
|
|
11854
12049
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
11855
|
-
return override ||
|
|
12050
|
+
return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
11856
12051
|
}
|
|
11857
12052
|
function safeBundleIdSegment(value, fallback) {
|
|
11858
12053
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -11868,6 +12063,14 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
11868
12063
|
const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
|
|
11869
12064
|
const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
|
|
11870
12065
|
const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
|
|
12066
|
+
const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
|
|
12067
|
+
const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
|
|
12068
|
+
const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
|
|
12069
|
+
const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
|
|
12070
|
+
const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
|
|
12071
|
+
const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
|
|
12072
|
+
const cliStatus = typeof cli?.status === "string" ? cli.status : "";
|
|
12073
|
+
const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
|
|
11871
12074
|
return {
|
|
11872
12075
|
createdAt: bundle.createdAt,
|
|
11873
12076
|
targetSessionId: target.targetSessionId,
|
|
@@ -11876,8 +12079,22 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
11876
12079
|
readChatSuccess: readChat.success,
|
|
11877
12080
|
readChatStatus: readChat.status,
|
|
11878
12081
|
readChatTotalMessages: readChat.totalMessages,
|
|
12082
|
+
readChatReturnedMessages,
|
|
11879
12083
|
cliStatus: cli?.status,
|
|
12084
|
+
cliParsedStatus: cliParsedStatus || void 0,
|
|
11880
12085
|
cliMessageCount: cli?.messageCount,
|
|
12086
|
+
cliParsedMessageCount,
|
|
12087
|
+
cliPartialResponseChars: cliPartialResponse.length,
|
|
12088
|
+
parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
|
|
12089
|
+
parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
|
|
12090
|
+
readChatDebug: Object.keys(debugReadChat).length ? {
|
|
12091
|
+
adapterStatus: debugReadChat.adapterStatus,
|
|
12092
|
+
parsedStatus: debugReadChat.parsedStatus,
|
|
12093
|
+
returnedStatus: debugReadChat.returnedStatus,
|
|
12094
|
+
parsedMsgCount: debugReadChat.parsedMsgCount,
|
|
12095
|
+
returnedMsgCount: debugReadChat.returnedMsgCount,
|
|
12096
|
+
shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
|
|
12097
|
+
} : void 0,
|
|
11881
12098
|
hasFrontendSnapshot: !!frontend
|
|
11882
12099
|
};
|
|
11883
12100
|
}
|
|
@@ -11885,7 +12102,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
11885
12102
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
11886
12103
|
const dir = getChatDebugBundleDir();
|
|
11887
12104
|
fs4.mkdirSync(dir, { recursive: true });
|
|
11888
|
-
const savedPath =
|
|
12105
|
+
const savedPath = path12.join(dir, `${bundleId}.json`);
|
|
11889
12106
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
11890
12107
|
`;
|
|
11891
12108
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -12115,7 +12332,7 @@ async function handleChatHistory(h, args) {
|
|
|
12115
12332
|
}
|
|
12116
12333
|
}
|
|
12117
12334
|
async function handleReadChat(h, args) {
|
|
12118
|
-
const provider = h.getProvider(args?.agentType);
|
|
12335
|
+
const provider = h.getProvider(args?.agentType || args?.providerType);
|
|
12119
12336
|
const transport = getTargetTransport(h, provider);
|
|
12120
12337
|
const historySessionId = getHistorySessionId(h, args);
|
|
12121
12338
|
const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
|
|
@@ -12142,10 +12359,13 @@ async function handleReadChat(h, args) {
|
|
|
12142
12359
|
const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
12143
12360
|
const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
12144
12361
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
12145
|
-
const returnedStatus = parsedRecord.status
|
|
12146
|
-
|
|
12362
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
12363
|
+
const runtimeMessageMerger = getTargetInstance(h, args);
|
|
12364
|
+
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
|
|
12365
|
+
const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
|
|
12366
|
+
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
12367
|
return buildReadChatCommandResult({
|
|
12148
|
-
messages:
|
|
12368
|
+
messages: returnedMessages,
|
|
12149
12369
|
status: returnedStatus,
|
|
12150
12370
|
activeModal,
|
|
12151
12371
|
debugReadChat: {
|
|
@@ -12156,7 +12376,7 @@ async function handleReadChat(h, args) {
|
|
|
12156
12376
|
returnedStatus: String(returnedStatus || ""),
|
|
12157
12377
|
shouldPreferAdapterMessages: false,
|
|
12158
12378
|
parsedMsgCount: parsedRecord.messages.length,
|
|
12159
|
-
returnedMsgCount:
|
|
12379
|
+
returnedMsgCount: returnedMessages.length
|
|
12160
12380
|
},
|
|
12161
12381
|
...title ? { title } : {},
|
|
12162
12382
|
...providerSessionId ? { providerSessionId } : {},
|
|
@@ -13029,7 +13249,7 @@ async function handleResolveAction(h, args) {
|
|
|
13029
13249
|
|
|
13030
13250
|
// src/commands/cdp-commands.ts
|
|
13031
13251
|
import * as fs5 from "fs";
|
|
13032
|
-
import * as
|
|
13252
|
+
import * as path13 from "path";
|
|
13033
13253
|
import * as os7 from "os";
|
|
13034
13254
|
var KEY_TO_VK = {
|
|
13035
13255
|
Backspace: 8,
|
|
@@ -13286,25 +13506,25 @@ function resolveSafePath(requestedPath) {
|
|
|
13286
13506
|
const inputPath = rawPath || ".";
|
|
13287
13507
|
const home = os7.homedir();
|
|
13288
13508
|
if (inputPath.startsWith("~")) {
|
|
13289
|
-
return
|
|
13509
|
+
return path13.resolve(path13.join(home, inputPath.slice(1)));
|
|
13290
13510
|
}
|
|
13291
13511
|
if (process.platform === "win32") {
|
|
13292
13512
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
13293
|
-
if (
|
|
13294
|
-
return
|
|
13513
|
+
if (path13.win32.isAbsolute(normalized)) {
|
|
13514
|
+
return path13.win32.normalize(normalized);
|
|
13295
13515
|
}
|
|
13296
|
-
return
|
|
13516
|
+
return path13.win32.resolve(normalized);
|
|
13297
13517
|
}
|
|
13298
|
-
if (
|
|
13299
|
-
return
|
|
13518
|
+
if (path13.isAbsolute(inputPath)) {
|
|
13519
|
+
return path13.normalize(inputPath);
|
|
13300
13520
|
}
|
|
13301
|
-
return
|
|
13521
|
+
return path13.resolve(inputPath);
|
|
13302
13522
|
}
|
|
13303
13523
|
function listDirectoryEntriesSafe(dirPath) {
|
|
13304
13524
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
13305
13525
|
const files = [];
|
|
13306
13526
|
for (const entry of entries) {
|
|
13307
|
-
const entryPath =
|
|
13527
|
+
const entryPath = path13.join(dirPath, entry.name);
|
|
13308
13528
|
try {
|
|
13309
13529
|
if (entry.isDirectory()) {
|
|
13310
13530
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -13358,7 +13578,7 @@ async function handleFileRead(h, args) {
|
|
|
13358
13578
|
async function handleFileWrite(h, args) {
|
|
13359
13579
|
try {
|
|
13360
13580
|
const filePath = resolveSafePath(args?.path);
|
|
13361
|
-
fs5.mkdirSync(
|
|
13581
|
+
fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
13362
13582
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
13363
13583
|
return { success: true, path: filePath };
|
|
13364
13584
|
} catch (e) {
|
|
@@ -14142,9 +14362,11 @@ var DaemonCommandHandler = class {
|
|
|
14142
14362
|
}
|
|
14143
14363
|
const sessionLookupFailed = !!targetSessionId && !session;
|
|
14144
14364
|
const managerKey = this.extractIdeType(args, sessionLookupFailed);
|
|
14145
|
-
let providerType;
|
|
14365
|
+
let providerType = args?.agentType || args?.providerType;
|
|
14146
14366
|
if (!sessionLookupFailed) {
|
|
14147
|
-
providerType = session?.providerType ||
|
|
14367
|
+
providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
|
|
14368
|
+
} else if (!providerType) {
|
|
14369
|
+
providerType = this.inferProviderType(managerKey);
|
|
14148
14370
|
}
|
|
14149
14371
|
return { session, managerKey, providerType, sessionLookupFailed };
|
|
14150
14372
|
}
|
|
@@ -14224,7 +14446,8 @@ var DaemonCommandHandler = class {
|
|
|
14224
14446
|
"pty_resize",
|
|
14225
14447
|
"invoke_provider_script"
|
|
14226
14448
|
]);
|
|
14227
|
-
|
|
14449
|
+
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);
|
|
14450
|
+
if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
|
|
14228
14451
|
const result2 = {
|
|
14229
14452
|
success: false,
|
|
14230
14453
|
error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
|
|
@@ -14478,16 +14701,16 @@ var DaemonCommandHandler = class {
|
|
|
14478
14701
|
// src/commands/cli-manager.ts
|
|
14479
14702
|
init_provider_cli_adapter();
|
|
14480
14703
|
import * as os13 from "os";
|
|
14481
|
-
import * as
|
|
14704
|
+
import * as path17 from "path";
|
|
14482
14705
|
import * as crypto4 from "crypto";
|
|
14483
|
-
import { existsSync as
|
|
14706
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
14484
14707
|
import { execFileSync } from "child_process";
|
|
14485
14708
|
import chalk from "chalk";
|
|
14486
14709
|
init_config();
|
|
14487
14710
|
|
|
14488
14711
|
// src/providers/cli-provider-instance.ts
|
|
14489
14712
|
import * as os12 from "os";
|
|
14490
|
-
import * as
|
|
14713
|
+
import * as path16 from "path";
|
|
14491
14714
|
import * as crypto3 from "crypto";
|
|
14492
14715
|
import * as fs6 from "fs";
|
|
14493
14716
|
import { createRequire } from "module";
|
|
@@ -14546,7 +14769,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
14546
14769
|
var CachedDatabaseSync = null;
|
|
14547
14770
|
function getDatabaseSync() {
|
|
14548
14771
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
14549
|
-
const requireFn = typeof __require === "function" ? __require : createRequire(
|
|
14772
|
+
const requireFn = typeof __require === "function" ? __require : createRequire(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
14550
14773
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
14551
14774
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
14552
14775
|
if (!CachedDatabaseSync) {
|
|
@@ -14599,7 +14822,7 @@ var CliProviderInstance = class {
|
|
|
14599
14822
|
this.providerSessionId = options?.providerSessionId;
|
|
14600
14823
|
this.launchMode = options?.launchMode || "new";
|
|
14601
14824
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
14602
|
-
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
|
|
14825
|
+
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
14603
14826
|
this.monitor = new StatusMonitor();
|
|
14604
14827
|
this.historyWriter = new ChatHistoryWriter();
|
|
14605
14828
|
}
|
|
@@ -15076,7 +15299,19 @@ var CliProviderInstance = class {
|
|
|
15076
15299
|
}
|
|
15077
15300
|
}
|
|
15078
15301
|
pushEvent(event) {
|
|
15079
|
-
|
|
15302
|
+
const enrichedEvent = {
|
|
15303
|
+
...event,
|
|
15304
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
|
|
15305
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
|
|
15306
|
+
providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
|
|
15307
|
+
workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
|
|
15308
|
+
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
15309
|
+
};
|
|
15310
|
+
if (this.context?.emitProviderEvent) {
|
|
15311
|
+
this.context.emitProviderEvent(enrichedEvent);
|
|
15312
|
+
return;
|
|
15313
|
+
}
|
|
15314
|
+
this.events.push(enrichedEvent);
|
|
15080
15315
|
}
|
|
15081
15316
|
flushEvents() {
|
|
15082
15317
|
const events = [...this.events];
|
|
@@ -15283,12 +15518,31 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15283
15518
|
);
|
|
15284
15519
|
}
|
|
15285
15520
|
}
|
|
15521
|
+
mergeRuntimeChatMessages(parsedMessages) {
|
|
15522
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
15523
|
+
}
|
|
15286
15524
|
mergeConversationMessages(parsedMessages) {
|
|
15287
15525
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15526
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
15527
|
+
message,
|
|
15528
|
+
index,
|
|
15529
|
+
source: "parsed"
|
|
15530
|
+
}));
|
|
15531
|
+
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
15532
|
+
message: entry.message,
|
|
15533
|
+
index: parsedMessages.length + index,
|
|
15534
|
+
source: "runtime"
|
|
15535
|
+
}));
|
|
15536
|
+
const getTime = (message) => {
|
|
15537
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
15538
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
15539
|
+
};
|
|
15540
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
15541
|
+
const aTime = getTime(a.message);
|
|
15542
|
+
const bTime = getTime(b.message);
|
|
15543
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
15544
|
+
if (aTime && !bTime && a.source === "runtime" && b.source === "parsed") return -1;
|
|
15545
|
+
if (!aTime && bTime && a.source === "parsed" && b.source === "runtime") return 1;
|
|
15292
15546
|
return a.index - b.index;
|
|
15293
15547
|
}).map((entry) => entry.message));
|
|
15294
15548
|
}
|
|
@@ -16617,17 +16871,17 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
16617
16871
|
// src/commands/cli-manager.ts
|
|
16618
16872
|
function isExplicitCommand(command) {
|
|
16619
16873
|
const trimmed = command.trim();
|
|
16620
|
-
return
|
|
16874
|
+
return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
16621
16875
|
}
|
|
16622
16876
|
function expandExecutable(command) {
|
|
16623
16877
|
const trimmed = command.trim();
|
|
16624
|
-
return trimmed.startsWith("~") ?
|
|
16878
|
+
return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
16625
16879
|
}
|
|
16626
16880
|
function commandExists(command) {
|
|
16627
16881
|
const trimmed = command.trim();
|
|
16628
16882
|
if (!trimmed) return false;
|
|
16629
16883
|
if (isExplicitCommand(trimmed)) {
|
|
16630
|
-
return
|
|
16884
|
+
return existsSync12(expandExecutable(trimmed));
|
|
16631
16885
|
}
|
|
16632
16886
|
try {
|
|
16633
16887
|
execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -16645,6 +16899,35 @@ function colorize(color, text) {
|
|
|
16645
16899
|
const fn = chalkApi?.[color];
|
|
16646
16900
|
return typeof fn === "function" ? fn(text) : text;
|
|
16647
16901
|
}
|
|
16902
|
+
var COORDINATOR_DELEGATED_ENV_UNSETS = {
|
|
16903
|
+
ADHDEV_INLINE_MESH: "",
|
|
16904
|
+
ADHDEV_MCP_TRANSPORT: "",
|
|
16905
|
+
ADHDEV_MESH_ID: "",
|
|
16906
|
+
HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
|
|
16907
|
+
};
|
|
16908
|
+
function hasCliArg(args, flag) {
|
|
16909
|
+
return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
16910
|
+
}
|
|
16911
|
+
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
16912
|
+
const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
16913
|
+
mkdirSync7(baseDir, { recursive: true });
|
|
16914
|
+
const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
16915
|
+
const filePath = path17.join(baseDir, `${workspaceHash}.json`);
|
|
16916
|
+
writeFileSync7(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
16917
|
+
return filePath;
|
|
16918
|
+
}
|
|
16919
|
+
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
16920
|
+
const cliType = String(input.cliType || "").trim();
|
|
16921
|
+
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
16922
|
+
const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
|
|
16923
|
+
if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
|
|
16924
|
+
cliArgs.unshift("--ignore-user-config");
|
|
16925
|
+
}
|
|
16926
|
+
if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
|
|
16927
|
+
cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
16928
|
+
}
|
|
16929
|
+
return { cliArgs, env };
|
|
16930
|
+
}
|
|
16648
16931
|
function isUuid(value) {
|
|
16649
16932
|
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
16933
|
}
|
|
@@ -16815,7 +17098,7 @@ var DaemonCliManager = class {
|
|
|
16815
17098
|
attachExisting
|
|
16816
17099
|
}) || void 0;
|
|
16817
17100
|
}
|
|
16818
|
-
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
|
|
17101
|
+
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
|
|
16819
17102
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16820
17103
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
16821
17104
|
if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
|
|
@@ -16829,7 +17112,7 @@ var DaemonCliManager = class {
|
|
|
16829
17112
|
providerSessionId,
|
|
16830
17113
|
attachExisting
|
|
16831
17114
|
);
|
|
16832
|
-
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
|
|
17115
|
+
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
16833
17116
|
}
|
|
16834
17117
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
16835
17118
|
}
|
|
@@ -16902,7 +17185,7 @@ var DaemonCliManager = class {
|
|
|
16902
17185
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
16903
17186
|
const trimmed = (workingDir || "").trim();
|
|
16904
17187
|
if (!trimmed) throw new Error("working directory required");
|
|
16905
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17188
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
|
|
16906
17189
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16907
17190
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
16908
17191
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -17032,6 +17315,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17032
17315
|
{
|
|
17033
17316
|
providerSessionId: sessionBinding.providerSessionId,
|
|
17034
17317
|
launchMode: sessionBinding.launchMode,
|
|
17318
|
+
extraEnv: options?.extraEnv,
|
|
17035
17319
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
17036
17320
|
this.persistRecentActivity({
|
|
17037
17321
|
kind: "cli",
|
|
@@ -17052,7 +17336,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17052
17336
|
resolvedCliArgs,
|
|
17053
17337
|
key,
|
|
17054
17338
|
sessionBinding.providerSessionId,
|
|
17055
|
-
false
|
|
17339
|
+
false,
|
|
17340
|
+
options?.extraEnv
|
|
17056
17341
|
);
|
|
17057
17342
|
try {
|
|
17058
17343
|
await adapter.spawn();
|
|
@@ -17276,12 +17561,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17276
17561
|
const dir = resolved.path;
|
|
17277
17562
|
const launchSource = resolved.source;
|
|
17278
17563
|
if (!cliType) throw new Error("cliType required");
|
|
17564
|
+
const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
|
|
17565
|
+
const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
|
|
17566
|
+
cliType,
|
|
17567
|
+
workspace: dir,
|
|
17568
|
+
cliArgs: args?.cliArgs,
|
|
17569
|
+
env: args?.env
|
|
17570
|
+
}) : null;
|
|
17279
17571
|
const started = await this.startSession(
|
|
17280
17572
|
cliType,
|
|
17281
17573
|
dir,
|
|
17282
|
-
args?.cliArgs,
|
|
17574
|
+
delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
|
|
17283
17575
|
args?.initialModel,
|
|
17284
|
-
{
|
|
17576
|
+
{
|
|
17577
|
+
resumeSessionId: args?.resumeSessionId,
|
|
17578
|
+
settingsOverride,
|
|
17579
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
17580
|
+
}
|
|
17285
17581
|
);
|
|
17286
17582
|
return {
|
|
17287
17583
|
success: true,
|
|
@@ -17403,11 +17699,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17403
17699
|
import { execSync as execSync4, spawn as spawn2 } from "child_process";
|
|
17404
17700
|
import * as net from "net";
|
|
17405
17701
|
import * as os15 from "os";
|
|
17406
|
-
import * as
|
|
17702
|
+
import * as path19 from "path";
|
|
17407
17703
|
|
|
17408
17704
|
// src/providers/provider-loader.ts
|
|
17409
17705
|
import * as fs7 from "fs";
|
|
17410
|
-
import * as
|
|
17706
|
+
import * as path18 from "path";
|
|
17411
17707
|
import * as os14 from "os";
|
|
17412
17708
|
import * as chokidar from "chokidar";
|
|
17413
17709
|
init_logger();
|
|
@@ -17731,7 +18027,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17731
18027
|
try {
|
|
17732
18028
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
17733
18029
|
return ["ide", "extension", "cli", "acp"].some(
|
|
17734
|
-
(category) => fs7.existsSync(
|
|
18030
|
+
(category) => fs7.existsSync(path18.join(candidate, category))
|
|
17735
18031
|
);
|
|
17736
18032
|
} catch {
|
|
17737
18033
|
return false;
|
|
@@ -17739,20 +18035,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17739
18035
|
}
|
|
17740
18036
|
static hasProviderRootMarker(candidate) {
|
|
17741
18037
|
try {
|
|
17742
|
-
return fs7.existsSync(
|
|
18038
|
+
return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
17743
18039
|
} catch {
|
|
17744
18040
|
return false;
|
|
17745
18041
|
}
|
|
17746
18042
|
}
|
|
17747
18043
|
detectDefaultUserDir() {
|
|
17748
|
-
const fallback =
|
|
18044
|
+
const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17749
18045
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17750
18046
|
const visited = /* @__PURE__ */ new Set();
|
|
17751
18047
|
for (const start of this.probeStarts) {
|
|
17752
|
-
let current =
|
|
18048
|
+
let current = path18.resolve(start);
|
|
17753
18049
|
while (!visited.has(current)) {
|
|
17754
18050
|
visited.add(current);
|
|
17755
|
-
const siblingCandidate =
|
|
18051
|
+
const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17756
18052
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17757
18053
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17758
18054
|
if (envOptIn || hasMarker) {
|
|
@@ -17774,7 +18070,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17774
18070
|
return { path: siblingCandidate, source };
|
|
17775
18071
|
}
|
|
17776
18072
|
}
|
|
17777
|
-
const parent =
|
|
18073
|
+
const parent = path18.dirname(current);
|
|
17778
18074
|
if (parent === current) break;
|
|
17779
18075
|
current = parent;
|
|
17780
18076
|
}
|
|
@@ -17784,11 +18080,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17784
18080
|
constructor(options) {
|
|
17785
18081
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17786
18082
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17787
|
-
this.defaultProvidersDir =
|
|
18083
|
+
this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17788
18084
|
const detected = this.detectDefaultUserDir();
|
|
17789
18085
|
this.userDir = detected.path;
|
|
17790
18086
|
this.userDirSource = detected.source;
|
|
17791
|
-
this.upstreamDir =
|
|
18087
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17792
18088
|
this.disableUpstream = false;
|
|
17793
18089
|
this.applySourceConfig({
|
|
17794
18090
|
userDir: options?.userDir,
|
|
@@ -17847,7 +18143,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17847
18143
|
this.userDir = detected.path;
|
|
17848
18144
|
this.userDirSource = detected.source;
|
|
17849
18145
|
}
|
|
17850
|
-
this.upstreamDir =
|
|
18146
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17851
18147
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
17852
18148
|
if (this.explicitProviderDir) {
|
|
17853
18149
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -17861,7 +18157,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17861
18157
|
* Canonical provider directory shape for a given root.
|
|
17862
18158
|
*/
|
|
17863
18159
|
getProviderDir(root, category, type) {
|
|
17864
|
-
return
|
|
18160
|
+
return path18.join(root, category, type);
|
|
17865
18161
|
}
|
|
17866
18162
|
/**
|
|
17867
18163
|
* Canonical user override directory for a provider.
|
|
@@ -17888,7 +18184,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17888
18184
|
resolveProviderFile(type, ...segments) {
|
|
17889
18185
|
const dir = this.findProviderDirInternal(type);
|
|
17890
18186
|
if (!dir) return null;
|
|
17891
|
-
return
|
|
18187
|
+
return path18.join(dir, ...segments);
|
|
17892
18188
|
}
|
|
17893
18189
|
/**
|
|
17894
18190
|
* Load all providers (3-tier priority)
|
|
@@ -17927,7 +18223,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17927
18223
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
17928
18224
|
try {
|
|
17929
18225
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
17930
|
-
(d) => fs7.statSync(
|
|
18226
|
+
(d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
|
|
17931
18227
|
);
|
|
17932
18228
|
} catch {
|
|
17933
18229
|
return false;
|
|
@@ -18424,8 +18720,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18424
18720
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
18425
18721
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
18426
18722
|
if (providerDir) {
|
|
18427
|
-
const fullDir =
|
|
18428
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18723
|
+
const fullDir = path18.join(providerDir, entry.scriptDir);
|
|
18724
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18429
18725
|
}
|
|
18430
18726
|
matched = true;
|
|
18431
18727
|
}
|
|
@@ -18440,8 +18736,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18440
18736
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18441
18737
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
18442
18738
|
if (providerDir) {
|
|
18443
|
-
const fullDir =
|
|
18444
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18739
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18740
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18445
18741
|
}
|
|
18446
18742
|
}
|
|
18447
18743
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -18458,8 +18754,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18458
18754
|
resolved._resolvedScriptDir = dirOverride;
|
|
18459
18755
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
18460
18756
|
if (providerDir) {
|
|
18461
|
-
const fullDir =
|
|
18462
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18757
|
+
const fullDir = path18.join(providerDir, dirOverride);
|
|
18758
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18463
18759
|
}
|
|
18464
18760
|
}
|
|
18465
18761
|
} else if (override.scripts) {
|
|
@@ -18475,8 +18771,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18475
18771
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18476
18772
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
18477
18773
|
if (providerDir) {
|
|
18478
|
-
const fullDir =
|
|
18479
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18774
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18775
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18480
18776
|
}
|
|
18481
18777
|
}
|
|
18482
18778
|
}
|
|
@@ -18508,14 +18804,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18508
18804
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
18509
18805
|
return null;
|
|
18510
18806
|
}
|
|
18511
|
-
const dir =
|
|
18807
|
+
const dir = path18.join(providerDir, scriptDir);
|
|
18512
18808
|
if (!fs7.existsSync(dir)) {
|
|
18513
18809
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
18514
18810
|
return null;
|
|
18515
18811
|
}
|
|
18516
18812
|
const cached = this.scriptsCache.get(dir);
|
|
18517
18813
|
if (cached) return cached;
|
|
18518
|
-
const scriptsJs =
|
|
18814
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
18519
18815
|
if (fs7.existsSync(scriptsJs)) {
|
|
18520
18816
|
try {
|
|
18521
18817
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -18557,7 +18853,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18557
18853
|
return;
|
|
18558
18854
|
}
|
|
18559
18855
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
18560
|
-
this.log(`File changed: ${
|
|
18856
|
+
this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
|
|
18561
18857
|
this.reload();
|
|
18562
18858
|
}
|
|
18563
18859
|
};
|
|
@@ -18612,7 +18908,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18612
18908
|
}
|
|
18613
18909
|
const https = __require("https");
|
|
18614
18910
|
const { execSync: execSync7 } = __require("child_process");
|
|
18615
|
-
const metaPath =
|
|
18911
|
+
const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
18616
18912
|
let prevEtag = "";
|
|
18617
18913
|
let prevTimestamp = 0;
|
|
18618
18914
|
try {
|
|
@@ -18672,17 +18968,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18672
18968
|
return { updated: false };
|
|
18673
18969
|
}
|
|
18674
18970
|
this.log("Downloading latest providers from GitHub...");
|
|
18675
|
-
const tmpTar =
|
|
18676
|
-
const tmpExtract =
|
|
18971
|
+
const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
18972
|
+
const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
18677
18973
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
18678
18974
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
18679
18975
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
18680
18976
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
18681
18977
|
const rootDir = extracted.find(
|
|
18682
|
-
(d) => fs7.statSync(
|
|
18978
|
+
(d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
18683
18979
|
);
|
|
18684
18980
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
18685
|
-
const sourceDir =
|
|
18981
|
+
const sourceDir = path18.join(tmpExtract, rootDir);
|
|
18686
18982
|
const backupDir = this.upstreamDir + ".bak";
|
|
18687
18983
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
18688
18984
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -18757,8 +19053,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18757
19053
|
copyDirRecursive(src, dest) {
|
|
18758
19054
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18759
19055
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18760
|
-
const srcPath =
|
|
18761
|
-
const destPath =
|
|
19056
|
+
const srcPath = path18.join(src, entry.name);
|
|
19057
|
+
const destPath = path18.join(dest, entry.name);
|
|
18762
19058
|
if (entry.isDirectory()) {
|
|
18763
19059
|
this.copyDirRecursive(srcPath, destPath);
|
|
18764
19060
|
} else {
|
|
@@ -18769,7 +19065,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18769
19065
|
/** .meta.json save */
|
|
18770
19066
|
writeMeta(metaPath, etag, timestamp) {
|
|
18771
19067
|
try {
|
|
18772
|
-
fs7.mkdirSync(
|
|
19068
|
+
fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
|
|
18773
19069
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18774
19070
|
etag,
|
|
18775
19071
|
timestamp,
|
|
@@ -18786,7 +19082,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18786
19082
|
const scan = (d) => {
|
|
18787
19083
|
try {
|
|
18788
19084
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18789
|
-
if (entry.isDirectory()) scan(
|
|
19085
|
+
if (entry.isDirectory()) scan(path18.join(d, entry.name));
|
|
18790
19086
|
else if (entry.name === "provider.json") count++;
|
|
18791
19087
|
}
|
|
18792
19088
|
} catch {
|
|
@@ -19014,17 +19310,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19014
19310
|
for (const root of searchRoots) {
|
|
19015
19311
|
if (!fs7.existsSync(root)) continue;
|
|
19016
19312
|
const candidate = this.getProviderDir(root, cat, type);
|
|
19017
|
-
if (fs7.existsSync(
|
|
19018
|
-
const catDir =
|
|
19313
|
+
if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
|
|
19314
|
+
const catDir = path18.join(root, cat);
|
|
19019
19315
|
if (fs7.existsSync(catDir)) {
|
|
19020
19316
|
try {
|
|
19021
19317
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
19022
19318
|
if (!entry.isDirectory()) continue;
|
|
19023
|
-
const jsonPath =
|
|
19319
|
+
const jsonPath = path18.join(catDir, entry.name, "provider.json");
|
|
19024
19320
|
if (fs7.existsSync(jsonPath)) {
|
|
19025
19321
|
try {
|
|
19026
19322
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
19027
|
-
if (data.type === type) return
|
|
19323
|
+
if (data.type === type) return path18.join(catDir, entry.name);
|
|
19028
19324
|
} catch {
|
|
19029
19325
|
}
|
|
19030
19326
|
}
|
|
@@ -19041,7 +19337,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19041
19337
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
19042
19338
|
*/
|
|
19043
19339
|
buildScriptWrappersFromDir(dir) {
|
|
19044
|
-
const scriptsJs =
|
|
19340
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
19045
19341
|
if (fs7.existsSync(scriptsJs)) {
|
|
19046
19342
|
try {
|
|
19047
19343
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -19055,7 +19351,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19055
19351
|
for (const file of fs7.readdirSync(dir)) {
|
|
19056
19352
|
if (!file.endsWith(".js")) continue;
|
|
19057
19353
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
19058
|
-
const filePath =
|
|
19354
|
+
const filePath = path18.join(dir, file);
|
|
19059
19355
|
result[scriptName] = (...args) => {
|
|
19060
19356
|
try {
|
|
19061
19357
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -19115,7 +19411,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19115
19411
|
}
|
|
19116
19412
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
19117
19413
|
if (hasJson) {
|
|
19118
|
-
const jsonPath =
|
|
19414
|
+
const jsonPath = path18.join(d, "provider.json");
|
|
19119
19415
|
try {
|
|
19120
19416
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
19121
19417
|
const mod = JSON.parse(raw);
|
|
@@ -19136,7 +19432,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19136
19432
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
19137
19433
|
} else {
|
|
19138
19434
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
19139
|
-
const scriptsPath =
|
|
19435
|
+
const scriptsPath = path18.join(d, "scripts.js");
|
|
19140
19436
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
19141
19437
|
try {
|
|
19142
19438
|
delete __require.cache[__require.resolve(scriptsPath)];
|
|
@@ -19162,7 +19458,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19162
19458
|
if (!entry.isDirectory()) continue;
|
|
19163
19459
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
19164
19460
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
19165
|
-
scan(
|
|
19461
|
+
scan(path18.join(d, entry.name));
|
|
19166
19462
|
}
|
|
19167
19463
|
}
|
|
19168
19464
|
};
|
|
@@ -19487,8 +19783,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
19487
19783
|
const appNameMap = getMacAppIdentifiers();
|
|
19488
19784
|
const appName = appNameMap[ideId];
|
|
19489
19785
|
if (appName) {
|
|
19490
|
-
const storagePath =
|
|
19491
|
-
process.env.APPDATA ||
|
|
19786
|
+
const storagePath = path19.join(
|
|
19787
|
+
process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
|
|
19492
19788
|
appName,
|
|
19493
19789
|
"storage.json"
|
|
19494
19790
|
);
|
|
@@ -19677,9 +19973,9 @@ init_logger();
|
|
|
19677
19973
|
|
|
19678
19974
|
// src/logging/command-log.ts
|
|
19679
19975
|
import * as fs8 from "fs";
|
|
19680
|
-
import * as
|
|
19976
|
+
import * as path20 from "path";
|
|
19681
19977
|
import * as os16 from "os";
|
|
19682
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
19978
|
+
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
19979
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
19684
19980
|
var MAX_DAYS = 7;
|
|
19685
19981
|
try {
|
|
@@ -19717,13 +20013,13 @@ function getDateStr2() {
|
|
|
19717
20013
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19718
20014
|
}
|
|
19719
20015
|
var currentDate2 = getDateStr2();
|
|
19720
|
-
var currentFile =
|
|
20016
|
+
var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19721
20017
|
var writeCount2 = 0;
|
|
19722
20018
|
function checkRotation() {
|
|
19723
20019
|
const today = getDateStr2();
|
|
19724
20020
|
if (today !== currentDate2) {
|
|
19725
20021
|
currentDate2 = today;
|
|
19726
|
-
currentFile =
|
|
20022
|
+
currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19727
20023
|
cleanOldFiles();
|
|
19728
20024
|
}
|
|
19729
20025
|
}
|
|
@@ -19737,7 +20033,7 @@ function cleanOldFiles() {
|
|
|
19737
20033
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
19738
20034
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
19739
20035
|
try {
|
|
19740
|
-
fs8.unlinkSync(
|
|
20036
|
+
fs8.unlinkSync(path20.join(LOG_DIR2, file));
|
|
19741
20037
|
} catch {
|
|
19742
20038
|
}
|
|
19743
20039
|
}
|
|
@@ -19821,13 +20117,65 @@ cleanOldFiles();
|
|
|
19821
20117
|
|
|
19822
20118
|
// src/commands/router.ts
|
|
19823
20119
|
init_logger();
|
|
20120
|
+
import * as yaml from "js-yaml";
|
|
19824
20121
|
|
|
19825
20122
|
// src/commands/mesh-coordinator.ts
|
|
19826
|
-
import {
|
|
20123
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
20124
|
+
import { existsSync as existsSync15, readdirSync as readdirSync6, realpathSync as realpathSync2 } from "fs";
|
|
19827
20125
|
import { createRequire as createRequire2 } from "module";
|
|
19828
|
-
import
|
|
20126
|
+
import * as os17 from "os";
|
|
20127
|
+
import { dirname as dirname4, isAbsolute as isAbsolute10, join as join18, resolve as resolve13 } from "path";
|
|
19829
20128
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
19830
20129
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20130
|
+
var HERMES_CLI_TYPE = "hermes-cli";
|
|
20131
|
+
var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
|
|
20132
|
+
function isHermesProvider(provider, cliType) {
|
|
20133
|
+
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
20134
|
+
return type === HERMES_CLI_TYPE;
|
|
20135
|
+
}
|
|
20136
|
+
function resolveHermesMeshCoordinatorSetup(options) {
|
|
20137
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
20138
|
+
meshId: options.meshId,
|
|
20139
|
+
nodeExecutable: options.nodeExecutable,
|
|
20140
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath
|
|
20141
|
+
});
|
|
20142
|
+
if (!mcpServer) {
|
|
20143
|
+
return {
|
|
20144
|
+
kind: "unsupported",
|
|
20145
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20146
|
+
};
|
|
20147
|
+
}
|
|
20148
|
+
const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
|
|
20149
|
+
if (!configPath.trim()) {
|
|
20150
|
+
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20151
|
+
}
|
|
20152
|
+
return {
|
|
20153
|
+
kind: "auto_import",
|
|
20154
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20155
|
+
configPath,
|
|
20156
|
+
configFormat: "hermes_config_yaml",
|
|
20157
|
+
mcpServer
|
|
20158
|
+
};
|
|
20159
|
+
}
|
|
20160
|
+
function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
|
|
20161
|
+
return {
|
|
20162
|
+
kind: "manual",
|
|
20163
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20164
|
+
configFormat: "hermes_config_yaml",
|
|
20165
|
+
configPathCommand: HERMES_MCP_CONFIG_PATH,
|
|
20166
|
+
requiresRestart: true,
|
|
20167
|
+
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.",
|
|
20168
|
+
template: renderMeshCoordinatorTemplate(
|
|
20169
|
+
"mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
|
|
20170
|
+
{
|
|
20171
|
+
meshId,
|
|
20172
|
+
workspace,
|
|
20173
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20174
|
+
adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
|
|
20175
|
+
}
|
|
20176
|
+
)
|
|
20177
|
+
};
|
|
20178
|
+
}
|
|
19831
20179
|
function resolveMeshCoordinatorSetup(options) {
|
|
19832
20180
|
const { provider, meshId, workspace } = options;
|
|
19833
20181
|
const config = provider?.meshCoordinator;
|
|
@@ -19837,6 +20185,9 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19837
20185
|
reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
|
|
19838
20186
|
};
|
|
19839
20187
|
}
|
|
20188
|
+
if (isHermesProvider(provider, options.cliType)) {
|
|
20189
|
+
return resolveHermesMeshCoordinatorSetup(options);
|
|
20190
|
+
}
|
|
19840
20191
|
const mcpConfig = config.mcpConfig;
|
|
19841
20192
|
if (!mcpConfig || mcpConfig.mode === "none") {
|
|
19842
20193
|
return {
|
|
@@ -19846,8 +20197,8 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19846
20197
|
}
|
|
19847
20198
|
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
|
|
19848
20199
|
if (mcpConfig.mode === "auto_import") {
|
|
19849
|
-
const
|
|
19850
|
-
if (!
|
|
20200
|
+
const path27 = mcpConfig.path?.trim();
|
|
20201
|
+
if (!path27) {
|
|
19851
20202
|
return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
|
|
19852
20203
|
}
|
|
19853
20204
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
@@ -19858,13 +20209,13 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19858
20209
|
if (!mcpServer) {
|
|
19859
20210
|
return {
|
|
19860
20211
|
kind: "unsupported",
|
|
19861
|
-
reason: "Could not resolve the ADHDev MCP server entrypoint
|
|
20212
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
19862
20213
|
};
|
|
19863
20214
|
}
|
|
19864
20215
|
return {
|
|
19865
20216
|
kind: "auto_import",
|
|
19866
20217
|
serverName,
|
|
19867
|
-
configPath:
|
|
20218
|
+
configPath: resolveMcpConfigPath(path27, workspace),
|
|
19868
20219
|
configFormat: mcpConfig.format,
|
|
19869
20220
|
mcpServer
|
|
19870
20221
|
};
|
|
@@ -19898,14 +20249,85 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19898
20249
|
function renderMeshCoordinatorTemplate(template, values) {
|
|
19899
20250
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
|
|
19900
20251
|
}
|
|
20252
|
+
function resolveMcpConfigPath(configPath, workspace) {
|
|
20253
|
+
const trimmed = configPath.trim();
|
|
20254
|
+
if (trimmed === "~") return os17.homedir();
|
|
20255
|
+
if (trimmed.startsWith("~/")) return join18(os17.homedir(), trimmed.slice(2));
|
|
20256
|
+
if (isAbsolute10(trimmed)) return trimmed;
|
|
20257
|
+
return join18(workspace, trimmed);
|
|
20258
|
+
}
|
|
19901
20259
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
19902
20260
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
19903
20261
|
if (!entryPath) return null;
|
|
20262
|
+
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
|
|
20263
|
+
if (!nodeExecutable) return null;
|
|
19904
20264
|
return {
|
|
19905
|
-
command:
|
|
19906
|
-
args: [entryPath, "--repo-mesh", options.meshId]
|
|
20265
|
+
command: nodeExecutable,
|
|
20266
|
+
args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
|
|
19907
20267
|
};
|
|
19908
20268
|
}
|
|
20269
|
+
function resolveMcpNodeExecutable(explicitExecutable) {
|
|
20270
|
+
const explicit = explicitExecutable?.trim();
|
|
20271
|
+
if (explicit) return explicit;
|
|
20272
|
+
const candidates = [];
|
|
20273
|
+
const addCandidate = (candidate) => {
|
|
20274
|
+
const trimmed = candidate?.trim();
|
|
20275
|
+
if (!trimmed) return;
|
|
20276
|
+
const normalized = normalizeExistingPath(trimmed) || trimmed;
|
|
20277
|
+
if (!candidates.includes(normalized)) candidates.push(normalized);
|
|
20278
|
+
};
|
|
20279
|
+
addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
|
|
20280
|
+
addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
|
|
20281
|
+
addCandidate(process.env.npm_node_execpath);
|
|
20282
|
+
addNodeCandidatesFromPath(process.env.PATH, addCandidate);
|
|
20283
|
+
addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
|
|
20284
|
+
addCandidate("/opt/homebrew/bin/node");
|
|
20285
|
+
addCandidate("/usr/local/bin/node");
|
|
20286
|
+
addCandidate("/usr/bin/node");
|
|
20287
|
+
addCandidate(process.execPath);
|
|
20288
|
+
for (const candidate of candidates) {
|
|
20289
|
+
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
|
|
20290
|
+
}
|
|
20291
|
+
return null;
|
|
20292
|
+
}
|
|
20293
|
+
function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
20294
|
+
for (const entry of (pathValue || "").split(":")) {
|
|
20295
|
+
const dir = entry.trim();
|
|
20296
|
+
if (!dir) continue;
|
|
20297
|
+
addCandidate(join18(dir, "node"));
|
|
20298
|
+
}
|
|
20299
|
+
}
|
|
20300
|
+
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
20301
|
+
const versionsDir = join18(homeDir, ".nvm", "versions", "node");
|
|
20302
|
+
try {
|
|
20303
|
+
const versionDirs = readdirSync6(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
20304
|
+
for (const versionDir of versionDirs) {
|
|
20305
|
+
addCandidate(join18(versionsDir, versionDir, "bin", "node"));
|
|
20306
|
+
}
|
|
20307
|
+
} catch {
|
|
20308
|
+
}
|
|
20309
|
+
}
|
|
20310
|
+
function compareNodeVersionNamesDescending(a, b) {
|
|
20311
|
+
const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
20312
|
+
const left = parse(a);
|
|
20313
|
+
const right = parse(b);
|
|
20314
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
20315
|
+
const diff = (right[i] || 0) - (left[i] || 0);
|
|
20316
|
+
if (diff !== 0) return diff;
|
|
20317
|
+
}
|
|
20318
|
+
return b.localeCompare(a);
|
|
20319
|
+
}
|
|
20320
|
+
function nodeRuntimeSupportsWebSocket(nodeExecutable) {
|
|
20321
|
+
try {
|
|
20322
|
+
execFileSync2(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
|
|
20323
|
+
stdio: "ignore",
|
|
20324
|
+
timeout: 3e3
|
|
20325
|
+
});
|
|
20326
|
+
return true;
|
|
20327
|
+
} catch {
|
|
20328
|
+
return false;
|
|
20329
|
+
}
|
|
20330
|
+
}
|
|
19909
20331
|
function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
19910
20332
|
const explicit = explicitPath?.trim();
|
|
19911
20333
|
if (explicit) return normalizeExistingPath(explicit) || explicit;
|
|
@@ -19918,7 +20340,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19918
20340
|
const addPackagedCandidates = (baseFile) => {
|
|
19919
20341
|
if (!baseFile) return;
|
|
19920
20342
|
const realBase = normalizeExistingPath(baseFile) || baseFile;
|
|
19921
|
-
const dir =
|
|
20343
|
+
const dir = dirname4(realBase);
|
|
19922
20344
|
addCandidate(resolve13(dir, "../vendor/mcp-server/index.js"));
|
|
19923
20345
|
addCandidate(resolve13(dir, "../../vendor/mcp-server/index.js"));
|
|
19924
20346
|
addCandidate(resolve13(dir, "../../../vendor/mcp-server/index.js"));
|
|
@@ -19931,7 +20353,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19931
20353
|
if (normalized) return normalized;
|
|
19932
20354
|
}
|
|
19933
20355
|
try {
|
|
19934
|
-
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] :
|
|
20356
|
+
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join18(process.cwd(), "adhdev-daemon.js");
|
|
19935
20357
|
const req = createRequire2(requireBase);
|
|
19936
20358
|
const resolvedModule = req.resolve("@adhdev/mcp-server");
|
|
19937
20359
|
return normalizeExistingPath(resolvedModule) || resolvedModule;
|
|
@@ -19941,16 +20363,110 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19941
20363
|
}
|
|
19942
20364
|
function normalizeExistingPath(filePath) {
|
|
19943
20365
|
try {
|
|
19944
|
-
if (!
|
|
20366
|
+
if (!existsSync15(filePath)) return null;
|
|
19945
20367
|
return realpathSync2.native(filePath);
|
|
19946
20368
|
} catch {
|
|
19947
20369
|
return null;
|
|
19948
20370
|
}
|
|
19949
20371
|
}
|
|
19950
20372
|
|
|
20373
|
+
// src/mesh/mesh-events.ts
|
|
20374
|
+
init_mesh_config();
|
|
20375
|
+
init_logger();
|
|
20376
|
+
function readNonEmptyString(value) {
|
|
20377
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
20378
|
+
}
|
|
20379
|
+
function formatCompletionMetadata(event) {
|
|
20380
|
+
const parts = [
|
|
20381
|
+
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
20382
|
+
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
20383
|
+
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
20384
|
+
].filter(Boolean);
|
|
20385
|
+
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
20386
|
+
}
|
|
20387
|
+
function buildMeshSystemMessage(args) {
|
|
20388
|
+
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
20389
|
+
if (args.event === "agent:generating_completed") {
|
|
20390
|
+
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. You may use mesh_read_chat to review its progress.`;
|
|
20391
|
+
}
|
|
20392
|
+
if (args.event === "agent:waiting_approval") {
|
|
20393
|
+
return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
20394
|
+
}
|
|
20395
|
+
return "";
|
|
20396
|
+
}
|
|
20397
|
+
function injectMeshSystemMessage(components, args) {
|
|
20398
|
+
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
20399
|
+
const instState = inst.getState();
|
|
20400
|
+
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
20401
|
+
if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
|
|
20402
|
+
return true;
|
|
20403
|
+
});
|
|
20404
|
+
if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
|
|
20405
|
+
const messageText = buildMeshSystemMessage({
|
|
20406
|
+
event: args.event,
|
|
20407
|
+
nodeLabel: args.nodeLabel,
|
|
20408
|
+
metadataEvent: args.metadataEvent
|
|
20409
|
+
});
|
|
20410
|
+
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
20411
|
+
for (const coord of coordinatorInstances) {
|
|
20412
|
+
const coordState = coord.getState();
|
|
20413
|
+
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
20414
|
+
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
20415
|
+
}
|
|
20416
|
+
return { success: true, forwarded: coordinatorInstances.length };
|
|
20417
|
+
}
|
|
20418
|
+
function handleMeshForwardEvent(components, payload) {
|
|
20419
|
+
const eventName = readNonEmptyString(payload.event);
|
|
20420
|
+
if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
|
|
20421
|
+
return { success: false, error: "unsupported mesh event" };
|
|
20422
|
+
}
|
|
20423
|
+
const meshId = readNonEmptyString(payload.meshId);
|
|
20424
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
20425
|
+
const nodeId = readNonEmptyString(payload.nodeId);
|
|
20426
|
+
const workspace = readNonEmptyString(payload.workspace);
|
|
20427
|
+
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
20428
|
+
return injectMeshSystemMessage(components, {
|
|
20429
|
+
meshId,
|
|
20430
|
+
nodeLabel,
|
|
20431
|
+
event: eventName,
|
|
20432
|
+
metadataEvent: {
|
|
20433
|
+
targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
|
|
20434
|
+
providerType: readNonEmptyString(payload.providerType),
|
|
20435
|
+
providerSessionId: readNonEmptyString(payload.providerSessionId)
|
|
20436
|
+
}
|
|
20437
|
+
});
|
|
20438
|
+
}
|
|
20439
|
+
function setupMeshEventForwarding(components) {
|
|
20440
|
+
components.instanceManager.onEvent((event) => {
|
|
20441
|
+
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
20442
|
+
const instanceId = readNonEmptyString(event.instanceId);
|
|
20443
|
+
if (!instanceId) return;
|
|
20444
|
+
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
20445
|
+
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
20446
|
+
const state = sourceInstance.getState();
|
|
20447
|
+
const workspace = readNonEmptyString(state.workspace);
|
|
20448
|
+
if (!workspace) return;
|
|
20449
|
+
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
20450
|
+
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
20451
|
+
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
20452
|
+
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
20453
|
+
if (!meshId) return;
|
|
20454
|
+
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
20455
|
+
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
20456
|
+
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
20457
|
+
injectMeshSystemMessage(components, {
|
|
20458
|
+
meshId,
|
|
20459
|
+
sourceInstanceId: instanceId,
|
|
20460
|
+
nodeLabel,
|
|
20461
|
+
event: event.event,
|
|
20462
|
+
metadataEvent: event
|
|
20463
|
+
});
|
|
20464
|
+
});
|
|
20465
|
+
}
|
|
20466
|
+
|
|
19951
20467
|
// src/status/snapshot.ts
|
|
19952
20468
|
init_config();
|
|
19953
|
-
import * as
|
|
20469
|
+
import * as os18 from "os";
|
|
19954
20470
|
init_terminal_screen();
|
|
19955
20471
|
init_logger();
|
|
19956
20472
|
var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
|
|
@@ -20005,8 +20521,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20005
20521
|
}
|
|
20006
20522
|
function buildMachineInfo(profile = "full") {
|
|
20007
20523
|
const base = {
|
|
20008
|
-
hostname:
|
|
20009
|
-
platform:
|
|
20524
|
+
hostname: os18.hostname(),
|
|
20525
|
+
platform: os18.platform()
|
|
20010
20526
|
};
|
|
20011
20527
|
if (profile === "live") {
|
|
20012
20528
|
return base;
|
|
@@ -20015,23 +20531,23 @@ function buildMachineInfo(profile = "full") {
|
|
|
20015
20531
|
const memSnap2 = getHostMemorySnapshot();
|
|
20016
20532
|
return {
|
|
20017
20533
|
...base,
|
|
20018
|
-
arch:
|
|
20019
|
-
cpus:
|
|
20534
|
+
arch: os18.arch(),
|
|
20535
|
+
cpus: os18.cpus().length,
|
|
20020
20536
|
totalMem: memSnap2.totalMem,
|
|
20021
|
-
release:
|
|
20537
|
+
release: os18.release()
|
|
20022
20538
|
};
|
|
20023
20539
|
}
|
|
20024
20540
|
const memSnap = getHostMemorySnapshot();
|
|
20025
20541
|
return {
|
|
20026
20542
|
...base,
|
|
20027
|
-
arch:
|
|
20028
|
-
cpus:
|
|
20543
|
+
arch: os18.arch(),
|
|
20544
|
+
cpus: os18.cpus().length,
|
|
20029
20545
|
totalMem: memSnap.totalMem,
|
|
20030
20546
|
freeMem: memSnap.freeMem,
|
|
20031
20547
|
availableMem: memSnap.availableMem,
|
|
20032
|
-
loadavg:
|
|
20033
|
-
uptime:
|
|
20034
|
-
release:
|
|
20548
|
+
loadavg: os18.loadavg(),
|
|
20549
|
+
uptime: os18.uptime(),
|
|
20550
|
+
release: os18.release()
|
|
20035
20551
|
};
|
|
20036
20552
|
}
|
|
20037
20553
|
function parseMessageTime(value) {
|
|
@@ -20262,17 +20778,17 @@ function buildStatusSnapshot(options) {
|
|
|
20262
20778
|
}
|
|
20263
20779
|
|
|
20264
20780
|
// src/commands/upgrade-helper.ts
|
|
20265
|
-
import { execFileSync as
|
|
20781
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
20266
20782
|
import { spawn as spawn3 } from "child_process";
|
|
20267
20783
|
import * as fs9 from "fs";
|
|
20268
|
-
import * as
|
|
20269
|
-
import * as
|
|
20784
|
+
import * as os19 from "os";
|
|
20785
|
+
import * as path21 from "path";
|
|
20270
20786
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
20271
20787
|
function getUpgradeLogPath() {
|
|
20272
|
-
const home =
|
|
20273
|
-
const dir =
|
|
20788
|
+
const home = os19.homedir();
|
|
20789
|
+
const dir = path21.join(home, ".adhdev");
|
|
20274
20790
|
fs9.mkdirSync(dir, { recursive: true });
|
|
20275
|
-
return
|
|
20791
|
+
return path21.join(dir, "daemon-upgrade.log");
|
|
20276
20792
|
}
|
|
20277
20793
|
function appendUpgradeLog(message) {
|
|
20278
20794
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -20283,14 +20799,14 @@ function appendUpgradeLog(message) {
|
|
|
20283
20799
|
}
|
|
20284
20800
|
}
|
|
20285
20801
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
20286
|
-
const binDir =
|
|
20802
|
+
const binDir = path21.dirname(nodeExecutable);
|
|
20287
20803
|
if (platform10 === "win32") {
|
|
20288
|
-
const npmCliPath =
|
|
20804
|
+
const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
20289
20805
|
if (fs9.existsSync(npmCliPath)) {
|
|
20290
20806
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20291
20807
|
}
|
|
20292
20808
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
20293
|
-
const candidatePath =
|
|
20809
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20294
20810
|
if (fs9.existsSync(candidatePath)) {
|
|
20295
20811
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20296
20812
|
}
|
|
@@ -20298,7 +20814,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
20298
20814
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20299
20815
|
}
|
|
20300
20816
|
for (const candidate of ["npm"]) {
|
|
20301
|
-
const candidatePath =
|
|
20817
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20302
20818
|
if (fs9.existsSync(candidatePath)) {
|
|
20303
20819
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20304
20820
|
}
|
|
@@ -20315,13 +20831,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20315
20831
|
let currentDir = resolvedPath;
|
|
20316
20832
|
try {
|
|
20317
20833
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
20318
|
-
currentDir =
|
|
20834
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20319
20835
|
}
|
|
20320
20836
|
} catch {
|
|
20321
|
-
currentDir =
|
|
20837
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20322
20838
|
}
|
|
20323
20839
|
while (true) {
|
|
20324
|
-
const packageJsonPath =
|
|
20840
|
+
const packageJsonPath = path21.join(currentDir, "package.json");
|
|
20325
20841
|
try {
|
|
20326
20842
|
if (fs9.existsSync(packageJsonPath)) {
|
|
20327
20843
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -20332,7 +20848,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20332
20848
|
}
|
|
20333
20849
|
} catch {
|
|
20334
20850
|
}
|
|
20335
|
-
const parentDir =
|
|
20851
|
+
const parentDir = path21.dirname(currentDir);
|
|
20336
20852
|
if (parentDir === currentDir) {
|
|
20337
20853
|
return null;
|
|
20338
20854
|
}
|
|
@@ -20340,13 +20856,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20340
20856
|
}
|
|
20341
20857
|
}
|
|
20342
20858
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
20343
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
20344
|
-
if (
|
|
20859
|
+
const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
|
|
20860
|
+
if (path21.basename(nodeModulesDir) !== "node_modules") {
|
|
20345
20861
|
return null;
|
|
20346
20862
|
}
|
|
20347
|
-
const maybeLibDir =
|
|
20348
|
-
if (
|
|
20349
|
-
return
|
|
20863
|
+
const maybeLibDir = path21.dirname(nodeModulesDir);
|
|
20864
|
+
if (path21.basename(maybeLibDir) === "lib") {
|
|
20865
|
+
return path21.dirname(maybeLibDir);
|
|
20350
20866
|
}
|
|
20351
20867
|
return maybeLibDir;
|
|
20352
20868
|
}
|
|
@@ -20382,7 +20898,7 @@ function getNpmExecOptions(platform10 = process.platform) {
|
|
|
20382
20898
|
}
|
|
20383
20899
|
function execNpmCommandSync(args, options = {}, surface) {
|
|
20384
20900
|
const execOptions = surface?.execOptions || getNpmExecOptions();
|
|
20385
|
-
return
|
|
20901
|
+
return execFileSync3(
|
|
20386
20902
|
surface?.npmExecutable || "npm",
|
|
20387
20903
|
[...surface?.npmArgsPrefix || [], ...args],
|
|
20388
20904
|
{
|
|
@@ -20395,7 +20911,7 @@ function execNpmCommandSync(args, options = {}, surface) {
|
|
|
20395
20911
|
function killPid(pid) {
|
|
20396
20912
|
try {
|
|
20397
20913
|
if (process.platform === "win32") {
|
|
20398
|
-
|
|
20914
|
+
execFileSync3("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
|
|
20399
20915
|
} else {
|
|
20400
20916
|
process.kill(pid, "SIGTERM");
|
|
20401
20917
|
}
|
|
@@ -20407,7 +20923,7 @@ function killPid(pid) {
|
|
|
20407
20923
|
function getWindowsProcessCommandLine(pid) {
|
|
20408
20924
|
const pidFilter = `ProcessId=${pid}`;
|
|
20409
20925
|
try {
|
|
20410
|
-
const psOut =
|
|
20926
|
+
const psOut = execFileSync3("powershell.exe", [
|
|
20411
20927
|
"-NoProfile",
|
|
20412
20928
|
"-NonInteractive",
|
|
20413
20929
|
"-ExecutionPolicy",
|
|
@@ -20419,7 +20935,7 @@ function getWindowsProcessCommandLine(pid) {
|
|
|
20419
20935
|
} catch {
|
|
20420
20936
|
}
|
|
20421
20937
|
try {
|
|
20422
|
-
const wmicOut =
|
|
20938
|
+
const wmicOut = execFileSync3("wmic", [
|
|
20423
20939
|
"process",
|
|
20424
20940
|
"where",
|
|
20425
20941
|
pidFilter,
|
|
@@ -20435,7 +20951,7 @@ function getProcessCommandLine(pid) {
|
|
|
20435
20951
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
20436
20952
|
if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
|
|
20437
20953
|
try {
|
|
20438
|
-
const text =
|
|
20954
|
+
const text = execFileSync3("ps", ["-o", "command=", "-p", String(pid)], {
|
|
20439
20955
|
encoding: "utf8",
|
|
20440
20956
|
timeout: 3e3,
|
|
20441
20957
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -20461,7 +20977,7 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
20461
20977
|
}
|
|
20462
20978
|
}
|
|
20463
20979
|
function stopSessionHostProcesses(appName) {
|
|
20464
|
-
const pidFile =
|
|
20980
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
20465
20981
|
try {
|
|
20466
20982
|
if (fs9.existsSync(pidFile)) {
|
|
20467
20983
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -20478,7 +20994,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
20478
20994
|
}
|
|
20479
20995
|
}
|
|
20480
20996
|
function removeDaemonPidFile() {
|
|
20481
|
-
const pidFile =
|
|
20997
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
20482
20998
|
try {
|
|
20483
20999
|
fs9.unlinkSync(pidFile);
|
|
20484
21000
|
} catch {
|
|
@@ -20489,7 +21005,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20489
21005
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20490
21006
|
if (!npmRoot) return;
|
|
20491
21007
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20492
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
21008
|
+
const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
|
|
20493
21009
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
20494
21010
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
20495
21011
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -20497,25 +21013,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20497
21013
|
}
|
|
20498
21014
|
if (pkgName.startsWith("@")) {
|
|
20499
21015
|
const [scope, name] = pkgName.split("/");
|
|
20500
|
-
const scopeDir =
|
|
21016
|
+
const scopeDir = path21.join(npmRoot, scope);
|
|
20501
21017
|
if (!fs9.existsSync(scopeDir)) return;
|
|
20502
21018
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
20503
21019
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
20504
|
-
fs9.rmSync(
|
|
20505
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
21020
|
+
fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
|
|
21021
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
|
|
20506
21022
|
}
|
|
20507
21023
|
} else {
|
|
20508
21024
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
20509
21025
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
20510
|
-
fs9.rmSync(
|
|
20511
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
21026
|
+
fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
|
|
21027
|
+
appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
|
|
20512
21028
|
}
|
|
20513
21029
|
}
|
|
20514
21030
|
if (fs9.existsSync(binDir)) {
|
|
20515
21031
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
20516
21032
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
20517
|
-
fs9.rmSync(
|
|
20518
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
21033
|
+
fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
|
|
21034
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
|
|
20519
21035
|
}
|
|
20520
21036
|
}
|
|
20521
21037
|
}
|
|
@@ -20551,7 +21067,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
20551
21067
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
20552
21068
|
const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
|
|
20553
21069
|
appendUpgradeLog(`Installing ${spec}`);
|
|
20554
|
-
const installOutput =
|
|
21070
|
+
const installOutput = execFileSync3(
|
|
20555
21071
|
installCommand.command,
|
|
20556
21072
|
installCommand.args,
|
|
20557
21073
|
{
|
|
@@ -20616,6 +21132,56 @@ function normalizeReleaseChannel(value) {
|
|
|
20616
21132
|
function resolveUpgradeChannel(args) {
|
|
20617
21133
|
return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
|
|
20618
21134
|
}
|
|
21135
|
+
function readProviderPriorityFromPolicy(policy) {
|
|
21136
|
+
const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
|
|
21137
|
+
const raw = record.providerPriority;
|
|
21138
|
+
if (!Array.isArray(raw)) return [];
|
|
21139
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21140
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
21141
|
+
if (seen.has(type)) return false;
|
|
21142
|
+
seen.add(type);
|
|
21143
|
+
return true;
|
|
21144
|
+
});
|
|
21145
|
+
}
|
|
21146
|
+
async function resolveProviderTypeFromPriority(args) {
|
|
21147
|
+
if (!args.providerPriority.length) {
|
|
21148
|
+
return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
|
|
21149
|
+
}
|
|
21150
|
+
const failed = [];
|
|
21151
|
+
for (const requestedType of args.providerPriority) {
|
|
21152
|
+
const normalizedType = args.providerLoader.resolveAlias(requestedType);
|
|
21153
|
+
if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
21154
|
+
failed.push(`${requestedType}: disabled`);
|
|
21155
|
+
continue;
|
|
21156
|
+
}
|
|
21157
|
+
const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
|
|
21158
|
+
args.providerLoader.setCliDetectionResults([{
|
|
21159
|
+
id: normalizedType,
|
|
21160
|
+
installed: !!detected,
|
|
21161
|
+
path: detected?.path
|
|
21162
|
+
}], false);
|
|
21163
|
+
args.onStatusChange?.();
|
|
21164
|
+
if (detected) return { providerType: normalizedType };
|
|
21165
|
+
failed.push(`${requestedType}: not detected`);
|
|
21166
|
+
}
|
|
21167
|
+
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
21168
|
+
}
|
|
21169
|
+
function loadYamlModule() {
|
|
21170
|
+
return yaml;
|
|
21171
|
+
}
|
|
21172
|
+
function getMcpServersKey(format) {
|
|
21173
|
+
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
21174
|
+
}
|
|
21175
|
+
function parseMeshCoordinatorMcpConfig(text, format) {
|
|
21176
|
+
if (!text.trim()) return {};
|
|
21177
|
+
if (format === "claude_mcp_json") return JSON.parse(text);
|
|
21178
|
+
const parsed = loadYamlModule().load(text);
|
|
21179
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
21180
|
+
}
|
|
21181
|
+
function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
21182
|
+
if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
|
|
21183
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
21184
|
+
}
|
|
20619
21185
|
var CHAT_COMMANDS = [
|
|
20620
21186
|
"send_chat",
|
|
20621
21187
|
"new_chat",
|
|
@@ -20714,6 +21280,109 @@ var DaemonCommandRouter = class {
|
|
|
20714
21280
|
constructor(deps) {
|
|
20715
21281
|
this.deps = deps;
|
|
20716
21282
|
}
|
|
21283
|
+
getCachedInlineMesh(meshId, inlineMesh) {
|
|
21284
|
+
if (inlineMesh && typeof inlineMesh === "object") {
|
|
21285
|
+
this.inlineMeshCache.set(meshId, inlineMesh);
|
|
21286
|
+
return inlineMesh;
|
|
21287
|
+
}
|
|
21288
|
+
return this.inlineMeshCache.get(meshId);
|
|
21289
|
+
}
|
|
21290
|
+
async getMeshForCommand(meshId, inlineMesh) {
|
|
21291
|
+
try {
|
|
21292
|
+
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21293
|
+
const mesh = getMesh3(meshId);
|
|
21294
|
+
if (mesh) return { mesh, inline: false };
|
|
21295
|
+
} catch {
|
|
21296
|
+
}
|
|
21297
|
+
const cached = this.getCachedInlineMesh(meshId, inlineMesh);
|
|
21298
|
+
return cached ? { mesh: cached, inline: true } : null;
|
|
21299
|
+
}
|
|
21300
|
+
updateInlineMeshNode(meshId, mesh, node) {
|
|
21301
|
+
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
21302
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
21303
|
+
if (idx >= 0) mesh.nodes[idx] = node;
|
|
21304
|
+
else mesh.nodes.push(node);
|
|
21305
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21306
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21307
|
+
}
|
|
21308
|
+
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
21309
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
21310
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
|
|
21311
|
+
if (idx === -1) return false;
|
|
21312
|
+
mesh.nodes.splice(idx, 1);
|
|
21313
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21314
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21315
|
+
return true;
|
|
21316
|
+
}
|
|
21317
|
+
normalizeMeshSessionCleanupMode(value) {
|
|
21318
|
+
return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
|
|
21319
|
+
}
|
|
21320
|
+
sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
|
|
21321
|
+
const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
|
|
21322
|
+
if (!sessionId) return false;
|
|
21323
|
+
if (sessionIds?.size) return sessionIds.has(sessionId);
|
|
21324
|
+
const workspace = typeof node?.workspace === "string" ? node.workspace : "";
|
|
21325
|
+
if (workspace && record?.workspace === workspace) return true;
|
|
21326
|
+
if (record?.meta?.meshNodeId === nodeId) return true;
|
|
21327
|
+
return false;
|
|
21328
|
+
}
|
|
21329
|
+
isCompletedHostedSession(record) {
|
|
21330
|
+
return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
|
|
21331
|
+
}
|
|
21332
|
+
async cleanupMeshSessions(args) {
|
|
21333
|
+
if (args.mode === "preserve") {
|
|
21334
|
+
return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
|
|
21335
|
+
}
|
|
21336
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
21337
|
+
const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
|
|
21338
|
+
const sessions = await this.deps.sessionHostControl.listSessions();
|
|
21339
|
+
const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
|
|
21340
|
+
const stoppedSessionIds = [];
|
|
21341
|
+
const deletedSessionIds = [];
|
|
21342
|
+
const skippedSessionIds = [];
|
|
21343
|
+
const errors = [];
|
|
21344
|
+
for (const record of matched) {
|
|
21345
|
+
const sessionId = String(record.sessionId);
|
|
21346
|
+
const completed = this.isCompletedHostedSession(record);
|
|
21347
|
+
try {
|
|
21348
|
+
if (args.mode === "stop") {
|
|
21349
|
+
if (!completed) {
|
|
21350
|
+
if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21351
|
+
stoppedSessionIds.push(sessionId);
|
|
21352
|
+
} else {
|
|
21353
|
+
skippedSessionIds.push(sessionId);
|
|
21354
|
+
}
|
|
21355
|
+
continue;
|
|
21356
|
+
}
|
|
21357
|
+
if (args.mode === "delete_stopped") {
|
|
21358
|
+
if (completed) {
|
|
21359
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
|
|
21360
|
+
deletedSessionIds.push(sessionId);
|
|
21361
|
+
} else {
|
|
21362
|
+
skippedSessionIds.push(sessionId);
|
|
21363
|
+
}
|
|
21364
|
+
continue;
|
|
21365
|
+
}
|
|
21366
|
+
if (args.mode === "stop_and_delete") {
|
|
21367
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
|
|
21368
|
+
deletedSessionIds.push(sessionId);
|
|
21369
|
+
continue;
|
|
21370
|
+
}
|
|
21371
|
+
} catch (e) {
|
|
21372
|
+
errors.push({ sessionId, error: e?.message || String(e) });
|
|
21373
|
+
}
|
|
21374
|
+
}
|
|
21375
|
+
return {
|
|
21376
|
+
success: errors.length === 0,
|
|
21377
|
+
mode: args.mode,
|
|
21378
|
+
dryRun: args.dryRun === true,
|
|
21379
|
+
matchedCount: matched.length,
|
|
21380
|
+
stoppedSessionIds,
|
|
21381
|
+
deletedSessionIds,
|
|
21382
|
+
skippedSessionIds,
|
|
21383
|
+
...errors.length ? { errors } : {}
|
|
21384
|
+
};
|
|
21385
|
+
}
|
|
20717
21386
|
async traceSessionHostAction(action, args, run, summarizeResult) {
|
|
20718
21387
|
const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
|
|
20719
21388
|
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -20833,6 +21502,9 @@ var DaemonCommandRouter = class {
|
|
|
20833
21502
|
async executeDaemonCommand(cmd, args) {
|
|
20834
21503
|
switch (cmd) {
|
|
20835
21504
|
// ─── CLI / ACP commands ───
|
|
21505
|
+
case "mesh_forward_event": {
|
|
21506
|
+
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
21507
|
+
}
|
|
20836
21508
|
case "launch_cli":
|
|
20837
21509
|
case "stop_cli":
|
|
20838
21510
|
case "set_cli_view_mode":
|
|
@@ -21377,7 +22049,26 @@ var DaemonCommandRouter = class {
|
|
|
21377
22049
|
if (!name) return { success: false, error: "name required" };
|
|
21378
22050
|
try {
|
|
21379
22051
|
const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21380
|
-
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
|
|
22052
|
+
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
|
|
22053
|
+
return { success: true, mesh };
|
|
22054
|
+
} catch (e) {
|
|
22055
|
+
return { success: false, error: e.message };
|
|
22056
|
+
}
|
|
22057
|
+
}
|
|
22058
|
+
case "update_mesh": {
|
|
22059
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22060
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22061
|
+
try {
|
|
22062
|
+
const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22063
|
+
const patch = {};
|
|
22064
|
+
if (typeof args?.name === "string") patch.name = args.name;
|
|
22065
|
+
if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
|
|
22066
|
+
if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
|
|
22067
|
+
if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
|
|
22068
|
+
if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
|
|
22069
|
+
const mesh = updateMesh2(meshId, patch);
|
|
22070
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22071
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21381
22072
|
return { success: true, mesh };
|
|
21382
22073
|
} catch (e) {
|
|
21383
22074
|
return { success: false, error: e.message };
|
|
@@ -21401,21 +22092,164 @@ var DaemonCommandRouter = class {
|
|
|
21401
22092
|
if (!workspace) return { success: false, error: "workspace required" };
|
|
21402
22093
|
try {
|
|
21403
22094
|
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21404
|
-
const
|
|
22095
|
+
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
22096
|
+
const readOnly = args?.readOnly === true;
|
|
22097
|
+
const policy = {
|
|
22098
|
+
...readOnly ? { readOnly: true } : {},
|
|
22099
|
+
...providerPriority.length ? { providerPriority } : {}
|
|
22100
|
+
};
|
|
22101
|
+
const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
|
|
21405
22102
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
21406
22103
|
return { success: true, node };
|
|
21407
22104
|
} catch (e) {
|
|
21408
22105
|
return { success: false, error: e.message };
|
|
21409
22106
|
}
|
|
21410
22107
|
}
|
|
22108
|
+
case "update_mesh_node": {
|
|
22109
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22110
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22111
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22112
|
+
try {
|
|
22113
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22114
|
+
const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
|
|
22115
|
+
if (Array.isArray(args?.providerPriority)) {
|
|
22116
|
+
const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
|
|
22117
|
+
delete policy.provider_priority;
|
|
22118
|
+
if (providerPriority.length) {
|
|
22119
|
+
policy.providerPriority = providerPriority;
|
|
22120
|
+
} else {
|
|
22121
|
+
delete policy.providerPriority;
|
|
22122
|
+
}
|
|
22123
|
+
}
|
|
22124
|
+
const node = updateNode2(meshId, nodeId, { policy });
|
|
22125
|
+
if (!node) return { success: false, error: "Mesh node not found" };
|
|
22126
|
+
return { success: true, node };
|
|
22127
|
+
} catch (e) {
|
|
22128
|
+
return { success: false, error: e.message };
|
|
22129
|
+
}
|
|
22130
|
+
}
|
|
22131
|
+
case "cleanup_mesh_sessions": {
|
|
22132
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22133
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22134
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22135
|
+
try {
|
|
22136
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22137
|
+
const mesh = meshRecord?.mesh;
|
|
22138
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22139
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22140
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
22141
|
+
const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
|
|
22142
|
+
const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
|
|
22143
|
+
const result = await this.cleanupMeshSessions({
|
|
22144
|
+
meshId,
|
|
22145
|
+
nodeId,
|
|
22146
|
+
node,
|
|
22147
|
+
mode,
|
|
22148
|
+
sessionIds,
|
|
22149
|
+
dryRun: args?.dryRun === true
|
|
22150
|
+
});
|
|
22151
|
+
return result;
|
|
22152
|
+
} catch (e) {
|
|
22153
|
+
return { success: false, error: e.message };
|
|
22154
|
+
}
|
|
22155
|
+
}
|
|
21411
22156
|
case "remove_mesh_node": {
|
|
21412
22157
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21413
22158
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
21414
22159
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
21415
22160
|
try {
|
|
21416
|
-
const
|
|
21417
|
-
const
|
|
21418
|
-
|
|
22161
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22162
|
+
const mesh = meshRecord?.mesh;
|
|
22163
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22164
|
+
const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
|
|
22165
|
+
args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
|
|
22166
|
+
);
|
|
22167
|
+
let sessionCleanup;
|
|
22168
|
+
if (node && sessionCleanupMode !== "preserve") {
|
|
22169
|
+
sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
|
|
22170
|
+
if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
|
|
22171
|
+
}
|
|
22172
|
+
if (node?.isLocalWorktree && node.workspace) {
|
|
22173
|
+
try {
|
|
22174
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
22175
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
22176
|
+
if (repoRoot) {
|
|
22177
|
+
const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22178
|
+
await removeWorktree2(repoRoot, node.workspace);
|
|
22179
|
+
}
|
|
22180
|
+
} catch (e) {
|
|
22181
|
+
LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
|
|
22182
|
+
}
|
|
22183
|
+
}
|
|
22184
|
+
let removed = false;
|
|
22185
|
+
if (meshRecord?.inline) {
|
|
22186
|
+
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
22187
|
+
} else {
|
|
22188
|
+
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22189
|
+
removed = removeNode3(meshId, nodeId);
|
|
22190
|
+
}
|
|
22191
|
+
return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
|
|
22192
|
+
} catch (e) {
|
|
22193
|
+
return { success: false, error: e.message };
|
|
22194
|
+
}
|
|
22195
|
+
}
|
|
22196
|
+
case "clone_mesh_node": {
|
|
22197
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22198
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
22199
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
22200
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
22201
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22202
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
22203
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
22204
|
+
try {
|
|
22205
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22206
|
+
const mesh = meshRecord?.mesh;
|
|
22207
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22208
|
+
const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
|
|
22209
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
22210
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
22211
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22212
|
+
const result = await createWorktree2({
|
|
22213
|
+
repoRoot,
|
|
22214
|
+
branch,
|
|
22215
|
+
baseBranch,
|
|
22216
|
+
meshName: mesh.name
|
|
22217
|
+
});
|
|
22218
|
+
let node;
|
|
22219
|
+
if (meshRecord.inline) {
|
|
22220
|
+
const { randomUUID: randomUUID8 } = await import("crypto");
|
|
22221
|
+
node = {
|
|
22222
|
+
id: `node_${randomUUID8().replace(/-/g, "")}`,
|
|
22223
|
+
workspace: result.worktreePath,
|
|
22224
|
+
repoRoot: result.worktreePath,
|
|
22225
|
+
daemonId: sourceNode.daemonId,
|
|
22226
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22227
|
+
policy: { ...sourceNode.policy || {} },
|
|
22228
|
+
isLocalWorktree: true,
|
|
22229
|
+
worktreeBranch: result.branch,
|
|
22230
|
+
clonedFromNodeId: sourceNodeId
|
|
22231
|
+
};
|
|
22232
|
+
this.updateInlineMeshNode(meshId, mesh, node);
|
|
22233
|
+
} else {
|
|
22234
|
+
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22235
|
+
node = addNode3(meshId, {
|
|
22236
|
+
workspace: result.worktreePath,
|
|
22237
|
+
repoRoot: result.worktreePath,
|
|
22238
|
+
daemonId: sourceNode.daemonId,
|
|
22239
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22240
|
+
isLocalWorktree: true,
|
|
22241
|
+
worktreeBranch: result.branch,
|
|
22242
|
+
clonedFromNodeId: sourceNodeId,
|
|
22243
|
+
policy: { ...sourceNode.policy || {} }
|
|
22244
|
+
});
|
|
22245
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
22246
|
+
}
|
|
22247
|
+
return {
|
|
22248
|
+
success: true,
|
|
22249
|
+
node,
|
|
22250
|
+
worktreePath: result.worktreePath,
|
|
22251
|
+
branch: result.branch
|
|
22252
|
+
};
|
|
21419
22253
|
} catch (e) {
|
|
21420
22254
|
return { success: false, error: e.message };
|
|
21421
22255
|
}
|
|
@@ -21423,7 +22257,7 @@ var DaemonCommandRouter = class {
|
|
|
21423
22257
|
// ─── Mesh Coordinator Launch ───
|
|
21424
22258
|
case "launch_mesh_coordinator": {
|
|
21425
22259
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21426
|
-
|
|
22260
|
+
let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
|
|
21427
22261
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
21428
22262
|
try {
|
|
21429
22263
|
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
@@ -21451,9 +22285,29 @@ var DaemonCommandRouter = class {
|
|
|
21451
22285
|
}
|
|
21452
22286
|
const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
|
|
21453
22287
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
22288
|
+
if (!cliType) {
|
|
22289
|
+
const resolved = await resolveProviderTypeFromPriority({
|
|
22290
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
|
|
22291
|
+
providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
|
|
22292
|
+
providerLoader: this.deps.providerLoader,
|
|
22293
|
+
onStatusChange: this.deps.onStatusChange
|
|
22294
|
+
});
|
|
22295
|
+
if (!resolved.providerType) {
|
|
22296
|
+
return {
|
|
22297
|
+
success: false,
|
|
22298
|
+
code: "mesh_coordinator_provider_priority_unusable",
|
|
22299
|
+
error: resolved.error || "No usable provider found from node providerPriority",
|
|
22300
|
+
meshId,
|
|
22301
|
+
cliType,
|
|
22302
|
+
workspace
|
|
22303
|
+
};
|
|
22304
|
+
}
|
|
22305
|
+
cliType = resolved.providerType;
|
|
22306
|
+
}
|
|
21454
22307
|
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
21455
22308
|
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
21456
22309
|
provider: providerMeta,
|
|
22310
|
+
cliType,
|
|
21457
22311
|
meshId,
|
|
21458
22312
|
workspace
|
|
21459
22313
|
});
|
|
@@ -21478,7 +22332,8 @@ var DaemonCommandRouter = class {
|
|
|
21478
22332
|
meshCoordinatorSetup: coordinatorSetup
|
|
21479
22333
|
};
|
|
21480
22334
|
}
|
|
21481
|
-
|
|
22335
|
+
const configFormat = coordinatorSetup.configFormat;
|
|
22336
|
+
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
21482
22337
|
return {
|
|
21483
22338
|
success: false,
|
|
21484
22339
|
code: "mesh_coordinator_unsupported",
|
|
@@ -21488,44 +22343,93 @@ var DaemonCommandRouter = class {
|
|
|
21488
22343
|
workspace
|
|
21489
22344
|
};
|
|
21490
22345
|
}
|
|
21491
|
-
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
|
|
22346
|
+
let systemPrompt = "";
|
|
22347
|
+
try {
|
|
22348
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
22349
|
+
} catch (error) {
|
|
22350
|
+
const message = error?.message || String(error);
|
|
22351
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
22352
|
+
return {
|
|
22353
|
+
success: false,
|
|
22354
|
+
code: "mesh_coordinator_prompt_failed",
|
|
22355
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
22356
|
+
meshId,
|
|
22357
|
+
cliType,
|
|
22358
|
+
workspace
|
|
22359
|
+
};
|
|
21501
22360
|
}
|
|
22361
|
+
const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
|
|
22362
|
+
const { dirname: dirname9 } = await import("path");
|
|
22363
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
22364
|
+
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
22365
|
+
const returnManualFallback = (message) => ({
|
|
22366
|
+
success: false,
|
|
22367
|
+
code: "mesh_coordinator_manual_mcp_setup_required",
|
|
22368
|
+
error: message,
|
|
22369
|
+
meshId,
|
|
22370
|
+
cliType,
|
|
22371
|
+
workspace,
|
|
22372
|
+
meshCoordinatorSetup: hermesManualFallback
|
|
22373
|
+
});
|
|
21502
22374
|
const mcpServerEntry = {
|
|
21503
22375
|
command: coordinatorSetup.mcpServer.command,
|
|
21504
22376
|
args: coordinatorSetup.mcpServer.args
|
|
21505
22377
|
};
|
|
21506
22378
|
if (args?.inlineMesh) {
|
|
21507
22379
|
mcpServerEntry.env = {
|
|
21508
|
-
ADHDEV_INLINE_MESH: JSON.stringify(mesh)
|
|
22380
|
+
ADHDEV_INLINE_MESH: JSON.stringify(mesh),
|
|
22381
|
+
ADHDEV_MCP_TRANSPORT: "ipc"
|
|
21509
22382
|
};
|
|
21510
22383
|
}
|
|
22384
|
+
try {
|
|
22385
|
+
mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
|
|
22386
|
+
} catch (error) {
|
|
22387
|
+
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
22388
|
+
LOG.error("MeshCoordinator", message);
|
|
22389
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22390
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
22391
|
+
}
|
|
22392
|
+
const hadExistingMcpConfig = existsSync23(mcpConfigPath);
|
|
22393
|
+
let existingMcpConfig = {};
|
|
22394
|
+
if (hadExistingMcpConfig) {
|
|
22395
|
+
try {
|
|
22396
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
|
|
22397
|
+
copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
|
|
22398
|
+
} catch (error) {
|
|
22399
|
+
LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
22400
|
+
return {
|
|
22401
|
+
success: false,
|
|
22402
|
+
code: "mesh_coordinator_config_parse_failed",
|
|
22403
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`
|
|
22404
|
+
};
|
|
22405
|
+
}
|
|
22406
|
+
}
|
|
22407
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
22408
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
21511
22409
|
const mcpConfig = {
|
|
21512
22410
|
...existingMcpConfig,
|
|
21513
|
-
|
|
21514
|
-
...
|
|
22411
|
+
[mcpServersKey]: {
|
|
22412
|
+
...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
|
|
21515
22413
|
[coordinatorSetup.serverName]: mcpServerEntry
|
|
21516
22414
|
}
|
|
21517
22415
|
};
|
|
21518
|
-
writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
21519
|
-
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21520
|
-
let systemPrompt = "";
|
|
21521
22416
|
try {
|
|
21522
|
-
|
|
21523
|
-
} catch {
|
|
21524
|
-
|
|
22417
|
+
writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
22418
|
+
} catch (error) {
|
|
22419
|
+
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
22420
|
+
LOG.error("MeshCoordinator", message);
|
|
22421
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22422
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21525
22423
|
}
|
|
22424
|
+
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21526
22425
|
const cliArgs = [];
|
|
22426
|
+
const launchEnv = {};
|
|
21527
22427
|
if (systemPrompt) {
|
|
21528
|
-
|
|
22428
|
+
if (configFormat === "hermes_config_yaml") {
|
|
22429
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
22430
|
+
} else {
|
|
22431
|
+
cliArgs.push("--append-system-prompt", systemPrompt);
|
|
22432
|
+
}
|
|
21529
22433
|
}
|
|
21530
22434
|
if (cliType === "claude-cli") {
|
|
21531
22435
|
cliArgs.push("--mcp-config", coordinatorSetup.configPath);
|
|
@@ -21534,6 +22438,7 @@ var DaemonCommandRouter = class {
|
|
|
21534
22438
|
cliType,
|
|
21535
22439
|
dir: workspace,
|
|
21536
22440
|
cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
|
|
22441
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
21537
22442
|
settings: {
|
|
21538
22443
|
meshCoordinatorFor: meshId
|
|
21539
22444
|
}
|
|
@@ -21713,6 +22618,12 @@ var DaemonStatusReporter = class {
|
|
|
21713
22618
|
if (providerType) {
|
|
21714
22619
|
payload.providerType = providerType;
|
|
21715
22620
|
}
|
|
22621
|
+
if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
|
|
22622
|
+
payload.providerSessionId = event.providerSessionId.trim();
|
|
22623
|
+
}
|
|
22624
|
+
if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
|
|
22625
|
+
payload.workspaceName = event.workspaceName.trim();
|
|
22626
|
+
}
|
|
21716
22627
|
if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
|
|
21717
22628
|
payload.duration = event.duration;
|
|
21718
22629
|
}
|
|
@@ -22960,7 +23871,10 @@ var ProviderInstanceManager = class {
|
|
|
22960
23871
|
this.instances.get(id).dispose();
|
|
22961
23872
|
}
|
|
22962
23873
|
this.instances.set(id, instance);
|
|
22963
|
-
await instance.init(
|
|
23874
|
+
await instance.init({
|
|
23875
|
+
...context,
|
|
23876
|
+
emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
|
|
23877
|
+
});
|
|
22964
23878
|
}
|
|
22965
23879
|
/**
|
|
22966
23880
|
* Instance remove
|
|
@@ -23122,6 +24036,17 @@ var ProviderInstanceManager = class {
|
|
|
23122
24036
|
onEvent(listener) {
|
|
23123
24037
|
this.eventListeners.push(listener);
|
|
23124
24038
|
}
|
|
24039
|
+
emitProviderEvent(providerType, instanceId, event) {
|
|
24040
|
+
const payload = {
|
|
24041
|
+
...event,
|
|
24042
|
+
providerType,
|
|
24043
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
|
|
24044
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
|
|
24045
|
+
};
|
|
24046
|
+
for (const listener of this.eventListeners) {
|
|
24047
|
+
listener(payload);
|
|
24048
|
+
}
|
|
24049
|
+
}
|
|
23125
24050
|
emitPendingEvents(providerType, state, extra = {}) {
|
|
23126
24051
|
for (const event of state.pendingEvents) {
|
|
23127
24052
|
for (const listener of this.eventListeners) {
|
|
@@ -23194,11 +24119,11 @@ var ProviderInstanceManager = class {
|
|
|
23194
24119
|
|
|
23195
24120
|
// src/providers/version-archive.ts
|
|
23196
24121
|
import * as fs11 from "fs";
|
|
23197
|
-
import * as
|
|
23198
|
-
import * as
|
|
24122
|
+
import * as path22 from "path";
|
|
24123
|
+
import * as os20 from "os";
|
|
23199
24124
|
import { execSync as execSync5 } from "child_process";
|
|
23200
24125
|
import { platform as platform8 } from "os";
|
|
23201
|
-
var ARCHIVE_PATH =
|
|
24126
|
+
var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
|
|
23202
24127
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
23203
24128
|
var VersionArchive = class {
|
|
23204
24129
|
history = {};
|
|
@@ -23245,7 +24170,7 @@ var VersionArchive = class {
|
|
|
23245
24170
|
}
|
|
23246
24171
|
save() {
|
|
23247
24172
|
try {
|
|
23248
|
-
fs11.mkdirSync(
|
|
24173
|
+
fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
|
|
23249
24174
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
23250
24175
|
} catch {
|
|
23251
24176
|
}
|
|
@@ -23301,8 +24226,8 @@ function getVersion(binary, versionCommand) {
|
|
|
23301
24226
|
function checkPathExists2(paths) {
|
|
23302
24227
|
for (const p of paths) {
|
|
23303
24228
|
if (p.includes("*")) {
|
|
23304
|
-
const home =
|
|
23305
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
24229
|
+
const home = os20.homedir();
|
|
24230
|
+
const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
|
|
23306
24231
|
if (fs11.existsSync(resolved)) return resolved;
|
|
23307
24232
|
} else {
|
|
23308
24233
|
if (fs11.existsSync(p)) return p;
|
|
@@ -23312,7 +24237,7 @@ function checkPathExists2(paths) {
|
|
|
23312
24237
|
}
|
|
23313
24238
|
function getMacAppVersion(appPath) {
|
|
23314
24239
|
if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
23315
|
-
const plistPath =
|
|
24240
|
+
const plistPath = path22.join(appPath, "Contents", "Info.plist");
|
|
23316
24241
|
if (!fs11.existsSync(plistPath)) return null;
|
|
23317
24242
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
23318
24243
|
return raw || null;
|
|
@@ -23338,7 +24263,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23338
24263
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
23339
24264
|
let resolvedBin = cliBin;
|
|
23340
24265
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
23341
|
-
const bundled =
|
|
24266
|
+
const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
23342
24267
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
23343
24268
|
}
|
|
23344
24269
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -23379,7 +24304,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23379
24304
|
// src/daemon/dev-server.ts
|
|
23380
24305
|
import * as http2 from "http";
|
|
23381
24306
|
import * as fs15 from "fs";
|
|
23382
|
-
import * as
|
|
24307
|
+
import * as path26 from "path";
|
|
23383
24308
|
init_config();
|
|
23384
24309
|
|
|
23385
24310
|
// src/daemon/scaffold-template.ts
|
|
@@ -23731,7 +24656,7 @@ init_logger();
|
|
|
23731
24656
|
// src/daemon/dev-cdp-handlers.ts
|
|
23732
24657
|
init_logger();
|
|
23733
24658
|
import * as fs12 from "fs";
|
|
23734
|
-
import * as
|
|
24659
|
+
import * as path23 from "path";
|
|
23735
24660
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
23736
24661
|
const body = await ctx.readBody(req);
|
|
23737
24662
|
const { expression, timeout, ideType } = body;
|
|
@@ -23909,17 +24834,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
23909
24834
|
return;
|
|
23910
24835
|
}
|
|
23911
24836
|
let scriptsPath = "";
|
|
23912
|
-
const directScripts =
|
|
24837
|
+
const directScripts = path23.join(dir, "scripts.js");
|
|
23913
24838
|
if (fs12.existsSync(directScripts)) {
|
|
23914
24839
|
scriptsPath = directScripts;
|
|
23915
24840
|
} else {
|
|
23916
|
-
const scriptsDir =
|
|
24841
|
+
const scriptsDir = path23.join(dir, "scripts");
|
|
23917
24842
|
if (fs12.existsSync(scriptsDir)) {
|
|
23918
24843
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
23919
|
-
return fs12.statSync(
|
|
24844
|
+
return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
|
|
23920
24845
|
}).sort().reverse();
|
|
23921
24846
|
for (const ver of versions) {
|
|
23922
|
-
const p =
|
|
24847
|
+
const p = path23.join(scriptsDir, ver, "scripts.js");
|
|
23923
24848
|
if (fs12.existsSync(p)) {
|
|
23924
24849
|
scriptsPath = p;
|
|
23925
24850
|
break;
|
|
@@ -24748,7 +25673,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
24748
25673
|
|
|
24749
25674
|
// src/daemon/dev-cli-debug.ts
|
|
24750
25675
|
import * as fs13 from "fs";
|
|
24751
|
-
import * as
|
|
25676
|
+
import * as path24 from "path";
|
|
24752
25677
|
function slugifyFixtureName(value) {
|
|
24753
25678
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24754
25679
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -24758,11 +25683,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
24758
25683
|
if (!providerDir) {
|
|
24759
25684
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
24760
25685
|
}
|
|
24761
|
-
return
|
|
25686
|
+
return path24.join(providerDir, "fixtures");
|
|
24762
25687
|
}
|
|
24763
25688
|
function readCliFixture(ctx, type, name) {
|
|
24764
25689
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
24765
|
-
const filePath =
|
|
25690
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
24766
25691
|
if (!fs13.existsSync(filePath)) {
|
|
24767
25692
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
24768
25693
|
}
|
|
@@ -25529,7 +26454,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
25529
26454
|
},
|
|
25530
26455
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
25531
26456
|
};
|
|
25532
|
-
const filePath =
|
|
26457
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
25533
26458
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
25534
26459
|
ctx.json(res, 200, {
|
|
25535
26460
|
saved: true,
|
|
@@ -25553,7 +26478,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
25553
26478
|
return;
|
|
25554
26479
|
}
|
|
25555
26480
|
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 =
|
|
26481
|
+
const fullPath = path24.join(fixtureDir, file);
|
|
25557
26482
|
try {
|
|
25558
26483
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
25559
26484
|
return {
|
|
@@ -25689,8 +26614,8 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
25689
26614
|
|
|
25690
26615
|
// src/daemon/dev-auto-implement.ts
|
|
25691
26616
|
import * as fs14 from "fs";
|
|
25692
|
-
import * as
|
|
25693
|
-
import * as
|
|
26617
|
+
import * as path25 from "path";
|
|
26618
|
+
import * as os21 from "os";
|
|
25694
26619
|
function getAutoImplPid(ctx) {
|
|
25695
26620
|
const pid = ctx.autoImplProcess?.pid;
|
|
25696
26621
|
return typeof pid === "number" && pid > 0 ? pid : null;
|
|
@@ -25739,22 +26664,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
25739
26664
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
25740
26665
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
25741
26666
|
try {
|
|
25742
|
-
return fs14.statSync(
|
|
26667
|
+
return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
25743
26668
|
} catch {
|
|
25744
26669
|
return false;
|
|
25745
26670
|
}
|
|
25746
26671
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
25747
26672
|
if (versions.length === 0) return null;
|
|
25748
|
-
return
|
|
26673
|
+
return path25.join(scriptsDir, versions[0]);
|
|
25749
26674
|
}
|
|
25750
26675
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
25751
|
-
const canonicalUserDir =
|
|
25752
|
-
const desiredDir = requestedDir ?
|
|
25753
|
-
const upstreamRoot =
|
|
25754
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
26676
|
+
const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
26677
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
26678
|
+
const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
|
|
26679
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
25755
26680
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
25756
26681
|
}
|
|
25757
|
-
if (
|
|
26682
|
+
if (path25.basename(desiredDir) !== type) {
|
|
25758
26683
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
25759
26684
|
}
|
|
25760
26685
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -25762,11 +26687,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
25762
26687
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
25763
26688
|
}
|
|
25764
26689
|
if (!fs14.existsSync(desiredDir)) {
|
|
25765
|
-
fs14.mkdirSync(
|
|
26690
|
+
fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
25766
26691
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
25767
26692
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
25768
26693
|
}
|
|
25769
|
-
const providerJson =
|
|
26694
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
25770
26695
|
if (!fs14.existsSync(providerJson)) {
|
|
25771
26696
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
25772
26697
|
}
|
|
@@ -25777,13 +26702,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
25777
26702
|
const refDir = ctx.findProviderDir(referenceType);
|
|
25778
26703
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
25779
26704
|
const referenceScripts = {};
|
|
25780
|
-
const scriptsDir =
|
|
26705
|
+
const scriptsDir = path25.join(refDir, "scripts");
|
|
25781
26706
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
25782
26707
|
if (!latestDir) return referenceScripts;
|
|
25783
26708
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
25784
26709
|
if (!file.endsWith(".js")) continue;
|
|
25785
26710
|
try {
|
|
25786
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
26711
|
+
referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
|
|
25787
26712
|
} catch {
|
|
25788
26713
|
}
|
|
25789
26714
|
}
|
|
@@ -25891,9 +26816,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
25891
26816
|
});
|
|
25892
26817
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
25893
26818
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
25894
|
-
const tmpDir =
|
|
26819
|
+
const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
|
|
25895
26820
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
25896
|
-
const promptFile =
|
|
26821
|
+
const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
25897
26822
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
25898
26823
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
25899
26824
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -26046,7 +26971,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26046
26971
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
26047
26972
|
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
26048
26973
|
let shellCmd;
|
|
26049
|
-
const isWin =
|
|
26974
|
+
const isWin = os21.platform() === "win32";
|
|
26050
26975
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
26051
26976
|
const promptMode = autoImpl?.promptMode ?? "stdin";
|
|
26052
26977
|
const extraArgs = autoImpl?.extraArgs ?? [];
|
|
@@ -26085,7 +27010,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26085
27010
|
try {
|
|
26086
27011
|
const pty = __require("node-pty");
|
|
26087
27012
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
26088
|
-
const isWin2 =
|
|
27013
|
+
const isWin2 = os21.platform() === "win32";
|
|
26089
27014
|
child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
26090
27015
|
name: "xterm-256color",
|
|
26091
27016
|
cols: 120,
|
|
@@ -26325,7 +27250,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26325
27250
|
setMode: "set_mode.js"
|
|
26326
27251
|
};
|
|
26327
27252
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26328
|
-
const scriptsDir =
|
|
27253
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26329
27254
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26330
27255
|
if (latestScriptsDir) {
|
|
26331
27256
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26336,7 +27261,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26336
27261
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
26337
27262
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26338
27263
|
try {
|
|
26339
|
-
const content = fs14.readFileSync(
|
|
27264
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26340
27265
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26341
27266
|
lines.push("```javascript");
|
|
26342
27267
|
lines.push(content);
|
|
@@ -26353,7 +27278,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26353
27278
|
lines.push("");
|
|
26354
27279
|
for (const file of refFiles) {
|
|
26355
27280
|
try {
|
|
26356
|
-
const content = fs14.readFileSync(
|
|
27281
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26357
27282
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26358
27283
|
lines.push("```javascript");
|
|
26359
27284
|
lines.push(content);
|
|
@@ -26394,10 +27319,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26394
27319
|
lines.push("");
|
|
26395
27320
|
}
|
|
26396
27321
|
}
|
|
26397
|
-
const docsDir =
|
|
27322
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26398
27323
|
const loadGuide = (name) => {
|
|
26399
27324
|
try {
|
|
26400
|
-
const p =
|
|
27325
|
+
const p = path25.join(docsDir, name);
|
|
26401
27326
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26402
27327
|
} catch {
|
|
26403
27328
|
}
|
|
@@ -26634,7 +27559,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26634
27559
|
parseApproval: "parse_approval.js"
|
|
26635
27560
|
};
|
|
26636
27561
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26637
|
-
const scriptsDir =
|
|
27562
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26638
27563
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26639
27564
|
if (latestScriptsDir) {
|
|
26640
27565
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26646,7 +27571,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26646
27571
|
if (!file.endsWith(".js")) continue;
|
|
26647
27572
|
if (!targetFileNames.has(file)) continue;
|
|
26648
27573
|
try {
|
|
26649
|
-
const content = fs14.readFileSync(
|
|
27574
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26650
27575
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26651
27576
|
lines.push("```javascript");
|
|
26652
27577
|
lines.push(content);
|
|
@@ -26662,7 +27587,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26662
27587
|
lines.push("");
|
|
26663
27588
|
for (const file of refFiles) {
|
|
26664
27589
|
try {
|
|
26665
|
-
const content = fs14.readFileSync(
|
|
27590
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26666
27591
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26667
27592
|
lines.push("```javascript");
|
|
26668
27593
|
lines.push(content);
|
|
@@ -26695,10 +27620,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26695
27620
|
lines.push("");
|
|
26696
27621
|
}
|
|
26697
27622
|
}
|
|
26698
|
-
const docsDir =
|
|
27623
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26699
27624
|
const loadGuide = (name) => {
|
|
26700
27625
|
try {
|
|
26701
|
-
const p =
|
|
27626
|
+
const p = path25.join(docsDir, name);
|
|
26702
27627
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26703
27628
|
} catch {
|
|
26704
27629
|
}
|
|
@@ -27145,8 +28070,8 @@ var DevServer = class _DevServer {
|
|
|
27145
28070
|
}
|
|
27146
28071
|
getEndpointList() {
|
|
27147
28072
|
return this.routes.map((r) => {
|
|
27148
|
-
const
|
|
27149
|
-
return `${r.method.padEnd(5)} ${
|
|
28073
|
+
const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
28074
|
+
return `${r.method.padEnd(5)} ${path27}`;
|
|
27150
28075
|
});
|
|
27151
28076
|
}
|
|
27152
28077
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -27434,12 +28359,12 @@ var DevServer = class _DevServer {
|
|
|
27434
28359
|
// ─── DevConsole SPA ───
|
|
27435
28360
|
getConsoleDistDir() {
|
|
27436
28361
|
const candidates = [
|
|
27437
|
-
|
|
27438
|
-
|
|
27439
|
-
|
|
28362
|
+
path26.resolve(__dirname, "../../web-devconsole/dist"),
|
|
28363
|
+
path26.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
28364
|
+
path26.join(process.cwd(), "packages/web-devconsole/dist")
|
|
27440
28365
|
];
|
|
27441
28366
|
for (const dir of candidates) {
|
|
27442
|
-
if (fs15.existsSync(
|
|
28367
|
+
if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
|
|
27443
28368
|
}
|
|
27444
28369
|
return null;
|
|
27445
28370
|
}
|
|
@@ -27449,7 +28374,7 @@ var DevServer = class _DevServer {
|
|
|
27449
28374
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
27450
28375
|
return;
|
|
27451
28376
|
}
|
|
27452
|
-
const htmlPath =
|
|
28377
|
+
const htmlPath = path26.join(distDir, "index.html");
|
|
27453
28378
|
try {
|
|
27454
28379
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
27455
28380
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -27474,15 +28399,15 @@ var DevServer = class _DevServer {
|
|
|
27474
28399
|
this.json(res, 404, { error: "Not found" });
|
|
27475
28400
|
return;
|
|
27476
28401
|
}
|
|
27477
|
-
const safePath =
|
|
27478
|
-
const filePath =
|
|
28402
|
+
const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
|
|
28403
|
+
const filePath = path26.join(distDir, safePath);
|
|
27479
28404
|
if (!filePath.startsWith(distDir)) {
|
|
27480
28405
|
this.json(res, 403, { error: "Forbidden" });
|
|
27481
28406
|
return;
|
|
27482
28407
|
}
|
|
27483
28408
|
try {
|
|
27484
28409
|
const content = fs15.readFileSync(filePath);
|
|
27485
|
-
const ext =
|
|
28410
|
+
const ext = path26.extname(filePath);
|
|
27486
28411
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
27487
28412
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
27488
28413
|
res.end(content);
|
|
@@ -27595,9 +28520,9 @@ var DevServer = class _DevServer {
|
|
|
27595
28520
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27596
28521
|
if (entry.isDirectory()) {
|
|
27597
28522
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
27598
|
-
scan(
|
|
28523
|
+
scan(path26.join(d, entry.name), rel);
|
|
27599
28524
|
} else {
|
|
27600
|
-
const stat2 = fs15.statSync(
|
|
28525
|
+
const stat2 = fs15.statSync(path26.join(d, entry.name));
|
|
27601
28526
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
27602
28527
|
}
|
|
27603
28528
|
}
|
|
@@ -27620,7 +28545,7 @@ var DevServer = class _DevServer {
|
|
|
27620
28545
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27621
28546
|
return;
|
|
27622
28547
|
}
|
|
27623
|
-
const fullPath =
|
|
28548
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27624
28549
|
if (!fullPath.startsWith(dir)) {
|
|
27625
28550
|
this.json(res, 403, { error: "Forbidden" });
|
|
27626
28551
|
return;
|
|
@@ -27645,14 +28570,14 @@ var DevServer = class _DevServer {
|
|
|
27645
28570
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27646
28571
|
return;
|
|
27647
28572
|
}
|
|
27648
|
-
const fullPath =
|
|
28573
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27649
28574
|
if (!fullPath.startsWith(dir)) {
|
|
27650
28575
|
this.json(res, 403, { error: "Forbidden" });
|
|
27651
28576
|
return;
|
|
27652
28577
|
}
|
|
27653
28578
|
try {
|
|
27654
28579
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
27655
|
-
fs15.mkdirSync(
|
|
28580
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27656
28581
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27657
28582
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
27658
28583
|
this.providerLoader.reload();
|
|
@@ -27669,7 +28594,7 @@ var DevServer = class _DevServer {
|
|
|
27669
28594
|
return;
|
|
27670
28595
|
}
|
|
27671
28596
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
27672
|
-
const p =
|
|
28597
|
+
const p = path26.join(dir, name);
|
|
27673
28598
|
if (fs15.existsSync(p)) {
|
|
27674
28599
|
const source = fs15.readFileSync(p, "utf-8");
|
|
27675
28600
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -27690,8 +28615,8 @@ var DevServer = class _DevServer {
|
|
|
27690
28615
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
27691
28616
|
return;
|
|
27692
28617
|
}
|
|
27693
|
-
const target = fs15.existsSync(
|
|
27694
|
-
const targetPath =
|
|
28618
|
+
const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
28619
|
+
const targetPath = path26.join(dir, target);
|
|
27695
28620
|
try {
|
|
27696
28621
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
27697
28622
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -27838,7 +28763,7 @@ var DevServer = class _DevServer {
|
|
|
27838
28763
|
}
|
|
27839
28764
|
let targetDir;
|
|
27840
28765
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
27841
|
-
const jsonPath =
|
|
28766
|
+
const jsonPath = path26.join(targetDir, "provider.json");
|
|
27842
28767
|
if (fs15.existsSync(jsonPath)) {
|
|
27843
28768
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
27844
28769
|
return;
|
|
@@ -27850,8 +28775,8 @@ var DevServer = class _DevServer {
|
|
|
27850
28775
|
const createdFiles = ["provider.json"];
|
|
27851
28776
|
if (result.files) {
|
|
27852
28777
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
27853
|
-
const fullPath =
|
|
27854
|
-
fs15.mkdirSync(
|
|
28778
|
+
const fullPath = path26.join(targetDir, relPath);
|
|
28779
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27855
28780
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27856
28781
|
createdFiles.push(relPath);
|
|
27857
28782
|
}
|
|
@@ -27904,22 +28829,22 @@ var DevServer = class _DevServer {
|
|
|
27904
28829
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
27905
28830
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
27906
28831
|
try {
|
|
27907
|
-
return fs15.statSync(
|
|
28832
|
+
return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
|
|
27908
28833
|
} catch {
|
|
27909
28834
|
return false;
|
|
27910
28835
|
}
|
|
27911
28836
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
27912
28837
|
if (versions.length === 0) return null;
|
|
27913
|
-
return
|
|
28838
|
+
return path26.join(scriptsDir, versions[0]);
|
|
27914
28839
|
}
|
|
27915
28840
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
27916
|
-
const canonicalUserDir =
|
|
27917
|
-
const desiredDir = requestedDir ?
|
|
27918
|
-
const upstreamRoot =
|
|
27919
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
28841
|
+
const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
28842
|
+
const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
|
|
28843
|
+
const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
|
|
28844
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
|
|
27920
28845
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
27921
28846
|
}
|
|
27922
|
-
if (
|
|
28847
|
+
if (path26.basename(desiredDir) !== type) {
|
|
27923
28848
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
27924
28849
|
}
|
|
27925
28850
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -27927,11 +28852,11 @@ var DevServer = class _DevServer {
|
|
|
27927
28852
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
27928
28853
|
}
|
|
27929
28854
|
if (!fs15.existsSync(desiredDir)) {
|
|
27930
|
-
fs15.mkdirSync(
|
|
28855
|
+
fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
|
|
27931
28856
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
27932
28857
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
27933
28858
|
}
|
|
27934
|
-
const providerJson =
|
|
28859
|
+
const providerJson = path26.join(desiredDir, "provider.json");
|
|
27935
28860
|
if (!fs15.existsSync(providerJson)) {
|
|
27936
28861
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
27937
28862
|
}
|
|
@@ -27967,7 +28892,7 @@ var DevServer = class _DevServer {
|
|
|
27967
28892
|
setMode: "set_mode.js"
|
|
27968
28893
|
};
|
|
27969
28894
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
27970
|
-
const scriptsDir =
|
|
28895
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
27971
28896
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
27972
28897
|
if (latestScriptsDir) {
|
|
27973
28898
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -27978,7 +28903,7 @@ var DevServer = class _DevServer {
|
|
|
27978
28903
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
27979
28904
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
27980
28905
|
try {
|
|
27981
|
-
const content = fs15.readFileSync(
|
|
28906
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
27982
28907
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
27983
28908
|
lines.push("```javascript");
|
|
27984
28909
|
lines.push(content);
|
|
@@ -27995,7 +28920,7 @@ var DevServer = class _DevServer {
|
|
|
27995
28920
|
lines.push("");
|
|
27996
28921
|
for (const file of refFiles) {
|
|
27997
28922
|
try {
|
|
27998
|
-
const content = fs15.readFileSync(
|
|
28923
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
27999
28924
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28000
28925
|
lines.push("```javascript");
|
|
28001
28926
|
lines.push(content);
|
|
@@ -28036,10 +28961,10 @@ var DevServer = class _DevServer {
|
|
|
28036
28961
|
lines.push("");
|
|
28037
28962
|
}
|
|
28038
28963
|
}
|
|
28039
|
-
const docsDir =
|
|
28964
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28040
28965
|
const loadGuide = (name) => {
|
|
28041
28966
|
try {
|
|
28042
|
-
const p =
|
|
28967
|
+
const p = path26.join(docsDir, name);
|
|
28043
28968
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28044
28969
|
} catch {
|
|
28045
28970
|
}
|
|
@@ -28213,7 +29138,7 @@ var DevServer = class _DevServer {
|
|
|
28213
29138
|
parseApproval: "parse_approval.js"
|
|
28214
29139
|
};
|
|
28215
29140
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28216
|
-
const scriptsDir =
|
|
29141
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28217
29142
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28218
29143
|
if (latestScriptsDir) {
|
|
28219
29144
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28225,7 +29150,7 @@ var DevServer = class _DevServer {
|
|
|
28225
29150
|
if (!file.endsWith(".js")) continue;
|
|
28226
29151
|
if (!targetFileNames.has(file)) continue;
|
|
28227
29152
|
try {
|
|
28228
|
-
const content = fs15.readFileSync(
|
|
29153
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28229
29154
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28230
29155
|
lines.push("```javascript");
|
|
28231
29156
|
lines.push(content);
|
|
@@ -28241,7 +29166,7 @@ var DevServer = class _DevServer {
|
|
|
28241
29166
|
lines.push("");
|
|
28242
29167
|
for (const file of refFiles) {
|
|
28243
29168
|
try {
|
|
28244
|
-
const content = fs15.readFileSync(
|
|
29169
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28245
29170
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28246
29171
|
lines.push("```javascript");
|
|
28247
29172
|
lines.push(content);
|
|
@@ -28274,10 +29199,10 @@ var DevServer = class _DevServer {
|
|
|
28274
29199
|
lines.push("");
|
|
28275
29200
|
}
|
|
28276
29201
|
}
|
|
28277
|
-
const docsDir =
|
|
29202
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28278
29203
|
const loadGuide = (name) => {
|
|
28279
29204
|
try {
|
|
28280
|
-
const p =
|
|
29205
|
+
const p = path26.join(docsDir, name);
|
|
28281
29206
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28282
29207
|
} catch {
|
|
28283
29208
|
}
|
|
@@ -29282,48 +30207,6 @@ var SessionRegistry = class {
|
|
|
29282
30207
|
// src/boot/daemon-lifecycle.ts
|
|
29283
30208
|
init_logger();
|
|
29284
30209
|
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
30210
|
async function initDaemonComponents(config) {
|
|
29328
30211
|
installGlobalInterceptor();
|
|
29329
30212
|
const appConfig = loadConfig();
|
|
@@ -29629,6 +30512,7 @@ export {
|
|
|
29629
30512
|
createGitWorkspaceMonitor,
|
|
29630
30513
|
createInteractionId,
|
|
29631
30514
|
createMesh,
|
|
30515
|
+
createWorktree,
|
|
29632
30516
|
deleteMesh,
|
|
29633
30517
|
detectAllVersions,
|
|
29634
30518
|
detectCLIs,
|
|
@@ -29681,6 +30565,7 @@ export {
|
|
|
29681
30565
|
launchWithCdp,
|
|
29682
30566
|
listHostedCliRuntimes,
|
|
29683
30567
|
listMeshes,
|
|
30568
|
+
listWorktrees,
|
|
29684
30569
|
loadConfig,
|
|
29685
30570
|
loadState,
|
|
29686
30571
|
logCommand,
|
|
@@ -29700,6 +30585,7 @@ export {
|
|
|
29700
30585
|
normalizeSessionModalFields,
|
|
29701
30586
|
parsePorcelainV2Status,
|
|
29702
30587
|
parseProviderSourceConfigUpdate,
|
|
30588
|
+
parseWorktreeListOutput,
|
|
29703
30589
|
partitionSessionHostDiagnosticsSessions,
|
|
29704
30590
|
partitionSessionHostRecords,
|
|
29705
30591
|
prepareSessionChatTailUpdate,
|
|
@@ -29709,6 +30595,7 @@ export {
|
|
|
29709
30595
|
recordDebugTrace,
|
|
29710
30596
|
registerExtensionProviders,
|
|
29711
30597
|
removeNode,
|
|
30598
|
+
removeWorktree,
|
|
29712
30599
|
resetConfig,
|
|
29713
30600
|
resetDebugRuntimeConfig,
|
|
29714
30601
|
resetState,
|
|
@@ -29718,6 +30605,7 @@ export {
|
|
|
29718
30605
|
resolveGitRepository,
|
|
29719
30606
|
resolveSessionHostAppName,
|
|
29720
30607
|
resolveSessionHostAppNameResolution,
|
|
30608
|
+
resolveWorktreePath,
|
|
29721
30609
|
runAsyncBatch,
|
|
29722
30610
|
runGit,
|
|
29723
30611
|
saveConfig,
|