@adhdev/daemon-core 0.9.76-rc.6 → 0.9.76-rc.60
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.d.ts +2 -2
- package/dist/index.js +1525 -446
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1550 -477
- 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 +27 -0
- package/dist/session-host/runtime-support.d.ts +2 -1
- package/dist/shared-types.d.ts +4 -0
- package/dist/types.d.ts +9 -0
- package/package.json +4 -5
- package/src/cli-adapters/provider-cli-adapter.ts +28 -7
- package/src/cli-adapters/provider-cli-runtime.ts +3 -2
- package/src/commands/chat-commands.ts +126 -11
- package/src/commands/cli-manager.ts +78 -5
- package/src/commands/handler.ts +13 -4
- package/src/commands/mesh-coordinator.ts +148 -5
- package/src/commands/router.d.ts +1 -0
- package/src/commands/router.ts +553 -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/index.ts +3 -0
- package/src/mesh/coordinator-prompt.ts +29 -14
- package/src/mesh/mesh-events.ts +109 -43
- package/src/providers/chat-message-normalization.ts +80 -0
- package/src/providers/cli-provider-instance.d.ts +2 -0
- package/src/providers/cli-provider-instance.ts +93 -8
- package/src/providers/provider-instance-manager.ts +20 -1
- package/src/providers/provider-instance.ts +2 -0
- package/src/providers/read-chat-contract.ts +8 -0
- package/src/repo-mesh-types.ts +30 -0
- package/src/session-host/runtime-support.ts +55 -7
- package/src/shared-types.ts +4 -0
- package/src/status/builders.ts +17 -12
- package/src/status/reporter.ts +6 -0
- package/src/types.ts +9 -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.** Treat delegated agent summaries as self-reports, not verification. Verify side effects via \`mesh_git_status\` (including related repo freshness when configured), not by reading source files.
|
|
669
|
+
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed. Never launch a duplicate session or second worker solely because \`mesh_read_chat\` has no final assistant message while the delegated session is still showing tool/terminal activity.
|
|
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.
|
|
537
|
-
|
|
538
|
-
|
|
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.
|
|
705
|
+
4. **Monitor** \u2014 Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly just because the delegated session has not produced a final assistant message yet; tool/terminal activity means work may still be in progress. Do not call \`mesh_read_chat\` again within a few seconds for the same generating session; wait for the completion callback/status event instead unless you are debugging a real stall. Use at most one compact \`mesh_read_chat\` check after a completion/approval signal, an explicit user status request, or a real timeout/stall. Handle approvals via \`mesh_approve\`.
|
|
706
|
+
5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
|
|
539
707
|
6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
|
|
540
|
-
7. **
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
- **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
|
|
544
|
-
- **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
|
|
545
|
-
- **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
|
|
546
|
-
- **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
|
|
547
|
-
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
|
|
548
|
-
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
549
|
-
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
550
|
-
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
551
|
-
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
|
|
708
|
+
7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
|
|
709
|
+
8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
|
|
552
710
|
}
|
|
553
711
|
});
|
|
554
712
|
|
|
555
713
|
// src/logging/logger.ts
|
|
556
714
|
import * as fs2 from "fs";
|
|
557
|
-
import * as
|
|
715
|
+
import * as path10 from "path";
|
|
558
716
|
import * as os4 from "os";
|
|
559
717
|
function setLogLevel(level) {
|
|
560
718
|
currentLevel = level;
|
|
@@ -570,13 +728,13 @@ function getDaemonLogDir() {
|
|
|
570
728
|
return LOG_DIR;
|
|
571
729
|
}
|
|
572
730
|
function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
|
|
573
|
-
return
|
|
731
|
+
return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
|
|
574
732
|
}
|
|
575
733
|
function checkDateRotation() {
|
|
576
734
|
const today = getDateStr();
|
|
577
735
|
if (today !== currentDate) {
|
|
578
736
|
currentDate = today;
|
|
579
|
-
currentLogFile =
|
|
737
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
580
738
|
cleanOldLogs();
|
|
581
739
|
}
|
|
582
740
|
}
|
|
@@ -590,7 +748,7 @@ function cleanOldLogs() {
|
|
|
590
748
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
591
749
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
592
750
|
try {
|
|
593
|
-
fs2.unlinkSync(
|
|
751
|
+
fs2.unlinkSync(path10.join(LOG_DIR, file));
|
|
594
752
|
} catch {
|
|
595
753
|
}
|
|
596
754
|
}
|
|
@@ -713,7 +871,7 @@ var init_logger = __esm({
|
|
|
713
871
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
714
872
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
715
873
|
currentLevel = "info";
|
|
716
|
-
LOG_DIR = process.platform === "win32" ?
|
|
874
|
+
LOG_DIR = process.platform === "win32" ? path10.join(process.env.LOCALAPPDATA || process.env.APPDATA || path10.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path10.join(os4.homedir(), "Library", "Logs", "adhdev") : path10.join(os4.homedir(), ".local", "share", "adhdev", "logs");
|
|
717
875
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
718
876
|
MAX_LOG_DAYS = 7;
|
|
719
877
|
try {
|
|
@@ -721,16 +879,16 @@ var init_logger = __esm({
|
|
|
721
879
|
} catch {
|
|
722
880
|
}
|
|
723
881
|
currentDate = getDateStr();
|
|
724
|
-
currentLogFile =
|
|
882
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
725
883
|
cleanOldLogs();
|
|
726
884
|
try {
|
|
727
|
-
const oldLog =
|
|
885
|
+
const oldLog = path10.join(LOG_DIR, "daemon.log");
|
|
728
886
|
if (fs2.existsSync(oldLog)) {
|
|
729
887
|
const stat2 = fs2.statSync(oldLog);
|
|
730
888
|
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
731
|
-
fs2.renameSync(oldLog,
|
|
889
|
+
fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
732
890
|
}
|
|
733
|
-
const oldLogBackup =
|
|
891
|
+
const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
|
|
734
892
|
if (fs2.existsSync(oldLogBackup)) {
|
|
735
893
|
fs2.unlinkSync(oldLogBackup);
|
|
736
894
|
}
|
|
@@ -762,7 +920,7 @@ var init_logger = __esm({
|
|
|
762
920
|
}
|
|
763
921
|
};
|
|
764
922
|
interceptorInstalled = false;
|
|
765
|
-
LOG_PATH =
|
|
923
|
+
LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
766
924
|
}
|
|
767
925
|
});
|
|
768
926
|
|
|
@@ -1171,7 +1329,7 @@ var init_pty_transport = __esm({
|
|
|
1171
1329
|
|
|
1172
1330
|
// src/cli-adapters/provider-cli-shared.ts
|
|
1173
1331
|
import * as os9 from "os";
|
|
1174
|
-
import * as
|
|
1332
|
+
import * as path14 from "path";
|
|
1175
1333
|
import { execSync as execSync3 } from "child_process";
|
|
1176
1334
|
function stripAnsi(str) {
|
|
1177
1335
|
return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
|
|
@@ -1236,9 +1394,9 @@ function buildCliScreenSnapshot(text) {
|
|
|
1236
1394
|
function findBinary(name) {
|
|
1237
1395
|
const trimmed = String(name || "").trim();
|
|
1238
1396
|
if (!trimmed) return trimmed;
|
|
1239
|
-
const expanded = trimmed.startsWith("~") ?
|
|
1240
|
-
if (
|
|
1241
|
-
return
|
|
1397
|
+
const expanded = trimmed.startsWith("~") ? path14.join(os9.homedir(), trimmed.slice(1)) : trimmed;
|
|
1398
|
+
if (path14.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
|
|
1399
|
+
return path14.isAbsolute(expanded) ? expanded : path14.resolve(expanded);
|
|
1242
1400
|
}
|
|
1243
1401
|
const isWin = os9.platform() === "win32";
|
|
1244
1402
|
try {
|
|
@@ -1254,7 +1412,7 @@ function findBinary(name) {
|
|
|
1254
1412
|
}
|
|
1255
1413
|
}
|
|
1256
1414
|
function isScriptBinary(binaryPath) {
|
|
1257
|
-
if (!
|
|
1415
|
+
if (!path14.isAbsolute(binaryPath)) return false;
|
|
1258
1416
|
try {
|
|
1259
1417
|
const fs16 = __require("fs");
|
|
1260
1418
|
const resolved = fs16.realpathSync(binaryPath);
|
|
@@ -1270,7 +1428,7 @@ function isScriptBinary(binaryPath) {
|
|
|
1270
1428
|
}
|
|
1271
1429
|
}
|
|
1272
1430
|
function looksLikeMachOOrElf(filePath) {
|
|
1273
|
-
if (!
|
|
1431
|
+
if (!path14.isAbsolute(filePath)) return false;
|
|
1274
1432
|
try {
|
|
1275
1433
|
const fs16 = __require("fs");
|
|
1276
1434
|
const resolved = fs16.realpathSync(filePath);
|
|
@@ -1484,10 +1642,10 @@ var init_provider_cli_config = __esm({
|
|
|
1484
1642
|
|
|
1485
1643
|
// src/cli-adapters/provider-cli-runtime.ts
|
|
1486
1644
|
import * as os10 from "os";
|
|
1487
|
-
import * as
|
|
1645
|
+
import * as path15 from "path";
|
|
1488
1646
|
import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from "@adhdev/session-host-core";
|
|
1489
1647
|
function resolveCliSpawnPlan(options) {
|
|
1490
|
-
const { provider, runtimeSettings, workingDir, extraArgs } = options;
|
|
1648
|
+
const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
|
|
1491
1649
|
const { spawn: spawnConfig } = provider;
|
|
1492
1650
|
const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
|
|
1493
1651
|
const binaryPath = findBinary(configuredCommand);
|
|
@@ -1495,9 +1653,9 @@ function resolveCliSpawnPlan(options) {
|
|
|
1495
1653
|
const allArgs = [...spawnConfig.args, ...extraArgs];
|
|
1496
1654
|
let shellCmd;
|
|
1497
1655
|
let shellArgs;
|
|
1498
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1656
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1499
1657
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
1500
|
-
const useShellWin = !!spawnConfig.shell || isCmdShim || !
|
|
1658
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
1501
1659
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
1502
1660
|
if (useShell) {
|
|
1503
1661
|
shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
|
|
@@ -1511,7 +1669,7 @@ function resolveCliSpawnPlan(options) {
|
|
|
1511
1669
|
shellCmd = binaryPath;
|
|
1512
1670
|
shellArgs = allArgs;
|
|
1513
1671
|
}
|
|
1514
|
-
const env = buildCliSpawnEnv(process.env, spawnConfig.env);
|
|
1672
|
+
const env = buildCliSpawnEnv(process.env, { ...spawnConfig.env || {}, ...extraEnv || {} });
|
|
1515
1673
|
env.TERMINAL_CWD = workingDir;
|
|
1516
1674
|
return {
|
|
1517
1675
|
binaryPath,
|
|
@@ -1610,8 +1768,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1610
1768
|
init_provider_cli_runtime();
|
|
1611
1769
|
init_provider_cli_shared();
|
|
1612
1770
|
ProviderCliAdapter = class _ProviderCliAdapter {
|
|
1613
|
-
constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
|
|
1771
|
+
constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
|
|
1614
1772
|
this.extraArgs = extraArgs;
|
|
1773
|
+
this.extraEnv = extraEnv;
|
|
1615
1774
|
this.provider = provider;
|
|
1616
1775
|
this.transportFactory = transportFactory;
|
|
1617
1776
|
this.cliType = provider.type;
|
|
@@ -1762,8 +1921,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1762
1921
|
const currentSnapshot = normalizeScreenSnapshot(screenText);
|
|
1763
1922
|
const lastSnapshot = this.lastScreenSnapshot;
|
|
1764
1923
|
if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
|
|
1765
|
-
const
|
|
1766
|
-
const
|
|
1924
|
+
const activeScreenPattern = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel|Enter to confirm\s*[·•-]\s*Esc to cancel|\b(?:MCP servers?|tool calls?)\b[^\n\r]{0,160}\brequire approval\b/i;
|
|
1925
|
+
const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
|
|
1926
|
+
const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
|
|
1767
1927
|
if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
|
|
1768
1928
|
if (currentSnapshot.length >= lastSnapshot.length) return screenText;
|
|
1769
1929
|
return `${screenText}
|
|
@@ -1926,7 +2086,8 @@ ${lastSnapshot}`;
|
|
|
1926
2086
|
provider: this.provider,
|
|
1927
2087
|
runtimeSettings: this.runtimeSettings,
|
|
1928
2088
|
workingDir: this.workingDir,
|
|
1929
|
-
extraArgs: this.extraArgs
|
|
2089
|
+
extraArgs: this.extraArgs,
|
|
2090
|
+
extraEnv: this.extraEnv
|
|
1930
2091
|
});
|
|
1931
2092
|
LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
1932
2093
|
this.resetTraceSession();
|
|
@@ -3124,9 +3285,8 @@ ${lastSnapshot}`;
|
|
|
3124
3285
|
};
|
|
3125
3286
|
this.recordTrace("submit_echo_missing", diagnostic);
|
|
3126
3287
|
if (this.requirePromptEchoBeforeSubmit) {
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
completion.rejectOnce(new Error(message));
|
|
3288
|
+
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending guarded submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
|
|
3289
|
+
this.submitSendKey(state, completion);
|
|
3130
3290
|
return;
|
|
3131
3291
|
}
|
|
3132
3292
|
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
|
|
@@ -3173,7 +3333,14 @@ ${lastSnapshot}`;
|
|
|
3173
3333
|
})() : null;
|
|
3174
3334
|
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
|
|
3175
3335
|
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
|
|
3176
|
-
|
|
3336
|
+
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
3337
|
+
const parsedHasActionableModal = Boolean(
|
|
3338
|
+
parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
|
|
3339
|
+
);
|
|
3340
|
+
const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
|
|
3341
|
+
if (!terminalLooksIdle) {
|
|
3342
|
+
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
3343
|
+
}
|
|
3177
3344
|
}
|
|
3178
3345
|
if (this.isWaitingForResponse && !allowInputDuringGeneration) {
|
|
3179
3346
|
if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
|
|
@@ -4547,6 +4714,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
|
4547
4714
|
"dirty_index_required",
|
|
4548
4715
|
"conflict",
|
|
4549
4716
|
"invalid_args",
|
|
4717
|
+
"nothing_to_commit",
|
|
4550
4718
|
"git_command_failed"
|
|
4551
4719
|
]);
|
|
4552
4720
|
function failure(reason, error) {
|
|
@@ -4791,7 +4959,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
|
4791
4959
|
} catch (err) {
|
|
4792
4960
|
const output = (err?.stdout || "") + (err?.stderr || "");
|
|
4793
4961
|
if (/nothing to commit/i.test(output)) {
|
|
4794
|
-
throw new GitCommandError("
|
|
4962
|
+
throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
|
|
4963
|
+
stdout: err?.stdout,
|
|
4964
|
+
stderr: err?.stderr
|
|
4965
|
+
});
|
|
4795
4966
|
}
|
|
4796
4967
|
throw err;
|
|
4797
4968
|
}
|
|
@@ -4983,20 +5154,23 @@ var TurnSnapshotTracker = class {
|
|
|
4983
5154
|
}
|
|
4984
5155
|
};
|
|
4985
5156
|
|
|
5157
|
+
// src/git/index.ts
|
|
5158
|
+
init_git_worktree();
|
|
5159
|
+
|
|
4986
5160
|
// src/index.ts
|
|
4987
5161
|
init_config();
|
|
4988
5162
|
|
|
4989
5163
|
// src/config/workspaces.ts
|
|
4990
5164
|
import * as fs from "fs";
|
|
4991
5165
|
import * as os from "os";
|
|
4992
|
-
import * as
|
|
5166
|
+
import * as path5 from "path";
|
|
4993
5167
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4994
5168
|
var MAX_WORKSPACES = 50;
|
|
4995
5169
|
function expandPath(p) {
|
|
4996
5170
|
const t = (p || "").trim();
|
|
4997
5171
|
if (!t) return "";
|
|
4998
|
-
if (t.startsWith("~")) return
|
|
4999
|
-
return
|
|
5172
|
+
if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5173
|
+
return path5.resolve(t);
|
|
5000
5174
|
}
|
|
5001
5175
|
function validateWorkspacePath(absPath) {
|
|
5002
5176
|
try {
|
|
@@ -5010,7 +5184,7 @@ function validateWorkspacePath(absPath) {
|
|
|
5010
5184
|
}
|
|
5011
5185
|
}
|
|
5012
5186
|
function defaultWorkspaceLabel(absPath) {
|
|
5013
|
-
const base =
|
|
5187
|
+
const base = path5.basename(absPath) || absPath;
|
|
5014
5188
|
return base;
|
|
5015
5189
|
}
|
|
5016
5190
|
function getDefaultWorkspacePath(config) {
|
|
@@ -5101,9 +5275,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
5101
5275
|
return getDefaultWorkspacePath(config) || void 0;
|
|
5102
5276
|
}
|
|
5103
5277
|
function findWorkspaceByPath(config, rawPath) {
|
|
5104
|
-
const abs =
|
|
5278
|
+
const abs = path5.resolve(expandPath(rawPath));
|
|
5105
5279
|
if (!abs) return void 0;
|
|
5106
|
-
return (config.workspaces || []).find((w) =>
|
|
5280
|
+
return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
|
|
5107
5281
|
}
|
|
5108
5282
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
5109
5283
|
const abs = expandPath(rawPath);
|
|
@@ -5119,7 +5293,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
5119
5293
|
const v = validateWorkspacePath(abs);
|
|
5120
5294
|
if (!v.ok) return { error: v.error };
|
|
5121
5295
|
const list = [...config.workspaces || []];
|
|
5122
|
-
if (list.some((w) =>
|
|
5296
|
+
if (list.some((w) => path5.resolve(w.path) === abs)) {
|
|
5123
5297
|
return { error: "Workspace already in list" };
|
|
5124
5298
|
}
|
|
5125
5299
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -5153,7 +5327,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
5153
5327
|
}
|
|
5154
5328
|
|
|
5155
5329
|
// src/config/recent-activity.ts
|
|
5156
|
-
import * as
|
|
5330
|
+
import * as path6 from "path";
|
|
5157
5331
|
|
|
5158
5332
|
// src/providers/summary-metadata.ts
|
|
5159
5333
|
function normalizeSummaryItem(item) {
|
|
@@ -5222,9 +5396,9 @@ var MAX_ACTIVITY = 30;
|
|
|
5222
5396
|
function normalizeWorkspace(workspace) {
|
|
5223
5397
|
if (!workspace) return "";
|
|
5224
5398
|
try {
|
|
5225
|
-
return
|
|
5399
|
+
return path6.resolve(expandPath(workspace));
|
|
5226
5400
|
} catch {
|
|
5227
|
-
return
|
|
5401
|
+
return path6.resolve(workspace);
|
|
5228
5402
|
}
|
|
5229
5403
|
}
|
|
5230
5404
|
function buildRecentActivityKey(entry) {
|
|
@@ -5392,14 +5566,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5392
5566
|
}
|
|
5393
5567
|
|
|
5394
5568
|
// src/config/saved-sessions.ts
|
|
5395
|
-
import * as
|
|
5569
|
+
import * as path7 from "path";
|
|
5396
5570
|
var MAX_SAVED_SESSIONS = 500;
|
|
5397
5571
|
function normalizeWorkspace2(workspace) {
|
|
5398
5572
|
if (!workspace) return "";
|
|
5399
5573
|
try {
|
|
5400
|
-
return
|
|
5574
|
+
return path7.resolve(expandPath(workspace));
|
|
5401
5575
|
} catch {
|
|
5402
|
-
return
|
|
5576
|
+
return path7.resolve(workspace);
|
|
5403
5577
|
}
|
|
5404
5578
|
}
|
|
5405
5579
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5505,8 +5679,8 @@ async function syncMeshes(transport) {
|
|
|
5505
5679
|
|
|
5506
5680
|
// src/config/state-store.ts
|
|
5507
5681
|
init_config();
|
|
5508
|
-
import { existsSync as
|
|
5509
|
-
import { join as
|
|
5682
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5683
|
+
import { join as join5 } from "path";
|
|
5510
5684
|
var DEFAULT_STATE = {
|
|
5511
5685
|
recentActivity: [],
|
|
5512
5686
|
savedProviderSessions: [],
|
|
@@ -5519,7 +5693,7 @@ function isPlainObject2(value) {
|
|
|
5519
5693
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5520
5694
|
}
|
|
5521
5695
|
function getStatePath() {
|
|
5522
|
-
return
|
|
5696
|
+
return join5(getConfigDir(), "state.json");
|
|
5523
5697
|
}
|
|
5524
5698
|
function normalizeState(raw) {
|
|
5525
5699
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -5555,7 +5729,7 @@ function normalizeState(raw) {
|
|
|
5555
5729
|
}
|
|
5556
5730
|
function loadState() {
|
|
5557
5731
|
const statePath = getStatePath();
|
|
5558
|
-
if (!
|
|
5732
|
+
if (!existsSync5(statePath)) {
|
|
5559
5733
|
return { ...DEFAULT_STATE };
|
|
5560
5734
|
}
|
|
5561
5735
|
try {
|
|
@@ -5576,9 +5750,9 @@ function resetState() {
|
|
|
5576
5750
|
|
|
5577
5751
|
// src/detection/ide-detector.ts
|
|
5578
5752
|
import { execSync } from "child_process";
|
|
5579
|
-
import { existsSync as
|
|
5753
|
+
import { existsSync as existsSync6 } from "fs";
|
|
5580
5754
|
import { platform, homedir as homedir3 } from "os";
|
|
5581
|
-
import * as
|
|
5755
|
+
import * as path8 from "path";
|
|
5582
5756
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5583
5757
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5584
5758
|
function registerIDEDefinition(def) {
|
|
@@ -5597,10 +5771,10 @@ function getMergedDefinitions() {
|
|
|
5597
5771
|
function findCliCommand(command) {
|
|
5598
5772
|
const trimmed = String(command || "").trim();
|
|
5599
5773
|
if (!trimmed) return null;
|
|
5600
|
-
if (
|
|
5601
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5602
|
-
const resolved =
|
|
5603
|
-
return
|
|
5774
|
+
if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
5775
|
+
const candidate = trimmed.startsWith("~") ? path8.join(homedir3(), trimmed.slice(1)) : trimmed;
|
|
5776
|
+
const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
|
|
5777
|
+
return existsSync6(resolved) ? resolved : null;
|
|
5604
5778
|
}
|
|
5605
5779
|
try {
|
|
5606
5780
|
const result = execSync(
|
|
@@ -5627,31 +5801,31 @@ function getIdeVersion(cliCommand) {
|
|
|
5627
5801
|
function checkPathExists(paths) {
|
|
5628
5802
|
const home = homedir3();
|
|
5629
5803
|
for (const p of paths) {
|
|
5630
|
-
const normalized = p.startsWith("~") ?
|
|
5804
|
+
const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
|
|
5631
5805
|
if (normalized.includes("*")) {
|
|
5632
5806
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5633
5807
|
const resolved = normalized.replace("*", username);
|
|
5634
|
-
if (
|
|
5808
|
+
if (existsSync6(resolved)) return resolved;
|
|
5635
5809
|
} else {
|
|
5636
|
-
if (
|
|
5810
|
+
if (existsSync6(normalized)) return normalized;
|
|
5637
5811
|
}
|
|
5638
5812
|
}
|
|
5639
5813
|
return null;
|
|
5640
5814
|
}
|
|
5641
5815
|
async function detectIDEs(providerLoader) {
|
|
5642
|
-
const
|
|
5816
|
+
const os22 = platform();
|
|
5643
5817
|
const results = [];
|
|
5644
5818
|
for (const def of getMergedDefinitions()) {
|
|
5645
5819
|
const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
|
|
5646
|
-
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[
|
|
5820
|
+
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
|
|
5647
5821
|
let resolvedCli = cliPath;
|
|
5648
|
-
if (!resolvedCli && appPath &&
|
|
5822
|
+
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
5649
5823
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
5650
|
-
if (
|
|
5824
|
+
if (existsSync6(bundledCli)) resolvedCli = bundledCli;
|
|
5651
5825
|
}
|
|
5652
|
-
if (!resolvedCli && appPath &&
|
|
5653
|
-
const { dirname:
|
|
5654
|
-
const appDir =
|
|
5826
|
+
if (!resolvedCli && appPath && os22 === "win32") {
|
|
5827
|
+
const { dirname: dirname9 } = await import("path");
|
|
5828
|
+
const appDir = dirname9(appPath);
|
|
5655
5829
|
const candidates = [
|
|
5656
5830
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
5657
5831
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -5660,13 +5834,13 @@ async function detectIDEs(providerLoader) {
|
|
|
5660
5834
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
5661
5835
|
];
|
|
5662
5836
|
for (const c of candidates) {
|
|
5663
|
-
if (
|
|
5837
|
+
if (existsSync6(c)) {
|
|
5664
5838
|
resolvedCli = c;
|
|
5665
5839
|
break;
|
|
5666
5840
|
}
|
|
5667
5841
|
}
|
|
5668
5842
|
}
|
|
5669
|
-
const installed =
|
|
5843
|
+
const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
|
|
5670
5844
|
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
5671
5845
|
results.push({
|
|
5672
5846
|
id: def.id,
|
|
@@ -5685,8 +5859,8 @@ async function detectIDEs(providerLoader) {
|
|
|
5685
5859
|
// src/detection/cli-detector.ts
|
|
5686
5860
|
import { exec } from "child_process";
|
|
5687
5861
|
import * as os2 from "os";
|
|
5688
|
-
import * as
|
|
5689
|
-
import { existsSync as
|
|
5862
|
+
import * as path9 from "path";
|
|
5863
|
+
import { existsSync as existsSync7 } from "fs";
|
|
5690
5864
|
function parseVersion(raw) {
|
|
5691
5865
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
5692
5866
|
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
@@ -5698,19 +5872,19 @@ function shellQuote(value) {
|
|
|
5698
5872
|
function expandHome(value) {
|
|
5699
5873
|
const trimmed = value.trim();
|
|
5700
5874
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5701
|
-
return
|
|
5875
|
+
return path9.join(os2.homedir(), trimmed.slice(1));
|
|
5702
5876
|
}
|
|
5703
5877
|
function isExplicitCommandPath(command) {
|
|
5704
5878
|
const trimmed = command.trim();
|
|
5705
|
-
return
|
|
5879
|
+
return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5706
5880
|
}
|
|
5707
5881
|
function resolveCommandPath(command) {
|
|
5708
5882
|
const trimmed = command.trim();
|
|
5709
5883
|
if (!trimmed) return null;
|
|
5710
5884
|
if (isExplicitCommandPath(trimmed)) {
|
|
5711
5885
|
const expanded = expandHome(trimmed);
|
|
5712
|
-
const candidate =
|
|
5713
|
-
return
|
|
5886
|
+
const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
|
|
5887
|
+
return existsSync7(candidate) ? candidate : null;
|
|
5714
5888
|
}
|
|
5715
5889
|
return null;
|
|
5716
5890
|
}
|
|
@@ -7782,6 +7956,44 @@ function normalizeChatMessage(message) {
|
|
|
7782
7956
|
function normalizeChatMessages(messages) {
|
|
7783
7957
|
return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
|
|
7784
7958
|
}
|
|
7959
|
+
function readMessageMeta(message) {
|
|
7960
|
+
const meta = message?.meta;
|
|
7961
|
+
return meta && typeof meta === "object" && !Array.isArray(meta) ? meta : null;
|
|
7962
|
+
}
|
|
7963
|
+
function readStringField(value) {
|
|
7964
|
+
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
7965
|
+
}
|
|
7966
|
+
function readVisibilityField(message, meta) {
|
|
7967
|
+
const record = message;
|
|
7968
|
+
return readStringField(record.visibility ?? record.transcriptVisibility ?? meta?.visibility ?? meta?.transcriptVisibility);
|
|
7969
|
+
}
|
|
7970
|
+
function isExplicitlyHiddenFromTranscript(message, meta) {
|
|
7971
|
+
const record = message;
|
|
7972
|
+
const visibility = readVisibilityField(message, meta);
|
|
7973
|
+
const audience = readStringField(record.audience ?? meta?.audience);
|
|
7974
|
+
const source = readStringField(record.source ?? meta?.source);
|
|
7975
|
+
return visibility === "hidden" || visibility === "debug" || visibility === "internal" || audience === "debug" || audience === "trace" || audience === "internal" || source === "runtime_status" || source === "runtime_activity" || source === "provider_chrome" || source === "control" || record.internal === true || record.isInternal === true || record.debug === true || meta?.internal === true || meta?.isInternal === true || meta?.debug === true || meta?.statusOnly === true || meta?.controlOnly === true;
|
|
7976
|
+
}
|
|
7977
|
+
function isExplicitlyVisibleInTranscript(message, meta) {
|
|
7978
|
+
const record = message;
|
|
7979
|
+
const visibility = readVisibilityField(message, meta);
|
|
7980
|
+
const audience = readStringField(record.audience ?? meta?.audience);
|
|
7981
|
+
return visibility === "visible" || visibility === "user" || visibility === "chat" || audience === "chat" || record.userFacing === true || meta?.userFacing === true;
|
|
7982
|
+
}
|
|
7983
|
+
function isUserFacingChatMessage(message) {
|
|
7984
|
+
if (!message) return false;
|
|
7985
|
+
const meta = readMessageMeta(message);
|
|
7986
|
+
if (isExplicitlyHiddenFromTranscript(message, meta)) return false;
|
|
7987
|
+
if (isExplicitlyVisibleInTranscript(message, meta)) return true;
|
|
7988
|
+
const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
7989
|
+
const kind = resolveChatMessageKind(message);
|
|
7990
|
+
if (role === "user" || role === "human") return kind === "standard" || kind === "";
|
|
7991
|
+
if (role === "assistant") return kind === "standard" || kind === "";
|
|
7992
|
+
return false;
|
|
7993
|
+
}
|
|
7994
|
+
function filterUserFacingChatMessages(messages) {
|
|
7995
|
+
return (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
|
|
7996
|
+
}
|
|
7785
7997
|
|
|
7786
7998
|
// src/providers/control-effects.ts
|
|
7787
7999
|
function extractProviderControlValues(controls, data) {
|
|
@@ -7978,9 +8190,9 @@ ${cleanBody}`;
|
|
|
7978
8190
|
|
|
7979
8191
|
// src/config/chat-history.ts
|
|
7980
8192
|
import * as fs3 from "fs";
|
|
7981
|
-
import * as
|
|
8193
|
+
import * as path11 from "path";
|
|
7982
8194
|
import * as os5 from "os";
|
|
7983
|
-
var HISTORY_DIR =
|
|
8195
|
+
var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
|
|
7984
8196
|
var RETAIN_DAYS = 30;
|
|
7985
8197
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
7986
8198
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -8143,7 +8355,7 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
8143
8355
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
8144
8356
|
return new Map(files.map((file) => {
|
|
8145
8357
|
try {
|
|
8146
|
-
const stat2 = fs3.statSync(
|
|
8358
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8147
8359
|
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
8148
8360
|
} catch {
|
|
8149
8361
|
return [file, `${file}:missing`];
|
|
@@ -8154,7 +8366,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
8154
8366
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
8155
8367
|
}
|
|
8156
8368
|
function getSavedHistoryIndexFilePath(dir) {
|
|
8157
|
-
return
|
|
8369
|
+
return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
8158
8370
|
}
|
|
8159
8371
|
function getSavedHistoryIndexLockPath(dir) {
|
|
8160
8372
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -8256,7 +8468,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
8256
8468
|
}
|
|
8257
8469
|
for (const file of Array.from(currentEntries.keys())) {
|
|
8258
8470
|
if (incomingFiles.has(file)) continue;
|
|
8259
|
-
if (!fs3.existsSync(
|
|
8471
|
+
if (!fs3.existsSync(path11.join(dir, file))) {
|
|
8260
8472
|
currentEntries.delete(file);
|
|
8261
8473
|
}
|
|
8262
8474
|
}
|
|
@@ -8282,7 +8494,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8282
8494
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8283
8495
|
const files = listHistoryFiles(dir);
|
|
8284
8496
|
for (const file of files) {
|
|
8285
|
-
const stat2 = fs3.statSync(
|
|
8497
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8286
8498
|
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
8287
8499
|
}
|
|
8288
8500
|
return false;
|
|
@@ -8292,14 +8504,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8292
8504
|
}
|
|
8293
8505
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
8294
8506
|
try {
|
|
8295
|
-
const stat2 = fs3.statSync(
|
|
8507
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8296
8508
|
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
8297
8509
|
} catch {
|
|
8298
8510
|
return `${file}:missing`;
|
|
8299
8511
|
}
|
|
8300
8512
|
}
|
|
8301
8513
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
8302
|
-
const filePath =
|
|
8514
|
+
const filePath = path11.join(dir, file);
|
|
8303
8515
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
8304
8516
|
const currentEntry = entries.get(file) || null;
|
|
8305
8517
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -8372,7 +8584,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
8372
8584
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
8373
8585
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
8374
8586
|
if (!historySessionId) return null;
|
|
8375
|
-
const filePath =
|
|
8587
|
+
const filePath = path11.join(dir, file);
|
|
8376
8588
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8377
8589
|
const lines = content.split("\n").filter(Boolean);
|
|
8378
8590
|
let messageCount = 0;
|
|
@@ -8459,7 +8671,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
8459
8671
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
8460
8672
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
8461
8673
|
for (const file of files.slice().sort()) {
|
|
8462
|
-
const filePath =
|
|
8674
|
+
const filePath = path11.join(dir, file);
|
|
8463
8675
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
8464
8676
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
8465
8677
|
const persisted = persistedEntries.get(file);
|
|
@@ -8579,12 +8791,12 @@ var ChatHistoryWriter = class {
|
|
|
8579
8791
|
});
|
|
8580
8792
|
}
|
|
8581
8793
|
if (newMessages.length === 0) return;
|
|
8582
|
-
const dir =
|
|
8794
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8583
8795
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8584
8796
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8585
8797
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
8586
8798
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
8587
|
-
const filePath =
|
|
8799
|
+
const filePath = path11.join(dir, fileName);
|
|
8588
8800
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
8589
8801
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
8590
8802
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -8675,11 +8887,11 @@ var ChatHistoryWriter = class {
|
|
|
8675
8887
|
const ws = String(workspace || "").trim();
|
|
8676
8888
|
if (!id || !ws) return;
|
|
8677
8889
|
try {
|
|
8678
|
-
const dir =
|
|
8890
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8679
8891
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8680
8892
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8681
8893
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
8682
|
-
const filePath =
|
|
8894
|
+
const filePath = path11.join(dir, fileName);
|
|
8683
8895
|
const record = {
|
|
8684
8896
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8685
8897
|
receivedAt: Date.now(),
|
|
@@ -8725,14 +8937,14 @@ var ChatHistoryWriter = class {
|
|
|
8725
8937
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8726
8938
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8727
8939
|
}
|
|
8728
|
-
const dir =
|
|
8940
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8729
8941
|
if (!fs3.existsSync(dir)) return;
|
|
8730
8942
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8731
8943
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8732
8944
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8733
8945
|
for (const file of files) {
|
|
8734
|
-
const sourcePath =
|
|
8735
|
-
const targetPath =
|
|
8946
|
+
const sourcePath = path11.join(dir, file);
|
|
8947
|
+
const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8736
8948
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8737
8949
|
const rewritten = sourceLines.map((line) => {
|
|
8738
8950
|
try {
|
|
@@ -8766,13 +8978,13 @@ var ChatHistoryWriter = class {
|
|
|
8766
8978
|
const sessionId = String(historySessionId || "").trim();
|
|
8767
8979
|
if (!sessionId) return;
|
|
8768
8980
|
try {
|
|
8769
|
-
const dir =
|
|
8981
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8770
8982
|
if (!fs3.existsSync(dir)) return;
|
|
8771
8983
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8772
8984
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8773
8985
|
const seen = /* @__PURE__ */ new Set();
|
|
8774
8986
|
for (const file of files) {
|
|
8775
|
-
const filePath =
|
|
8987
|
+
const filePath = path11.join(dir, file);
|
|
8776
8988
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8777
8989
|
const next = [];
|
|
8778
8990
|
for (const line of lines) {
|
|
@@ -8826,11 +9038,11 @@ var ChatHistoryWriter = class {
|
|
|
8826
9038
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
8827
9039
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
8828
9040
|
for (const dir of agentDirs) {
|
|
8829
|
-
const dirPath =
|
|
9041
|
+
const dirPath = path11.join(HISTORY_DIR, dir.name);
|
|
8830
9042
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
8831
9043
|
let removedAny = false;
|
|
8832
9044
|
for (const file of files) {
|
|
8833
|
-
const filePath =
|
|
9045
|
+
const filePath = path11.join(dirPath, file);
|
|
8834
9046
|
const stat2 = fs3.statSync(filePath);
|
|
8835
9047
|
if (stat2.mtimeMs < cutoff) {
|
|
8836
9048
|
fs3.unlinkSync(filePath);
|
|
@@ -8880,13 +9092,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8880
9092
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8881
9093
|
try {
|
|
8882
9094
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8883
|
-
const dir =
|
|
9095
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8884
9096
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
8885
9097
|
const files = listHistoryFiles(dir, historySessionId);
|
|
8886
9098
|
const allMessages = [];
|
|
8887
9099
|
const seen = /* @__PURE__ */ new Set();
|
|
8888
9100
|
for (const file of files) {
|
|
8889
|
-
const filePath =
|
|
9101
|
+
const filePath = path11.join(dir, file);
|
|
8890
9102
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8891
9103
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
8892
9104
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8910,7 +9122,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8910
9122
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
8911
9123
|
try {
|
|
8912
9124
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8913
|
-
const dir =
|
|
9125
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8914
9126
|
if (!fs3.existsSync(dir)) {
|
|
8915
9127
|
savedHistorySessionCache.delete(sanitized);
|
|
8916
9128
|
return { sessions: [], hasMore: false };
|
|
@@ -8971,11 +9183,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8971
9183
|
}
|
|
8972
9184
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8973
9185
|
try {
|
|
8974
|
-
const dir =
|
|
9186
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8975
9187
|
if (!fs3.existsSync(dir)) return null;
|
|
8976
9188
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
8977
9189
|
for (const file of files) {
|
|
8978
|
-
const lines = fs3.readFileSync(
|
|
9190
|
+
const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
8979
9191
|
for (const line of lines) {
|
|
8980
9192
|
try {
|
|
8981
9193
|
const parsed = JSON.parse(line);
|
|
@@ -8995,16 +9207,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
8995
9207
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
8996
9208
|
if (records.length === 0) return false;
|
|
8997
9209
|
try {
|
|
8998
|
-
const dir =
|
|
9210
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8999
9211
|
fs3.mkdirSync(dir, { recursive: true });
|
|
9000
9212
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
9001
9213
|
for (const file of fs3.readdirSync(dir)) {
|
|
9002
9214
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
9003
|
-
fs3.unlinkSync(
|
|
9215
|
+
fs3.unlinkSync(path11.join(dir, file));
|
|
9004
9216
|
}
|
|
9005
9217
|
}
|
|
9006
9218
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
9007
|
-
const filePath =
|
|
9219
|
+
const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
9008
9220
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
9009
9221
|
`, "utf-8");
|
|
9010
9222
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -9754,6 +9966,14 @@ function validateMessage(message, source, index) {
|
|
|
9754
9966
|
if (typeof message.senderName === "string") normalized.senderName = message.senderName;
|
|
9755
9967
|
if (typeof message._type === "string") normalized._type = message._type;
|
|
9756
9968
|
if (typeof message._sub === "string") normalized._sub = message._sub;
|
|
9969
|
+
if (typeof message.visibility === "string") normalized.visibility = message.visibility;
|
|
9970
|
+
if (typeof message.transcriptVisibility === "string") normalized.transcriptVisibility = message.transcriptVisibility;
|
|
9971
|
+
if (typeof message.audience === "string") normalized.audience = message.audience;
|
|
9972
|
+
if (typeof message.source === "string") normalized.source = message.source;
|
|
9973
|
+
if (typeof message.userFacing === "boolean") normalized.userFacing = message.userFacing;
|
|
9974
|
+
if (typeof message.internal === "boolean") normalized.internal = message.internal;
|
|
9975
|
+
if (typeof message.isInternal === "boolean") normalized.isInternal = message.isInternal;
|
|
9976
|
+
if (typeof message.debug === "boolean") normalized.debug = message.debug;
|
|
9757
9977
|
return normalized;
|
|
9758
9978
|
}
|
|
9759
9979
|
function validateModal(activeModal, status, source) {
|
|
@@ -10999,6 +11219,14 @@ function getActiveChatOptions(profile) {
|
|
|
10999
11219
|
if (profile === "full") return {};
|
|
11000
11220
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
11001
11221
|
}
|
|
11222
|
+
function resolveSessionStatus(activeChat, providerStatus) {
|
|
11223
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
11224
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
11225
|
+
if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
|
|
11226
|
+
if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
|
|
11227
|
+
if (topLevelStatus !== "idle") return topLevelStatus;
|
|
11228
|
+
return chatStatus;
|
|
11229
|
+
}
|
|
11002
11230
|
function shouldIncludeSessionControls(profile) {
|
|
11003
11231
|
return profile !== "live";
|
|
11004
11232
|
}
|
|
@@ -11077,9 +11305,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11077
11305
|
providerName: state.name,
|
|
11078
11306
|
kind: "workspace",
|
|
11079
11307
|
transport: "cdp-page",
|
|
11080
|
-
status:
|
|
11081
|
-
activeModal: activeChat?.activeModal || null
|
|
11082
|
-
}),
|
|
11308
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11083
11309
|
title,
|
|
11084
11310
|
workspace,
|
|
11085
11311
|
...git && { git },
|
|
@@ -11114,9 +11340,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11114
11340
|
providerSessionId: ext.providerSessionId,
|
|
11115
11341
|
kind: "agent",
|
|
11116
11342
|
transport: "cdp-webview",
|
|
11117
|
-
status:
|
|
11118
|
-
activeModal: activeChat?.activeModal || null
|
|
11119
|
-
}),
|
|
11343
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
11120
11344
|
title: activeChat?.title || ext.name,
|
|
11121
11345
|
workspace,
|
|
11122
11346
|
...git && { git },
|
|
@@ -11166,9 +11390,7 @@ function buildCliSession(state, options) {
|
|
|
11166
11390
|
providerSessionId: state.providerSessionId,
|
|
11167
11391
|
kind: "agent",
|
|
11168
11392
|
transport: "pty",
|
|
11169
|
-
status:
|
|
11170
|
-
activeModal: activeChat?.activeModal || null
|
|
11171
|
-
}),
|
|
11393
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11172
11394
|
title: activeChat?.title || state.name,
|
|
11173
11395
|
workspace,
|
|
11174
11396
|
...git && { git },
|
|
@@ -11216,9 +11438,7 @@ function buildAcpSession(state, options) {
|
|
|
11216
11438
|
providerName: state.name,
|
|
11217
11439
|
kind: "agent",
|
|
11218
11440
|
transport: "acp",
|
|
11219
|
-
status:
|
|
11220
|
-
activeModal: activeChat?.activeModal || null
|
|
11221
|
-
}),
|
|
11441
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11222
11442
|
title: activeChat?.title || state.name,
|
|
11223
11443
|
workspace,
|
|
11224
11444
|
...git && { git },
|
|
@@ -11341,7 +11561,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
11341
11561
|
// src/commands/chat-commands.ts
|
|
11342
11562
|
import * as fs4 from "fs";
|
|
11343
11563
|
import * as os6 from "os";
|
|
11344
|
-
import * as
|
|
11564
|
+
import * as path12 from "path";
|
|
11345
11565
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
11346
11566
|
|
|
11347
11567
|
// src/providers/provider-input-support.ts
|
|
@@ -11544,6 +11764,7 @@ function buildSessionModalDeliverySignature(payload) {
|
|
|
11544
11764
|
// src/commands/chat-commands.ts
|
|
11545
11765
|
var RECENT_SEND_WINDOW_MS = 1200;
|
|
11546
11766
|
var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
|
|
11767
|
+
var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
|
|
11547
11768
|
var recentSendByTarget = /* @__PURE__ */ new Map();
|
|
11548
11769
|
function getCurrentProviderType(h, fallback = "") {
|
|
11549
11770
|
return h.currentSession?.providerType || h.currentProviderType || fallback;
|
|
@@ -11596,6 +11817,16 @@ function buildSendInputSignature(input) {
|
|
|
11596
11817
|
function getSendChatInputEnvelope(args) {
|
|
11597
11818
|
return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
|
|
11598
11819
|
}
|
|
11820
|
+
function sleep(ms) {
|
|
11821
|
+
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
11822
|
+
}
|
|
11823
|
+
async function waitOnceForFreshHermesCliStart(adapter, log) {
|
|
11824
|
+
if (adapter.cliType !== "hermes-cli") return;
|
|
11825
|
+
const status = typeof adapter.getStatus === "function" ? adapter.getStatus()?.status : void 0;
|
|
11826
|
+
if (status !== "starting") return;
|
|
11827
|
+
log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
|
|
11828
|
+
await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
|
|
11829
|
+
}
|
|
11599
11830
|
function getHistorySessionId(h, args) {
|
|
11600
11831
|
const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
|
|
11601
11832
|
if (explicit) return explicit;
|
|
@@ -11650,7 +11881,7 @@ function normalizeReadChatTailLimit(args) {
|
|
|
11650
11881
|
}
|
|
11651
11882
|
function normalizeReadChatMessages(payload) {
|
|
11652
11883
|
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
11653
|
-
return messages;
|
|
11884
|
+
return normalizeChatMessages(messages);
|
|
11654
11885
|
}
|
|
11655
11886
|
function deriveHistoryDedupKey(message) {
|
|
11656
11887
|
const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
|
|
@@ -11704,6 +11935,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
11704
11935
|
return raw;
|
|
11705
11936
|
}
|
|
11706
11937
|
}
|
|
11938
|
+
function isGeneratingLikeStatus(status) {
|
|
11939
|
+
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
11940
|
+
}
|
|
11941
|
+
function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
11942
|
+
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
11943
|
+
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
11944
|
+
const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
|
|
11945
|
+
if (adapterRawStatus !== "idle") return false;
|
|
11946
|
+
if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
|
|
11947
|
+
return true;
|
|
11948
|
+
}
|
|
11949
|
+
function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
11950
|
+
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
11951
|
+
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
11952
|
+
}
|
|
11953
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
11954
|
+
if (status !== "idle") return messages;
|
|
11955
|
+
return messages.map((message) => {
|
|
11956
|
+
const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
11957
|
+
const hasStreamingMeta = meta?.streaming === true;
|
|
11958
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
11959
|
+
return {
|
|
11960
|
+
...message,
|
|
11961
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
11962
|
+
...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
|
|
11963
|
+
};
|
|
11964
|
+
});
|
|
11965
|
+
}
|
|
11707
11966
|
function buildReadChatCommandResult(payload, args) {
|
|
11708
11967
|
let validatedPayload;
|
|
11709
11968
|
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
@@ -11716,13 +11975,22 @@ function buildReadChatCommandResult(payload, args) {
|
|
|
11716
11975
|
return { success: false, error: error?.message || String(error) };
|
|
11717
11976
|
}
|
|
11718
11977
|
const messages = normalizeReadChatMessages(validatedPayload);
|
|
11719
|
-
const
|
|
11978
|
+
const visibleMessages = filterUserFacingChatMessages(messages);
|
|
11979
|
+
const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
|
|
11980
|
+
const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
|
|
11981
|
+
const returnedDebugReadChat = debugReadChat ? {
|
|
11982
|
+
...debugReadChat,
|
|
11983
|
+
fullMsgCount: typeof debugReadChat.fullMsgCount === "number" ? debugReadChat.fullMsgCount : messages.length,
|
|
11984
|
+
visibleMsgCount: visibleMessages.length,
|
|
11985
|
+
hiddenMsgCount,
|
|
11986
|
+
returnedMsgCount: sync.messages.length
|
|
11987
|
+
} : void 0;
|
|
11720
11988
|
return {
|
|
11721
11989
|
success: true,
|
|
11722
11990
|
...validatedPayload,
|
|
11723
11991
|
messages: sync.messages,
|
|
11724
11992
|
totalMessages: sync.totalMessages,
|
|
11725
|
-
...
|
|
11993
|
+
...returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}
|
|
11726
11994
|
};
|
|
11727
11995
|
}
|
|
11728
11996
|
var DEFAULT_DEBUG_SANITIZE_OPTIONS = {
|
|
@@ -11852,7 +12120,7 @@ function buildDebugBundleText(bundle) {
|
|
|
11852
12120
|
}
|
|
11853
12121
|
function getChatDebugBundleDir() {
|
|
11854
12122
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
11855
|
-
return override ||
|
|
12123
|
+
return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
11856
12124
|
}
|
|
11857
12125
|
function safeBundleIdSegment(value, fallback) {
|
|
11858
12126
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -11868,6 +12136,14 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
11868
12136
|
const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
|
|
11869
12137
|
const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
|
|
11870
12138
|
const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
|
|
12139
|
+
const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
|
|
12140
|
+
const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
|
|
12141
|
+
const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
|
|
12142
|
+
const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
|
|
12143
|
+
const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
|
|
12144
|
+
const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
|
|
12145
|
+
const cliStatus = typeof cli?.status === "string" ? cli.status : "";
|
|
12146
|
+
const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
|
|
11871
12147
|
return {
|
|
11872
12148
|
createdAt: bundle.createdAt,
|
|
11873
12149
|
targetSessionId: target.targetSessionId,
|
|
@@ -11876,8 +12152,22 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
11876
12152
|
readChatSuccess: readChat.success,
|
|
11877
12153
|
readChatStatus: readChat.status,
|
|
11878
12154
|
readChatTotalMessages: readChat.totalMessages,
|
|
12155
|
+
readChatReturnedMessages,
|
|
11879
12156
|
cliStatus: cli?.status,
|
|
12157
|
+
cliParsedStatus: cliParsedStatus || void 0,
|
|
11880
12158
|
cliMessageCount: cli?.messageCount,
|
|
12159
|
+
cliParsedMessageCount,
|
|
12160
|
+
cliPartialResponseChars: cliPartialResponse.length,
|
|
12161
|
+
parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
|
|
12162
|
+
parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
|
|
12163
|
+
readChatDebug: Object.keys(debugReadChat).length ? {
|
|
12164
|
+
adapterStatus: debugReadChat.adapterStatus,
|
|
12165
|
+
parsedStatus: debugReadChat.parsedStatus,
|
|
12166
|
+
returnedStatus: debugReadChat.returnedStatus,
|
|
12167
|
+
parsedMsgCount: debugReadChat.parsedMsgCount,
|
|
12168
|
+
returnedMsgCount: debugReadChat.returnedMsgCount,
|
|
12169
|
+
shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
|
|
12170
|
+
} : void 0,
|
|
11881
12171
|
hasFrontendSnapshot: !!frontend
|
|
11882
12172
|
};
|
|
11883
12173
|
}
|
|
@@ -11885,7 +12175,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
11885
12175
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
11886
12176
|
const dir = getChatDebugBundleDir();
|
|
11887
12177
|
fs4.mkdirSync(dir, { recursive: true });
|
|
11888
|
-
const savedPath =
|
|
12178
|
+
const savedPath = path12.join(dir, `${bundleId}.json`);
|
|
11889
12179
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
11890
12180
|
`;
|
|
11891
12181
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -12115,7 +12405,7 @@ async function handleChatHistory(h, args) {
|
|
|
12115
12405
|
}
|
|
12116
12406
|
}
|
|
12117
12407
|
async function handleReadChat(h, args) {
|
|
12118
|
-
const provider = h.getProvider(args?.agentType);
|
|
12408
|
+
const provider = h.getProvider(args?.agentType || args?.providerType);
|
|
12119
12409
|
const transport = getTargetTransport(h, provider);
|
|
12120
12410
|
const historySessionId = getHistorySessionId(h, args);
|
|
12121
12411
|
const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
|
|
@@ -12142,10 +12432,13 @@ async function handleReadChat(h, args) {
|
|
|
12142
12432
|
const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
12143
12433
|
const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
12144
12434
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
12145
|
-
const returnedStatus = parsedRecord.status
|
|
12146
|
-
|
|
12435
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
12436
|
+
const runtimeMessageMerger = getTargetInstance(h, args);
|
|
12437
|
+
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
|
|
12438
|
+
const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
|
|
12439
|
+
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
12440
|
return buildReadChatCommandResult({
|
|
12148
|
-
messages:
|
|
12441
|
+
messages: returnedMessages,
|
|
12149
12442
|
status: returnedStatus,
|
|
12150
12443
|
activeModal,
|
|
12151
12444
|
debugReadChat: {
|
|
@@ -12156,7 +12449,7 @@ async function handleReadChat(h, args) {
|
|
|
12156
12449
|
returnedStatus: String(returnedStatus || ""),
|
|
12157
12450
|
shouldPreferAdapterMessages: false,
|
|
12158
12451
|
parsedMsgCount: parsedRecord.messages.length,
|
|
12159
|
-
returnedMsgCount:
|
|
12452
|
+
returnedMsgCount: returnedMessages.length
|
|
12160
12453
|
},
|
|
12161
12454
|
...title ? { title } : {},
|
|
12162
12455
|
...providerSessionId ? { providerSessionId } : {},
|
|
@@ -12402,6 +12695,7 @@ async function handleSendChat(h, args) {
|
|
|
12402
12695
|
try {
|
|
12403
12696
|
assertTextOnlyInput(provider, input);
|
|
12404
12697
|
if (!text) return { success: false, error: "text required for PTY send" };
|
|
12698
|
+
await waitOnceForFreshHermesCliStart(adapter, _log);
|
|
12405
12699
|
await adapter.sendMessage(text);
|
|
12406
12700
|
return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
|
|
12407
12701
|
} catch (e) {
|
|
@@ -12901,9 +13195,17 @@ async function handleResolveAction(h, args) {
|
|
|
12901
13195
|
const targetState = targetInstance?.getState?.();
|
|
12902
13196
|
const surfacedModal = targetState?.activeChat?.activeModal && Array.isArray(targetState.activeChat.activeModal.buttons) && targetState.activeChat.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? targetState.activeChat.activeModal : null;
|
|
12903
13197
|
const statusModal = status?.activeModal && Array.isArray(status.activeModal.buttons) && status.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? status.activeModal : null;
|
|
12904
|
-
const
|
|
12905
|
-
|
|
12906
|
-
|
|
13198
|
+
const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
|
|
13199
|
+
try {
|
|
13200
|
+
return parseMaybeJson(adapter.getScriptParsedStatus());
|
|
13201
|
+
} catch {
|
|
13202
|
+
return null;
|
|
13203
|
+
}
|
|
13204
|
+
})() : null;
|
|
13205
|
+
const parsedModal = parsedStatus?.status === "waiting_approval" && parsedStatus?.activeModal && Array.isArray(parsedStatus.activeModal.buttons) && parsedStatus.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? parsedStatus.activeModal : null;
|
|
13206
|
+
const effectiveModal = statusModal || surfacedModal || parsedModal;
|
|
13207
|
+
const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
|
|
13208
|
+
LOG.info("Command", `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || "")} rawStatus=${String(status?.status || "")} effectiveStatus=${String(effectiveStatus || "")} statusModal=${statusModal ? "yes" : "no"} surfacedModal=${surfacedModal ? "yes" : "no"} parsedModal=${parsedModal ? "yes" : "no"} instance=${targetInstance ? "yes" : "no"}`);
|
|
12907
13209
|
if (!effectiveModal) {
|
|
12908
13210
|
return { success: false, error: "Not in approval state" };
|
|
12909
13211
|
}
|
|
@@ -13029,7 +13331,7 @@ async function handleResolveAction(h, args) {
|
|
|
13029
13331
|
|
|
13030
13332
|
// src/commands/cdp-commands.ts
|
|
13031
13333
|
import * as fs5 from "fs";
|
|
13032
|
-
import * as
|
|
13334
|
+
import * as path13 from "path";
|
|
13033
13335
|
import * as os7 from "os";
|
|
13034
13336
|
var KEY_TO_VK = {
|
|
13035
13337
|
Backspace: 8,
|
|
@@ -13286,25 +13588,25 @@ function resolveSafePath(requestedPath) {
|
|
|
13286
13588
|
const inputPath = rawPath || ".";
|
|
13287
13589
|
const home = os7.homedir();
|
|
13288
13590
|
if (inputPath.startsWith("~")) {
|
|
13289
|
-
return
|
|
13591
|
+
return path13.resolve(path13.join(home, inputPath.slice(1)));
|
|
13290
13592
|
}
|
|
13291
13593
|
if (process.platform === "win32") {
|
|
13292
13594
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
13293
|
-
if (
|
|
13294
|
-
return
|
|
13595
|
+
if (path13.win32.isAbsolute(normalized)) {
|
|
13596
|
+
return path13.win32.normalize(normalized);
|
|
13295
13597
|
}
|
|
13296
|
-
return
|
|
13598
|
+
return path13.win32.resolve(normalized);
|
|
13297
13599
|
}
|
|
13298
|
-
if (
|
|
13299
|
-
return
|
|
13600
|
+
if (path13.isAbsolute(inputPath)) {
|
|
13601
|
+
return path13.normalize(inputPath);
|
|
13300
13602
|
}
|
|
13301
|
-
return
|
|
13603
|
+
return path13.resolve(inputPath);
|
|
13302
13604
|
}
|
|
13303
13605
|
function listDirectoryEntriesSafe(dirPath) {
|
|
13304
13606
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
13305
13607
|
const files = [];
|
|
13306
13608
|
for (const entry of entries) {
|
|
13307
|
-
const entryPath =
|
|
13609
|
+
const entryPath = path13.join(dirPath, entry.name);
|
|
13308
13610
|
try {
|
|
13309
13611
|
if (entry.isDirectory()) {
|
|
13310
13612
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -13358,7 +13660,7 @@ async function handleFileRead(h, args) {
|
|
|
13358
13660
|
async function handleFileWrite(h, args) {
|
|
13359
13661
|
try {
|
|
13360
13662
|
const filePath = resolveSafePath(args?.path);
|
|
13361
|
-
fs5.mkdirSync(
|
|
13663
|
+
fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
13362
13664
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
13363
13665
|
return { success: true, path: filePath };
|
|
13364
13666
|
} catch (e) {
|
|
@@ -14142,9 +14444,11 @@ var DaemonCommandHandler = class {
|
|
|
14142
14444
|
}
|
|
14143
14445
|
const sessionLookupFailed = !!targetSessionId && !session;
|
|
14144
14446
|
const managerKey = this.extractIdeType(args, sessionLookupFailed);
|
|
14145
|
-
let providerType;
|
|
14447
|
+
let providerType = args?.agentType || args?.providerType;
|
|
14146
14448
|
if (!sessionLookupFailed) {
|
|
14147
|
-
providerType = session?.providerType ||
|
|
14449
|
+
providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
|
|
14450
|
+
} else if (!providerType) {
|
|
14451
|
+
providerType = this.inferProviderType(managerKey);
|
|
14148
14452
|
}
|
|
14149
14453
|
return { session, managerKey, providerType, sessionLookupFailed };
|
|
14150
14454
|
}
|
|
@@ -14224,7 +14528,8 @@ var DaemonCommandHandler = class {
|
|
|
14224
14528
|
"pty_resize",
|
|
14225
14529
|
"invoke_provider_script"
|
|
14226
14530
|
]);
|
|
14227
|
-
|
|
14531
|
+
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);
|
|
14532
|
+
if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
|
|
14228
14533
|
const result2 = {
|
|
14229
14534
|
success: false,
|
|
14230
14535
|
error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
|
|
@@ -14478,16 +14783,16 @@ var DaemonCommandHandler = class {
|
|
|
14478
14783
|
// src/commands/cli-manager.ts
|
|
14479
14784
|
init_provider_cli_adapter();
|
|
14480
14785
|
import * as os13 from "os";
|
|
14481
|
-
import * as
|
|
14786
|
+
import * as path17 from "path";
|
|
14482
14787
|
import * as crypto4 from "crypto";
|
|
14483
|
-
import { existsSync as
|
|
14788
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
14484
14789
|
import { execFileSync } from "child_process";
|
|
14485
14790
|
import chalk from "chalk";
|
|
14486
14791
|
init_config();
|
|
14487
14792
|
|
|
14488
14793
|
// src/providers/cli-provider-instance.ts
|
|
14489
14794
|
import * as os12 from "os";
|
|
14490
|
-
import * as
|
|
14795
|
+
import * as path16 from "path";
|
|
14491
14796
|
import * as crypto3 from "crypto";
|
|
14492
14797
|
import * as fs6 from "fs";
|
|
14493
14798
|
import { createRequire } from "module";
|
|
@@ -14546,7 +14851,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
14546
14851
|
var CachedDatabaseSync = null;
|
|
14547
14852
|
function getDatabaseSync() {
|
|
14548
14853
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
14549
|
-
const requireFn = typeof __require === "function" ? __require : createRequire(
|
|
14854
|
+
const requireFn = typeof __require === "function" ? __require : createRequire(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
14550
14855
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
14551
14856
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
14552
14857
|
if (!CachedDatabaseSync) {
|
|
@@ -14599,7 +14904,7 @@ var CliProviderInstance = class {
|
|
|
14599
14904
|
this.providerSessionId = options?.providerSessionId;
|
|
14600
14905
|
this.launchMode = options?.launchMode || "new";
|
|
14601
14906
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
14602
|
-
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
|
|
14907
|
+
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
14603
14908
|
this.monitor = new StatusMonitor();
|
|
14604
14909
|
this.historyWriter = new ChatHistoryWriter();
|
|
14605
14910
|
}
|
|
@@ -15076,7 +15381,19 @@ var CliProviderInstance = class {
|
|
|
15076
15381
|
}
|
|
15077
15382
|
}
|
|
15078
15383
|
pushEvent(event) {
|
|
15079
|
-
|
|
15384
|
+
const enrichedEvent = {
|
|
15385
|
+
...event,
|
|
15386
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
|
|
15387
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
|
|
15388
|
+
providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
|
|
15389
|
+
workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
|
|
15390
|
+
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
15391
|
+
};
|
|
15392
|
+
if (this.context?.emitProviderEvent) {
|
|
15393
|
+
this.context.emitProviderEvent(enrichedEvent);
|
|
15394
|
+
return;
|
|
15395
|
+
}
|
|
15396
|
+
this.events.push(enrichedEvent);
|
|
15080
15397
|
}
|
|
15081
15398
|
flushEvents() {
|
|
15082
15399
|
const events = [...this.events];
|
|
@@ -15283,12 +15600,59 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15283
15600
|
);
|
|
15284
15601
|
}
|
|
15285
15602
|
}
|
|
15603
|
+
mergeRuntimeChatMessages(parsedMessages) {
|
|
15604
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
15605
|
+
}
|
|
15286
15606
|
mergeConversationMessages(parsedMessages) {
|
|
15287
15607
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15608
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
15609
|
+
message,
|
|
15610
|
+
index,
|
|
15611
|
+
source: "parsed"
|
|
15612
|
+
}));
|
|
15613
|
+
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
15614
|
+
message: entry.message,
|
|
15615
|
+
index: parsedMessages.length + index,
|
|
15616
|
+
source: "runtime",
|
|
15617
|
+
runtimeKey: entry.key
|
|
15618
|
+
}));
|
|
15619
|
+
const getTime = (message) => {
|
|
15620
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
15621
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
15622
|
+
};
|
|
15623
|
+
const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
15624
|
+
const isRuntimeOverlay = (entry) => {
|
|
15625
|
+
if (entry.source !== "runtime") return false;
|
|
15626
|
+
const key = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
|
|
15627
|
+
if (key.startsWith("auto_approval:")) return true;
|
|
15628
|
+
return !isUserFacingChatMessage(entry.message);
|
|
15629
|
+
};
|
|
15630
|
+
const shouldKeepParsedBeforeUntimedRuntime = (message) => {
|
|
15631
|
+
const role = getRole(message);
|
|
15632
|
+
return role === "user" || role === "human";
|
|
15633
|
+
};
|
|
15634
|
+
const shouldKeepParsedAfterUntimedRuntime = (message) => {
|
|
15635
|
+
const role = getRole(message);
|
|
15636
|
+
if (role !== "assistant") return false;
|
|
15637
|
+
const kind = resolveChatMessageKind(message);
|
|
15638
|
+
return kind === "standard" || kind === "terminal";
|
|
15639
|
+
};
|
|
15640
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
15641
|
+
const aTime = getTime(a.message);
|
|
15642
|
+
const bTime = getTime(b.message);
|
|
15643
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
15644
|
+
if (a.source !== b.source && aTime !== bTime) {
|
|
15645
|
+
const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
|
|
15646
|
+
const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
|
|
15647
|
+
if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
|
|
15648
|
+
if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
|
|
15649
|
+
return a.source === "parsed" ? -1 : 1;
|
|
15650
|
+
}
|
|
15651
|
+
if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
|
|
15652
|
+
return a.source === "parsed" ? 1 : -1;
|
|
15653
|
+
}
|
|
15654
|
+
}
|
|
15655
|
+
}
|
|
15292
15656
|
return a.index - b.index;
|
|
15293
15657
|
}).map((entry) => entry.message));
|
|
15294
15658
|
}
|
|
@@ -16617,17 +16981,17 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
16617
16981
|
// src/commands/cli-manager.ts
|
|
16618
16982
|
function isExplicitCommand(command) {
|
|
16619
16983
|
const trimmed = command.trim();
|
|
16620
|
-
return
|
|
16984
|
+
return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
16621
16985
|
}
|
|
16622
16986
|
function expandExecutable(command) {
|
|
16623
16987
|
const trimmed = command.trim();
|
|
16624
|
-
return trimmed.startsWith("~") ?
|
|
16988
|
+
return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
16625
16989
|
}
|
|
16626
16990
|
function commandExists(command) {
|
|
16627
16991
|
const trimmed = command.trim();
|
|
16628
16992
|
if (!trimmed) return false;
|
|
16629
16993
|
if (isExplicitCommand(trimmed)) {
|
|
16630
|
-
return
|
|
16994
|
+
return existsSync12(expandExecutable(trimmed));
|
|
16631
16995
|
}
|
|
16632
16996
|
try {
|
|
16633
16997
|
execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -16645,6 +17009,35 @@ function colorize(color, text) {
|
|
|
16645
17009
|
const fn = chalkApi?.[color];
|
|
16646
17010
|
return typeof fn === "function" ? fn(text) : text;
|
|
16647
17011
|
}
|
|
17012
|
+
var COORDINATOR_DELEGATED_ENV_UNSETS = {
|
|
17013
|
+
ADHDEV_INLINE_MESH: "",
|
|
17014
|
+
ADHDEV_MCP_TRANSPORT: "",
|
|
17015
|
+
ADHDEV_MESH_ID: "",
|
|
17016
|
+
HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
|
|
17017
|
+
};
|
|
17018
|
+
function hasCliArg(args, flag) {
|
|
17019
|
+
return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
17020
|
+
}
|
|
17021
|
+
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
17022
|
+
const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
17023
|
+
mkdirSync7(baseDir, { recursive: true });
|
|
17024
|
+
const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
17025
|
+
const filePath = path17.join(baseDir, `${workspaceHash}.json`);
|
|
17026
|
+
writeFileSync7(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
17027
|
+
return filePath;
|
|
17028
|
+
}
|
|
17029
|
+
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
17030
|
+
const cliType = String(input.cliType || "").trim();
|
|
17031
|
+
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
17032
|
+
const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
|
|
17033
|
+
if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
|
|
17034
|
+
cliArgs.unshift("--ignore-user-config");
|
|
17035
|
+
}
|
|
17036
|
+
if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
|
|
17037
|
+
cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
17038
|
+
}
|
|
17039
|
+
return { cliArgs, env };
|
|
17040
|
+
}
|
|
16648
17041
|
function isUuid(value) {
|
|
16649
17042
|
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
17043
|
}
|
|
@@ -16815,7 +17208,7 @@ var DaemonCliManager = class {
|
|
|
16815
17208
|
attachExisting
|
|
16816
17209
|
}) || void 0;
|
|
16817
17210
|
}
|
|
16818
|
-
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
|
|
17211
|
+
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
|
|
16819
17212
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16820
17213
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
16821
17214
|
if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
|
|
@@ -16829,7 +17222,7 @@ var DaemonCliManager = class {
|
|
|
16829
17222
|
providerSessionId,
|
|
16830
17223
|
attachExisting
|
|
16831
17224
|
);
|
|
16832
|
-
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
|
|
17225
|
+
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
16833
17226
|
}
|
|
16834
17227
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
16835
17228
|
}
|
|
@@ -16902,7 +17295,7 @@ var DaemonCliManager = class {
|
|
|
16902
17295
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
16903
17296
|
const trimmed = (workingDir || "").trim();
|
|
16904
17297
|
if (!trimmed) throw new Error("working directory required");
|
|
16905
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17298
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
|
|
16906
17299
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16907
17300
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
16908
17301
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -17032,6 +17425,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17032
17425
|
{
|
|
17033
17426
|
providerSessionId: sessionBinding.providerSessionId,
|
|
17034
17427
|
launchMode: sessionBinding.launchMode,
|
|
17428
|
+
extraEnv: options?.extraEnv,
|
|
17035
17429
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
17036
17430
|
this.persistRecentActivity({
|
|
17037
17431
|
kind: "cli",
|
|
@@ -17052,7 +17446,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17052
17446
|
resolvedCliArgs,
|
|
17053
17447
|
key,
|
|
17054
17448
|
sessionBinding.providerSessionId,
|
|
17055
|
-
false
|
|
17449
|
+
false,
|
|
17450
|
+
options?.extraEnv
|
|
17056
17451
|
);
|
|
17057
17452
|
try {
|
|
17058
17453
|
await adapter.spawn();
|
|
@@ -17276,12 +17671,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17276
17671
|
const dir = resolved.path;
|
|
17277
17672
|
const launchSource = resolved.source;
|
|
17278
17673
|
if (!cliType) throw new Error("cliType required");
|
|
17674
|
+
const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
|
|
17675
|
+
const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
|
|
17676
|
+
cliType,
|
|
17677
|
+
workspace: dir,
|
|
17678
|
+
cliArgs: args?.cliArgs,
|
|
17679
|
+
env: args?.env
|
|
17680
|
+
}) : null;
|
|
17279
17681
|
const started = await this.startSession(
|
|
17280
17682
|
cliType,
|
|
17281
17683
|
dir,
|
|
17282
|
-
args?.cliArgs,
|
|
17684
|
+
delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
|
|
17283
17685
|
args?.initialModel,
|
|
17284
|
-
{
|
|
17686
|
+
{
|
|
17687
|
+
resumeSessionId: args?.resumeSessionId,
|
|
17688
|
+
settingsOverride,
|
|
17689
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
17690
|
+
}
|
|
17285
17691
|
);
|
|
17286
17692
|
return {
|
|
17287
17693
|
success: true,
|
|
@@ -17403,11 +17809,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17403
17809
|
import { execSync as execSync4, spawn as spawn2 } from "child_process";
|
|
17404
17810
|
import * as net from "net";
|
|
17405
17811
|
import * as os15 from "os";
|
|
17406
|
-
import * as
|
|
17812
|
+
import * as path19 from "path";
|
|
17407
17813
|
|
|
17408
17814
|
// src/providers/provider-loader.ts
|
|
17409
17815
|
import * as fs7 from "fs";
|
|
17410
|
-
import * as
|
|
17816
|
+
import * as path18 from "path";
|
|
17411
17817
|
import * as os14 from "os";
|
|
17412
17818
|
import * as chokidar from "chokidar";
|
|
17413
17819
|
init_logger();
|
|
@@ -17731,7 +18137,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17731
18137
|
try {
|
|
17732
18138
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
17733
18139
|
return ["ide", "extension", "cli", "acp"].some(
|
|
17734
|
-
(category) => fs7.existsSync(
|
|
18140
|
+
(category) => fs7.existsSync(path18.join(candidate, category))
|
|
17735
18141
|
);
|
|
17736
18142
|
} catch {
|
|
17737
18143
|
return false;
|
|
@@ -17739,20 +18145,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17739
18145
|
}
|
|
17740
18146
|
static hasProviderRootMarker(candidate) {
|
|
17741
18147
|
try {
|
|
17742
|
-
return fs7.existsSync(
|
|
18148
|
+
return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
17743
18149
|
} catch {
|
|
17744
18150
|
return false;
|
|
17745
18151
|
}
|
|
17746
18152
|
}
|
|
17747
18153
|
detectDefaultUserDir() {
|
|
17748
|
-
const fallback =
|
|
18154
|
+
const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17749
18155
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17750
18156
|
const visited = /* @__PURE__ */ new Set();
|
|
17751
18157
|
for (const start of this.probeStarts) {
|
|
17752
|
-
let current =
|
|
18158
|
+
let current = path18.resolve(start);
|
|
17753
18159
|
while (!visited.has(current)) {
|
|
17754
18160
|
visited.add(current);
|
|
17755
|
-
const siblingCandidate =
|
|
18161
|
+
const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17756
18162
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17757
18163
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17758
18164
|
if (envOptIn || hasMarker) {
|
|
@@ -17774,7 +18180,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17774
18180
|
return { path: siblingCandidate, source };
|
|
17775
18181
|
}
|
|
17776
18182
|
}
|
|
17777
|
-
const parent =
|
|
18183
|
+
const parent = path18.dirname(current);
|
|
17778
18184
|
if (parent === current) break;
|
|
17779
18185
|
current = parent;
|
|
17780
18186
|
}
|
|
@@ -17784,11 +18190,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17784
18190
|
constructor(options) {
|
|
17785
18191
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17786
18192
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17787
|
-
this.defaultProvidersDir =
|
|
18193
|
+
this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17788
18194
|
const detected = this.detectDefaultUserDir();
|
|
17789
18195
|
this.userDir = detected.path;
|
|
17790
18196
|
this.userDirSource = detected.source;
|
|
17791
|
-
this.upstreamDir =
|
|
18197
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17792
18198
|
this.disableUpstream = false;
|
|
17793
18199
|
this.applySourceConfig({
|
|
17794
18200
|
userDir: options?.userDir,
|
|
@@ -17847,7 +18253,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17847
18253
|
this.userDir = detected.path;
|
|
17848
18254
|
this.userDirSource = detected.source;
|
|
17849
18255
|
}
|
|
17850
|
-
this.upstreamDir =
|
|
18256
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17851
18257
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
17852
18258
|
if (this.explicitProviderDir) {
|
|
17853
18259
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -17861,7 +18267,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17861
18267
|
* Canonical provider directory shape for a given root.
|
|
17862
18268
|
*/
|
|
17863
18269
|
getProviderDir(root, category, type) {
|
|
17864
|
-
return
|
|
18270
|
+
return path18.join(root, category, type);
|
|
17865
18271
|
}
|
|
17866
18272
|
/**
|
|
17867
18273
|
* Canonical user override directory for a provider.
|
|
@@ -17888,7 +18294,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17888
18294
|
resolveProviderFile(type, ...segments) {
|
|
17889
18295
|
const dir = this.findProviderDirInternal(type);
|
|
17890
18296
|
if (!dir) return null;
|
|
17891
|
-
return
|
|
18297
|
+
return path18.join(dir, ...segments);
|
|
17892
18298
|
}
|
|
17893
18299
|
/**
|
|
17894
18300
|
* Load all providers (3-tier priority)
|
|
@@ -17927,7 +18333,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17927
18333
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
17928
18334
|
try {
|
|
17929
18335
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
17930
|
-
(d) => fs7.statSync(
|
|
18336
|
+
(d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
|
|
17931
18337
|
);
|
|
17932
18338
|
} catch {
|
|
17933
18339
|
return false;
|
|
@@ -18424,8 +18830,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18424
18830
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
18425
18831
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
18426
18832
|
if (providerDir) {
|
|
18427
|
-
const fullDir =
|
|
18428
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18833
|
+
const fullDir = path18.join(providerDir, entry.scriptDir);
|
|
18834
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18429
18835
|
}
|
|
18430
18836
|
matched = true;
|
|
18431
18837
|
}
|
|
@@ -18440,8 +18846,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18440
18846
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18441
18847
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
18442
18848
|
if (providerDir) {
|
|
18443
|
-
const fullDir =
|
|
18444
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18849
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18850
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18445
18851
|
}
|
|
18446
18852
|
}
|
|
18447
18853
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -18458,8 +18864,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18458
18864
|
resolved._resolvedScriptDir = dirOverride;
|
|
18459
18865
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
18460
18866
|
if (providerDir) {
|
|
18461
|
-
const fullDir =
|
|
18462
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18867
|
+
const fullDir = path18.join(providerDir, dirOverride);
|
|
18868
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18463
18869
|
}
|
|
18464
18870
|
}
|
|
18465
18871
|
} else if (override.scripts) {
|
|
@@ -18475,8 +18881,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18475
18881
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18476
18882
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
18477
18883
|
if (providerDir) {
|
|
18478
|
-
const fullDir =
|
|
18479
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18884
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18885
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18480
18886
|
}
|
|
18481
18887
|
}
|
|
18482
18888
|
}
|
|
@@ -18508,14 +18914,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18508
18914
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
18509
18915
|
return null;
|
|
18510
18916
|
}
|
|
18511
|
-
const dir =
|
|
18917
|
+
const dir = path18.join(providerDir, scriptDir);
|
|
18512
18918
|
if (!fs7.existsSync(dir)) {
|
|
18513
18919
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
18514
18920
|
return null;
|
|
18515
18921
|
}
|
|
18516
18922
|
const cached = this.scriptsCache.get(dir);
|
|
18517
18923
|
if (cached) return cached;
|
|
18518
|
-
const scriptsJs =
|
|
18924
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
18519
18925
|
if (fs7.existsSync(scriptsJs)) {
|
|
18520
18926
|
try {
|
|
18521
18927
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -18557,7 +18963,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18557
18963
|
return;
|
|
18558
18964
|
}
|
|
18559
18965
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
18560
|
-
this.log(`File changed: ${
|
|
18966
|
+
this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
|
|
18561
18967
|
this.reload();
|
|
18562
18968
|
}
|
|
18563
18969
|
};
|
|
@@ -18612,7 +19018,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18612
19018
|
}
|
|
18613
19019
|
const https = __require("https");
|
|
18614
19020
|
const { execSync: execSync7 } = __require("child_process");
|
|
18615
|
-
const metaPath =
|
|
19021
|
+
const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
18616
19022
|
let prevEtag = "";
|
|
18617
19023
|
let prevTimestamp = 0;
|
|
18618
19024
|
try {
|
|
@@ -18672,17 +19078,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18672
19078
|
return { updated: false };
|
|
18673
19079
|
}
|
|
18674
19080
|
this.log("Downloading latest providers from GitHub...");
|
|
18675
|
-
const tmpTar =
|
|
18676
|
-
const tmpExtract =
|
|
19081
|
+
const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
19082
|
+
const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
18677
19083
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
18678
19084
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
18679
19085
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
18680
19086
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
18681
19087
|
const rootDir = extracted.find(
|
|
18682
|
-
(d) => fs7.statSync(
|
|
19088
|
+
(d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
18683
19089
|
);
|
|
18684
19090
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
18685
|
-
const sourceDir =
|
|
19091
|
+
const sourceDir = path18.join(tmpExtract, rootDir);
|
|
18686
19092
|
const backupDir = this.upstreamDir + ".bak";
|
|
18687
19093
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
18688
19094
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -18757,8 +19163,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18757
19163
|
copyDirRecursive(src, dest) {
|
|
18758
19164
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18759
19165
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18760
|
-
const srcPath =
|
|
18761
|
-
const destPath =
|
|
19166
|
+
const srcPath = path18.join(src, entry.name);
|
|
19167
|
+
const destPath = path18.join(dest, entry.name);
|
|
18762
19168
|
if (entry.isDirectory()) {
|
|
18763
19169
|
this.copyDirRecursive(srcPath, destPath);
|
|
18764
19170
|
} else {
|
|
@@ -18769,7 +19175,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18769
19175
|
/** .meta.json save */
|
|
18770
19176
|
writeMeta(metaPath, etag, timestamp) {
|
|
18771
19177
|
try {
|
|
18772
|
-
fs7.mkdirSync(
|
|
19178
|
+
fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
|
|
18773
19179
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18774
19180
|
etag,
|
|
18775
19181
|
timestamp,
|
|
@@ -18786,7 +19192,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18786
19192
|
const scan = (d) => {
|
|
18787
19193
|
try {
|
|
18788
19194
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18789
|
-
if (entry.isDirectory()) scan(
|
|
19195
|
+
if (entry.isDirectory()) scan(path18.join(d, entry.name));
|
|
18790
19196
|
else if (entry.name === "provider.json") count++;
|
|
18791
19197
|
}
|
|
18792
19198
|
} catch {
|
|
@@ -19014,17 +19420,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19014
19420
|
for (const root of searchRoots) {
|
|
19015
19421
|
if (!fs7.existsSync(root)) continue;
|
|
19016
19422
|
const candidate = this.getProviderDir(root, cat, type);
|
|
19017
|
-
if (fs7.existsSync(
|
|
19018
|
-
const catDir =
|
|
19423
|
+
if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
|
|
19424
|
+
const catDir = path18.join(root, cat);
|
|
19019
19425
|
if (fs7.existsSync(catDir)) {
|
|
19020
19426
|
try {
|
|
19021
19427
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
19022
19428
|
if (!entry.isDirectory()) continue;
|
|
19023
|
-
const jsonPath =
|
|
19429
|
+
const jsonPath = path18.join(catDir, entry.name, "provider.json");
|
|
19024
19430
|
if (fs7.existsSync(jsonPath)) {
|
|
19025
19431
|
try {
|
|
19026
19432
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
19027
|
-
if (data.type === type) return
|
|
19433
|
+
if (data.type === type) return path18.join(catDir, entry.name);
|
|
19028
19434
|
} catch {
|
|
19029
19435
|
}
|
|
19030
19436
|
}
|
|
@@ -19041,7 +19447,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19041
19447
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
19042
19448
|
*/
|
|
19043
19449
|
buildScriptWrappersFromDir(dir) {
|
|
19044
|
-
const scriptsJs =
|
|
19450
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
19045
19451
|
if (fs7.existsSync(scriptsJs)) {
|
|
19046
19452
|
try {
|
|
19047
19453
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -19055,7 +19461,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19055
19461
|
for (const file of fs7.readdirSync(dir)) {
|
|
19056
19462
|
if (!file.endsWith(".js")) continue;
|
|
19057
19463
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
19058
|
-
const filePath =
|
|
19464
|
+
const filePath = path18.join(dir, file);
|
|
19059
19465
|
result[scriptName] = (...args) => {
|
|
19060
19466
|
try {
|
|
19061
19467
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -19115,7 +19521,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19115
19521
|
}
|
|
19116
19522
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
19117
19523
|
if (hasJson) {
|
|
19118
|
-
const jsonPath =
|
|
19524
|
+
const jsonPath = path18.join(d, "provider.json");
|
|
19119
19525
|
try {
|
|
19120
19526
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
19121
19527
|
const mod = JSON.parse(raw);
|
|
@@ -19136,7 +19542,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19136
19542
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
19137
19543
|
} else {
|
|
19138
19544
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
19139
|
-
const scriptsPath =
|
|
19545
|
+
const scriptsPath = path18.join(d, "scripts.js");
|
|
19140
19546
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
19141
19547
|
try {
|
|
19142
19548
|
delete __require.cache[__require.resolve(scriptsPath)];
|
|
@@ -19162,7 +19568,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19162
19568
|
if (!entry.isDirectory()) continue;
|
|
19163
19569
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
19164
19570
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
19165
|
-
scan(
|
|
19571
|
+
scan(path18.join(d, entry.name));
|
|
19166
19572
|
}
|
|
19167
19573
|
}
|
|
19168
19574
|
};
|
|
@@ -19487,8 +19893,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
19487
19893
|
const appNameMap = getMacAppIdentifiers();
|
|
19488
19894
|
const appName = appNameMap[ideId];
|
|
19489
19895
|
if (appName) {
|
|
19490
|
-
const storagePath =
|
|
19491
|
-
process.env.APPDATA ||
|
|
19896
|
+
const storagePath = path19.join(
|
|
19897
|
+
process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
|
|
19492
19898
|
appName,
|
|
19493
19899
|
"storage.json"
|
|
19494
19900
|
);
|
|
@@ -19677,9 +20083,9 @@ init_logger();
|
|
|
19677
20083
|
|
|
19678
20084
|
// src/logging/command-log.ts
|
|
19679
20085
|
import * as fs8 from "fs";
|
|
19680
|
-
import * as
|
|
20086
|
+
import * as path20 from "path";
|
|
19681
20087
|
import * as os16 from "os";
|
|
19682
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
20088
|
+
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
20089
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
19684
20090
|
var MAX_DAYS = 7;
|
|
19685
20091
|
try {
|
|
@@ -19717,13 +20123,13 @@ function getDateStr2() {
|
|
|
19717
20123
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19718
20124
|
}
|
|
19719
20125
|
var currentDate2 = getDateStr2();
|
|
19720
|
-
var currentFile =
|
|
20126
|
+
var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19721
20127
|
var writeCount2 = 0;
|
|
19722
20128
|
function checkRotation() {
|
|
19723
20129
|
const today = getDateStr2();
|
|
19724
20130
|
if (today !== currentDate2) {
|
|
19725
20131
|
currentDate2 = today;
|
|
19726
|
-
currentFile =
|
|
20132
|
+
currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19727
20133
|
cleanOldFiles();
|
|
19728
20134
|
}
|
|
19729
20135
|
}
|
|
@@ -19737,7 +20143,7 @@ function cleanOldFiles() {
|
|
|
19737
20143
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
19738
20144
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
19739
20145
|
try {
|
|
19740
|
-
fs8.unlinkSync(
|
|
20146
|
+
fs8.unlinkSync(path20.join(LOG_DIR2, file));
|
|
19741
20147
|
} catch {
|
|
19742
20148
|
}
|
|
19743
20149
|
}
|
|
@@ -19821,13 +20227,65 @@ cleanOldFiles();
|
|
|
19821
20227
|
|
|
19822
20228
|
// src/commands/router.ts
|
|
19823
20229
|
init_logger();
|
|
20230
|
+
import * as yaml from "js-yaml";
|
|
19824
20231
|
|
|
19825
20232
|
// src/commands/mesh-coordinator.ts
|
|
19826
|
-
import {
|
|
20233
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
20234
|
+
import { existsSync as existsSync15, readdirSync as readdirSync6, realpathSync as realpathSync2 } from "fs";
|
|
19827
20235
|
import { createRequire as createRequire2 } from "module";
|
|
19828
|
-
import
|
|
20236
|
+
import * as os17 from "os";
|
|
20237
|
+
import { dirname as dirname4, isAbsolute as isAbsolute10, join as join18, resolve as resolve13 } from "path";
|
|
19829
20238
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
19830
20239
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20240
|
+
var HERMES_CLI_TYPE = "hermes-cli";
|
|
20241
|
+
var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
|
|
20242
|
+
function isHermesProvider(provider, cliType) {
|
|
20243
|
+
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
20244
|
+
return type === HERMES_CLI_TYPE;
|
|
20245
|
+
}
|
|
20246
|
+
function resolveHermesMeshCoordinatorSetup(options) {
|
|
20247
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
20248
|
+
meshId: options.meshId,
|
|
20249
|
+
nodeExecutable: options.nodeExecutable,
|
|
20250
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath
|
|
20251
|
+
});
|
|
20252
|
+
if (!mcpServer) {
|
|
20253
|
+
return {
|
|
20254
|
+
kind: "unsupported",
|
|
20255
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20256
|
+
};
|
|
20257
|
+
}
|
|
20258
|
+
const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
|
|
20259
|
+
if (!configPath.trim()) {
|
|
20260
|
+
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20261
|
+
}
|
|
20262
|
+
return {
|
|
20263
|
+
kind: "auto_import",
|
|
20264
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20265
|
+
configPath,
|
|
20266
|
+
configFormat: "hermes_config_yaml",
|
|
20267
|
+
mcpServer
|
|
20268
|
+
};
|
|
20269
|
+
}
|
|
20270
|
+
function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
|
|
20271
|
+
return {
|
|
20272
|
+
kind: "manual",
|
|
20273
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20274
|
+
configFormat: "hermes_config_yaml",
|
|
20275
|
+
configPathCommand: HERMES_MCP_CONFIG_PATH,
|
|
20276
|
+
requiresRestart: true,
|
|
20277
|
+
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.",
|
|
20278
|
+
template: renderMeshCoordinatorTemplate(
|
|
20279
|
+
"mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
|
|
20280
|
+
{
|
|
20281
|
+
meshId,
|
|
20282
|
+
workspace,
|
|
20283
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20284
|
+
adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
|
|
20285
|
+
}
|
|
20286
|
+
)
|
|
20287
|
+
};
|
|
20288
|
+
}
|
|
19831
20289
|
function resolveMeshCoordinatorSetup(options) {
|
|
19832
20290
|
const { provider, meshId, workspace } = options;
|
|
19833
20291
|
const config = provider?.meshCoordinator;
|
|
@@ -19837,6 +20295,9 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19837
20295
|
reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
|
|
19838
20296
|
};
|
|
19839
20297
|
}
|
|
20298
|
+
if (isHermesProvider(provider, options.cliType)) {
|
|
20299
|
+
return resolveHermesMeshCoordinatorSetup(options);
|
|
20300
|
+
}
|
|
19840
20301
|
const mcpConfig = config.mcpConfig;
|
|
19841
20302
|
if (!mcpConfig || mcpConfig.mode === "none") {
|
|
19842
20303
|
return {
|
|
@@ -19846,8 +20307,8 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19846
20307
|
}
|
|
19847
20308
|
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
|
|
19848
20309
|
if (mcpConfig.mode === "auto_import") {
|
|
19849
|
-
const
|
|
19850
|
-
if (!
|
|
20310
|
+
const path27 = mcpConfig.path?.trim();
|
|
20311
|
+
if (!path27) {
|
|
19851
20312
|
return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
|
|
19852
20313
|
}
|
|
19853
20314
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
@@ -19858,13 +20319,13 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19858
20319
|
if (!mcpServer) {
|
|
19859
20320
|
return {
|
|
19860
20321
|
kind: "unsupported",
|
|
19861
|
-
reason: "Could not resolve the ADHDev MCP server entrypoint
|
|
20322
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
19862
20323
|
};
|
|
19863
20324
|
}
|
|
19864
20325
|
return {
|
|
19865
20326
|
kind: "auto_import",
|
|
19866
20327
|
serverName,
|
|
19867
|
-
configPath:
|
|
20328
|
+
configPath: resolveMcpConfigPath(path27, workspace),
|
|
19868
20329
|
configFormat: mcpConfig.format,
|
|
19869
20330
|
mcpServer
|
|
19870
20331
|
};
|
|
@@ -19898,14 +20359,85 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19898
20359
|
function renderMeshCoordinatorTemplate(template, values) {
|
|
19899
20360
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
|
|
19900
20361
|
}
|
|
20362
|
+
function resolveMcpConfigPath(configPath, workspace) {
|
|
20363
|
+
const trimmed = configPath.trim();
|
|
20364
|
+
if (trimmed === "~") return os17.homedir();
|
|
20365
|
+
if (trimmed.startsWith("~/")) return join18(os17.homedir(), trimmed.slice(2));
|
|
20366
|
+
if (isAbsolute10(trimmed)) return trimmed;
|
|
20367
|
+
return join18(workspace, trimmed);
|
|
20368
|
+
}
|
|
19901
20369
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
19902
20370
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
19903
20371
|
if (!entryPath) return null;
|
|
20372
|
+
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
|
|
20373
|
+
if (!nodeExecutable) return null;
|
|
19904
20374
|
return {
|
|
19905
|
-
command:
|
|
20375
|
+
command: nodeExecutable,
|
|
19906
20376
|
args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
|
|
19907
20377
|
};
|
|
19908
20378
|
}
|
|
20379
|
+
function resolveMcpNodeExecutable(explicitExecutable) {
|
|
20380
|
+
const explicit = explicitExecutable?.trim();
|
|
20381
|
+
if (explicit) return explicit;
|
|
20382
|
+
const candidates = [];
|
|
20383
|
+
const addCandidate = (candidate) => {
|
|
20384
|
+
const trimmed = candidate?.trim();
|
|
20385
|
+
if (!trimmed) return;
|
|
20386
|
+
const normalized = normalizeExistingPath(trimmed) || trimmed;
|
|
20387
|
+
if (!candidates.includes(normalized)) candidates.push(normalized);
|
|
20388
|
+
};
|
|
20389
|
+
addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
|
|
20390
|
+
addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
|
|
20391
|
+
addCandidate(process.env.npm_node_execpath);
|
|
20392
|
+
addNodeCandidatesFromPath(process.env.PATH, addCandidate);
|
|
20393
|
+
addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
|
|
20394
|
+
addCandidate("/opt/homebrew/bin/node");
|
|
20395
|
+
addCandidate("/usr/local/bin/node");
|
|
20396
|
+
addCandidate("/usr/bin/node");
|
|
20397
|
+
addCandidate(process.execPath);
|
|
20398
|
+
for (const candidate of candidates) {
|
|
20399
|
+
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
|
|
20400
|
+
}
|
|
20401
|
+
return null;
|
|
20402
|
+
}
|
|
20403
|
+
function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
20404
|
+
for (const entry of (pathValue || "").split(":")) {
|
|
20405
|
+
const dir = entry.trim();
|
|
20406
|
+
if (!dir) continue;
|
|
20407
|
+
addCandidate(join18(dir, "node"));
|
|
20408
|
+
}
|
|
20409
|
+
}
|
|
20410
|
+
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
20411
|
+
const versionsDir = join18(homeDir, ".nvm", "versions", "node");
|
|
20412
|
+
try {
|
|
20413
|
+
const versionDirs = readdirSync6(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
20414
|
+
for (const versionDir of versionDirs) {
|
|
20415
|
+
addCandidate(join18(versionsDir, versionDir, "bin", "node"));
|
|
20416
|
+
}
|
|
20417
|
+
} catch {
|
|
20418
|
+
}
|
|
20419
|
+
}
|
|
20420
|
+
function compareNodeVersionNamesDescending(a, b) {
|
|
20421
|
+
const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
20422
|
+
const left = parse(a);
|
|
20423
|
+
const right = parse(b);
|
|
20424
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
20425
|
+
const diff = (right[i] || 0) - (left[i] || 0);
|
|
20426
|
+
if (diff !== 0) return diff;
|
|
20427
|
+
}
|
|
20428
|
+
return b.localeCompare(a);
|
|
20429
|
+
}
|
|
20430
|
+
function nodeRuntimeSupportsWebSocket(nodeExecutable) {
|
|
20431
|
+
try {
|
|
20432
|
+
execFileSync2(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
|
|
20433
|
+
stdio: "ignore",
|
|
20434
|
+
timeout: 3e3
|
|
20435
|
+
});
|
|
20436
|
+
return true;
|
|
20437
|
+
} catch {
|
|
20438
|
+
return false;
|
|
20439
|
+
}
|
|
20440
|
+
}
|
|
19909
20441
|
function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
19910
20442
|
const explicit = explicitPath?.trim();
|
|
19911
20443
|
if (explicit) return normalizeExistingPath(explicit) || explicit;
|
|
@@ -19918,7 +20450,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19918
20450
|
const addPackagedCandidates = (baseFile) => {
|
|
19919
20451
|
if (!baseFile) return;
|
|
19920
20452
|
const realBase = normalizeExistingPath(baseFile) || baseFile;
|
|
19921
|
-
const dir =
|
|
20453
|
+
const dir = dirname4(realBase);
|
|
19922
20454
|
addCandidate(resolve13(dir, "../vendor/mcp-server/index.js"));
|
|
19923
20455
|
addCandidate(resolve13(dir, "../../vendor/mcp-server/index.js"));
|
|
19924
20456
|
addCandidate(resolve13(dir, "../../../vendor/mcp-server/index.js"));
|
|
@@ -19931,7 +20463,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19931
20463
|
if (normalized) return normalized;
|
|
19932
20464
|
}
|
|
19933
20465
|
try {
|
|
19934
|
-
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] :
|
|
20466
|
+
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join18(process.cwd(), "adhdev-daemon.js");
|
|
19935
20467
|
const req = createRequire2(requireBase);
|
|
19936
20468
|
const resolvedModule = req.resolve("@adhdev/mcp-server");
|
|
19937
20469
|
return normalizeExistingPath(resolvedModule) || resolvedModule;
|
|
@@ -19941,16 +20473,110 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19941
20473
|
}
|
|
19942
20474
|
function normalizeExistingPath(filePath) {
|
|
19943
20475
|
try {
|
|
19944
|
-
if (!
|
|
20476
|
+
if (!existsSync15(filePath)) return null;
|
|
19945
20477
|
return realpathSync2.native(filePath);
|
|
19946
20478
|
} catch {
|
|
19947
20479
|
return null;
|
|
19948
20480
|
}
|
|
19949
20481
|
}
|
|
19950
20482
|
|
|
20483
|
+
// src/mesh/mesh-events.ts
|
|
20484
|
+
init_mesh_config();
|
|
20485
|
+
init_logger();
|
|
20486
|
+
function readNonEmptyString(value) {
|
|
20487
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
20488
|
+
}
|
|
20489
|
+
function formatCompletionMetadata(event) {
|
|
20490
|
+
const parts = [
|
|
20491
|
+
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
20492
|
+
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
20493
|
+
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
20494
|
+
].filter(Boolean);
|
|
20495
|
+
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
20496
|
+
}
|
|
20497
|
+
function buildMeshSystemMessage(args) {
|
|
20498
|
+
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
20499
|
+
if (args.event === "agent:generating_completed") {
|
|
20500
|
+
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path; use mesh_read_chat once to review its final progress, but do not poll repeatedly.`;
|
|
20501
|
+
}
|
|
20502
|
+
if (args.event === "agent:waiting_approval") {
|
|
20503
|
+
return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
20504
|
+
}
|
|
20505
|
+
return "";
|
|
20506
|
+
}
|
|
20507
|
+
function injectMeshSystemMessage(components, args) {
|
|
20508
|
+
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
20509
|
+
const instState = inst.getState();
|
|
20510
|
+
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
20511
|
+
if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
|
|
20512
|
+
return true;
|
|
20513
|
+
});
|
|
20514
|
+
if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
|
|
20515
|
+
const messageText = buildMeshSystemMessage({
|
|
20516
|
+
event: args.event,
|
|
20517
|
+
nodeLabel: args.nodeLabel,
|
|
20518
|
+
metadataEvent: args.metadataEvent
|
|
20519
|
+
});
|
|
20520
|
+
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
20521
|
+
for (const coord of coordinatorInstances) {
|
|
20522
|
+
const coordState = coord.getState();
|
|
20523
|
+
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
20524
|
+
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
20525
|
+
}
|
|
20526
|
+
return { success: true, forwarded: coordinatorInstances.length };
|
|
20527
|
+
}
|
|
20528
|
+
function handleMeshForwardEvent(components, payload) {
|
|
20529
|
+
const eventName = readNonEmptyString(payload.event);
|
|
20530
|
+
if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
|
|
20531
|
+
return { success: false, error: "unsupported mesh event" };
|
|
20532
|
+
}
|
|
20533
|
+
const meshId = readNonEmptyString(payload.meshId);
|
|
20534
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
20535
|
+
const nodeId = readNonEmptyString(payload.nodeId);
|
|
20536
|
+
const workspace = readNonEmptyString(payload.workspace);
|
|
20537
|
+
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
20538
|
+
return injectMeshSystemMessage(components, {
|
|
20539
|
+
meshId,
|
|
20540
|
+
nodeLabel,
|
|
20541
|
+
event: eventName,
|
|
20542
|
+
metadataEvent: {
|
|
20543
|
+
targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
|
|
20544
|
+
providerType: readNonEmptyString(payload.providerType),
|
|
20545
|
+
providerSessionId: readNonEmptyString(payload.providerSessionId)
|
|
20546
|
+
}
|
|
20547
|
+
});
|
|
20548
|
+
}
|
|
20549
|
+
function setupMeshEventForwarding(components) {
|
|
20550
|
+
components.instanceManager.onEvent((event) => {
|
|
20551
|
+
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
20552
|
+
const instanceId = readNonEmptyString(event.instanceId);
|
|
20553
|
+
if (!instanceId) return;
|
|
20554
|
+
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
20555
|
+
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
20556
|
+
const state = sourceInstance.getState();
|
|
20557
|
+
const workspace = readNonEmptyString(state.workspace);
|
|
20558
|
+
if (!workspace) return;
|
|
20559
|
+
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
20560
|
+
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
20561
|
+
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
20562
|
+
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
20563
|
+
if (!meshId) return;
|
|
20564
|
+
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
20565
|
+
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
20566
|
+
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
20567
|
+
injectMeshSystemMessage(components, {
|
|
20568
|
+
meshId,
|
|
20569
|
+
sourceInstanceId: instanceId,
|
|
20570
|
+
nodeLabel,
|
|
20571
|
+
event: event.event,
|
|
20572
|
+
metadataEvent: event
|
|
20573
|
+
});
|
|
20574
|
+
});
|
|
20575
|
+
}
|
|
20576
|
+
|
|
19951
20577
|
// src/status/snapshot.ts
|
|
19952
20578
|
init_config();
|
|
19953
|
-
import * as
|
|
20579
|
+
import * as os18 from "os";
|
|
19954
20580
|
init_terminal_screen();
|
|
19955
20581
|
init_logger();
|
|
19956
20582
|
var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
|
|
@@ -20005,8 +20631,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20005
20631
|
}
|
|
20006
20632
|
function buildMachineInfo(profile = "full") {
|
|
20007
20633
|
const base = {
|
|
20008
|
-
hostname:
|
|
20009
|
-
platform:
|
|
20634
|
+
hostname: os18.hostname(),
|
|
20635
|
+
platform: os18.platform()
|
|
20010
20636
|
};
|
|
20011
20637
|
if (profile === "live") {
|
|
20012
20638
|
return base;
|
|
@@ -20015,23 +20641,23 @@ function buildMachineInfo(profile = "full") {
|
|
|
20015
20641
|
const memSnap2 = getHostMemorySnapshot();
|
|
20016
20642
|
return {
|
|
20017
20643
|
...base,
|
|
20018
|
-
arch:
|
|
20019
|
-
cpus:
|
|
20644
|
+
arch: os18.arch(),
|
|
20645
|
+
cpus: os18.cpus().length,
|
|
20020
20646
|
totalMem: memSnap2.totalMem,
|
|
20021
|
-
release:
|
|
20647
|
+
release: os18.release()
|
|
20022
20648
|
};
|
|
20023
20649
|
}
|
|
20024
20650
|
const memSnap = getHostMemorySnapshot();
|
|
20025
20651
|
return {
|
|
20026
20652
|
...base,
|
|
20027
|
-
arch:
|
|
20028
|
-
cpus:
|
|
20653
|
+
arch: os18.arch(),
|
|
20654
|
+
cpus: os18.cpus().length,
|
|
20029
20655
|
totalMem: memSnap.totalMem,
|
|
20030
20656
|
freeMem: memSnap.freeMem,
|
|
20031
20657
|
availableMem: memSnap.availableMem,
|
|
20032
|
-
loadavg:
|
|
20033
|
-
uptime:
|
|
20034
|
-
release:
|
|
20658
|
+
loadavg: os18.loadavg(),
|
|
20659
|
+
uptime: os18.uptime(),
|
|
20660
|
+
release: os18.release()
|
|
20035
20661
|
};
|
|
20036
20662
|
}
|
|
20037
20663
|
function parseMessageTime(value) {
|
|
@@ -20262,17 +20888,17 @@ function buildStatusSnapshot(options) {
|
|
|
20262
20888
|
}
|
|
20263
20889
|
|
|
20264
20890
|
// src/commands/upgrade-helper.ts
|
|
20265
|
-
import { execFileSync as
|
|
20891
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
20266
20892
|
import { spawn as spawn3 } from "child_process";
|
|
20267
20893
|
import * as fs9 from "fs";
|
|
20268
|
-
import * as
|
|
20269
|
-
import * as
|
|
20894
|
+
import * as os19 from "os";
|
|
20895
|
+
import * as path21 from "path";
|
|
20270
20896
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
20271
20897
|
function getUpgradeLogPath() {
|
|
20272
|
-
const home =
|
|
20273
|
-
const dir =
|
|
20898
|
+
const home = os19.homedir();
|
|
20899
|
+
const dir = path21.join(home, ".adhdev");
|
|
20274
20900
|
fs9.mkdirSync(dir, { recursive: true });
|
|
20275
|
-
return
|
|
20901
|
+
return path21.join(dir, "daemon-upgrade.log");
|
|
20276
20902
|
}
|
|
20277
20903
|
function appendUpgradeLog(message) {
|
|
20278
20904
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -20283,14 +20909,14 @@ function appendUpgradeLog(message) {
|
|
|
20283
20909
|
}
|
|
20284
20910
|
}
|
|
20285
20911
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
20286
|
-
const binDir =
|
|
20912
|
+
const binDir = path21.dirname(nodeExecutable);
|
|
20287
20913
|
if (platform10 === "win32") {
|
|
20288
|
-
const npmCliPath =
|
|
20914
|
+
const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
20289
20915
|
if (fs9.existsSync(npmCliPath)) {
|
|
20290
20916
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20291
20917
|
}
|
|
20292
20918
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
20293
|
-
const candidatePath =
|
|
20919
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20294
20920
|
if (fs9.existsSync(candidatePath)) {
|
|
20295
20921
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20296
20922
|
}
|
|
@@ -20298,7 +20924,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
20298
20924
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20299
20925
|
}
|
|
20300
20926
|
for (const candidate of ["npm"]) {
|
|
20301
|
-
const candidatePath =
|
|
20927
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20302
20928
|
if (fs9.existsSync(candidatePath)) {
|
|
20303
20929
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20304
20930
|
}
|
|
@@ -20315,13 +20941,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20315
20941
|
let currentDir = resolvedPath;
|
|
20316
20942
|
try {
|
|
20317
20943
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
20318
|
-
currentDir =
|
|
20944
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20319
20945
|
}
|
|
20320
20946
|
} catch {
|
|
20321
|
-
currentDir =
|
|
20947
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20322
20948
|
}
|
|
20323
20949
|
while (true) {
|
|
20324
|
-
const packageJsonPath =
|
|
20950
|
+
const packageJsonPath = path21.join(currentDir, "package.json");
|
|
20325
20951
|
try {
|
|
20326
20952
|
if (fs9.existsSync(packageJsonPath)) {
|
|
20327
20953
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -20332,7 +20958,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20332
20958
|
}
|
|
20333
20959
|
} catch {
|
|
20334
20960
|
}
|
|
20335
|
-
const parentDir =
|
|
20961
|
+
const parentDir = path21.dirname(currentDir);
|
|
20336
20962
|
if (parentDir === currentDir) {
|
|
20337
20963
|
return null;
|
|
20338
20964
|
}
|
|
@@ -20340,13 +20966,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20340
20966
|
}
|
|
20341
20967
|
}
|
|
20342
20968
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
20343
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
20344
|
-
if (
|
|
20969
|
+
const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
|
|
20970
|
+
if (path21.basename(nodeModulesDir) !== "node_modules") {
|
|
20345
20971
|
return null;
|
|
20346
20972
|
}
|
|
20347
|
-
const maybeLibDir =
|
|
20348
|
-
if (
|
|
20349
|
-
return
|
|
20973
|
+
const maybeLibDir = path21.dirname(nodeModulesDir);
|
|
20974
|
+
if (path21.basename(maybeLibDir) === "lib") {
|
|
20975
|
+
return path21.dirname(maybeLibDir);
|
|
20350
20976
|
}
|
|
20351
20977
|
return maybeLibDir;
|
|
20352
20978
|
}
|
|
@@ -20382,7 +21008,7 @@ function getNpmExecOptions(platform10 = process.platform) {
|
|
|
20382
21008
|
}
|
|
20383
21009
|
function execNpmCommandSync(args, options = {}, surface) {
|
|
20384
21010
|
const execOptions = surface?.execOptions || getNpmExecOptions();
|
|
20385
|
-
return
|
|
21011
|
+
return execFileSync3(
|
|
20386
21012
|
surface?.npmExecutable || "npm",
|
|
20387
21013
|
[...surface?.npmArgsPrefix || [], ...args],
|
|
20388
21014
|
{
|
|
@@ -20395,7 +21021,7 @@ function execNpmCommandSync(args, options = {}, surface) {
|
|
|
20395
21021
|
function killPid(pid) {
|
|
20396
21022
|
try {
|
|
20397
21023
|
if (process.platform === "win32") {
|
|
20398
|
-
|
|
21024
|
+
execFileSync3("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
|
|
20399
21025
|
} else {
|
|
20400
21026
|
process.kill(pid, "SIGTERM");
|
|
20401
21027
|
}
|
|
@@ -20407,7 +21033,7 @@ function killPid(pid) {
|
|
|
20407
21033
|
function getWindowsProcessCommandLine(pid) {
|
|
20408
21034
|
const pidFilter = `ProcessId=${pid}`;
|
|
20409
21035
|
try {
|
|
20410
|
-
const psOut =
|
|
21036
|
+
const psOut = execFileSync3("powershell.exe", [
|
|
20411
21037
|
"-NoProfile",
|
|
20412
21038
|
"-NonInteractive",
|
|
20413
21039
|
"-ExecutionPolicy",
|
|
@@ -20419,7 +21045,7 @@ function getWindowsProcessCommandLine(pid) {
|
|
|
20419
21045
|
} catch {
|
|
20420
21046
|
}
|
|
20421
21047
|
try {
|
|
20422
|
-
const wmicOut =
|
|
21048
|
+
const wmicOut = execFileSync3("wmic", [
|
|
20423
21049
|
"process",
|
|
20424
21050
|
"where",
|
|
20425
21051
|
pidFilter,
|
|
@@ -20435,7 +21061,7 @@ function getProcessCommandLine(pid) {
|
|
|
20435
21061
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
20436
21062
|
if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
|
|
20437
21063
|
try {
|
|
20438
|
-
const text =
|
|
21064
|
+
const text = execFileSync3("ps", ["-o", "command=", "-p", String(pid)], {
|
|
20439
21065
|
encoding: "utf8",
|
|
20440
21066
|
timeout: 3e3,
|
|
20441
21067
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -20461,7 +21087,7 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
20461
21087
|
}
|
|
20462
21088
|
}
|
|
20463
21089
|
function stopSessionHostProcesses(appName) {
|
|
20464
|
-
const pidFile =
|
|
21090
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
20465
21091
|
try {
|
|
20466
21092
|
if (fs9.existsSync(pidFile)) {
|
|
20467
21093
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -20478,7 +21104,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
20478
21104
|
}
|
|
20479
21105
|
}
|
|
20480
21106
|
function removeDaemonPidFile() {
|
|
20481
|
-
const pidFile =
|
|
21107
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
20482
21108
|
try {
|
|
20483
21109
|
fs9.unlinkSync(pidFile);
|
|
20484
21110
|
} catch {
|
|
@@ -20489,7 +21115,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20489
21115
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20490
21116
|
if (!npmRoot) return;
|
|
20491
21117
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20492
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
21118
|
+
const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
|
|
20493
21119
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
20494
21120
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
20495
21121
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -20497,25 +21123,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20497
21123
|
}
|
|
20498
21124
|
if (pkgName.startsWith("@")) {
|
|
20499
21125
|
const [scope, name] = pkgName.split("/");
|
|
20500
|
-
const scopeDir =
|
|
21126
|
+
const scopeDir = path21.join(npmRoot, scope);
|
|
20501
21127
|
if (!fs9.existsSync(scopeDir)) return;
|
|
20502
21128
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
20503
21129
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
20504
|
-
fs9.rmSync(
|
|
20505
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
21130
|
+
fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
|
|
21131
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
|
|
20506
21132
|
}
|
|
20507
21133
|
} else {
|
|
20508
21134
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
20509
21135
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
20510
|
-
fs9.rmSync(
|
|
20511
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
21136
|
+
fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
|
|
21137
|
+
appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
|
|
20512
21138
|
}
|
|
20513
21139
|
}
|
|
20514
21140
|
if (fs9.existsSync(binDir)) {
|
|
20515
21141
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
20516
21142
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
20517
|
-
fs9.rmSync(
|
|
20518
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
21143
|
+
fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
|
|
21144
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
|
|
20519
21145
|
}
|
|
20520
21146
|
}
|
|
20521
21147
|
}
|
|
@@ -20551,7 +21177,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
20551
21177
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
20552
21178
|
const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
|
|
20553
21179
|
appendUpgradeLog(`Installing ${spec}`);
|
|
20554
|
-
const installOutput =
|
|
21180
|
+
const installOutput = execFileSync3(
|
|
20555
21181
|
installCommand.command,
|
|
20556
21182
|
installCommand.args,
|
|
20557
21183
|
{
|
|
@@ -20616,6 +21242,56 @@ function normalizeReleaseChannel(value) {
|
|
|
20616
21242
|
function resolveUpgradeChannel(args) {
|
|
20617
21243
|
return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
|
|
20618
21244
|
}
|
|
21245
|
+
function readProviderPriorityFromPolicy(policy) {
|
|
21246
|
+
const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
|
|
21247
|
+
const raw = record.providerPriority;
|
|
21248
|
+
if (!Array.isArray(raw)) return [];
|
|
21249
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21250
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
21251
|
+
if (seen.has(type)) return false;
|
|
21252
|
+
seen.add(type);
|
|
21253
|
+
return true;
|
|
21254
|
+
});
|
|
21255
|
+
}
|
|
21256
|
+
async function resolveProviderTypeFromPriority(args) {
|
|
21257
|
+
if (!args.providerPriority.length) {
|
|
21258
|
+
return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
|
|
21259
|
+
}
|
|
21260
|
+
const failed = [];
|
|
21261
|
+
for (const requestedType of args.providerPriority) {
|
|
21262
|
+
const normalizedType = args.providerLoader.resolveAlias(requestedType);
|
|
21263
|
+
if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
21264
|
+
failed.push(`${requestedType}: disabled`);
|
|
21265
|
+
continue;
|
|
21266
|
+
}
|
|
21267
|
+
const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
|
|
21268
|
+
args.providerLoader.setCliDetectionResults([{
|
|
21269
|
+
id: normalizedType,
|
|
21270
|
+
installed: !!detected,
|
|
21271
|
+
path: detected?.path
|
|
21272
|
+
}], false);
|
|
21273
|
+
args.onStatusChange?.();
|
|
21274
|
+
if (detected) return { providerType: normalizedType };
|
|
21275
|
+
failed.push(`${requestedType}: not detected`);
|
|
21276
|
+
}
|
|
21277
|
+
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
21278
|
+
}
|
|
21279
|
+
function loadYamlModule() {
|
|
21280
|
+
return yaml;
|
|
21281
|
+
}
|
|
21282
|
+
function getMcpServersKey(format) {
|
|
21283
|
+
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
21284
|
+
}
|
|
21285
|
+
function parseMeshCoordinatorMcpConfig(text, format) {
|
|
21286
|
+
if (!text.trim()) return {};
|
|
21287
|
+
if (format === "claude_mcp_json") return JSON.parse(text);
|
|
21288
|
+
const parsed = loadYamlModule().load(text);
|
|
21289
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
21290
|
+
}
|
|
21291
|
+
function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
21292
|
+
if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
|
|
21293
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
21294
|
+
}
|
|
20619
21295
|
var CHAT_COMMANDS = [
|
|
20620
21296
|
"send_chat",
|
|
20621
21297
|
"new_chat",
|
|
@@ -20714,6 +21390,154 @@ var DaemonCommandRouter = class {
|
|
|
20714
21390
|
constructor(deps) {
|
|
20715
21391
|
this.deps = deps;
|
|
20716
21392
|
}
|
|
21393
|
+
getCachedInlineMesh(meshId, inlineMesh) {
|
|
21394
|
+
if (inlineMesh && typeof inlineMesh === "object") {
|
|
21395
|
+
this.inlineMeshCache.set(meshId, inlineMesh);
|
|
21396
|
+
return inlineMesh;
|
|
21397
|
+
}
|
|
21398
|
+
return this.inlineMeshCache.get(meshId);
|
|
21399
|
+
}
|
|
21400
|
+
async getMeshForCommand(meshId, inlineMesh) {
|
|
21401
|
+
try {
|
|
21402
|
+
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21403
|
+
const mesh = getMesh3(meshId);
|
|
21404
|
+
if (mesh) return { mesh, inline: false };
|
|
21405
|
+
} catch {
|
|
21406
|
+
}
|
|
21407
|
+
const cached = this.getCachedInlineMesh(meshId, inlineMesh);
|
|
21408
|
+
return cached ? { mesh: cached, inline: true } : null;
|
|
21409
|
+
}
|
|
21410
|
+
updateInlineMeshNode(meshId, mesh, node) {
|
|
21411
|
+
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
21412
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
21413
|
+
if (idx >= 0) mesh.nodes[idx] = node;
|
|
21414
|
+
else mesh.nodes.push(node);
|
|
21415
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21416
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21417
|
+
}
|
|
21418
|
+
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
21419
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
21420
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
|
|
21421
|
+
if (idx === -1) return false;
|
|
21422
|
+
mesh.nodes.splice(idx, 1);
|
|
21423
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21424
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21425
|
+
return true;
|
|
21426
|
+
}
|
|
21427
|
+
normalizeMeshSessionCleanupMode(value) {
|
|
21428
|
+
return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
|
|
21429
|
+
}
|
|
21430
|
+
sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
|
|
21431
|
+
const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
|
|
21432
|
+
if (!sessionId) return false;
|
|
21433
|
+
if (sessionIds?.size) return sessionIds.has(sessionId);
|
|
21434
|
+
const workspace = typeof node?.workspace === "string" ? node.workspace : "";
|
|
21435
|
+
if (workspace && record?.workspace === workspace) return true;
|
|
21436
|
+
if (record?.meta?.meshNodeId === nodeId) return true;
|
|
21437
|
+
return false;
|
|
21438
|
+
}
|
|
21439
|
+
isCompletedHostedSession(record) {
|
|
21440
|
+
return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
|
|
21441
|
+
}
|
|
21442
|
+
async cleanupMeshSessions(args) {
|
|
21443
|
+
if (args.mode === "preserve") {
|
|
21444
|
+
return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
|
|
21445
|
+
}
|
|
21446
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
21447
|
+
const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
|
|
21448
|
+
const sessions = await this.deps.sessionHostControl.listSessions();
|
|
21449
|
+
const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
|
|
21450
|
+
const hasExplicitSessionIds = !!requestedSessionIds?.size;
|
|
21451
|
+
const stoppedSessionIds = [];
|
|
21452
|
+
const deletedSessionIds = [];
|
|
21453
|
+
const skippedSessionIds = [];
|
|
21454
|
+
const skippedLiveSessionIds = [];
|
|
21455
|
+
const deleteUnsupportedSessionIds = [];
|
|
21456
|
+
const recordsRemainSessionIds = [];
|
|
21457
|
+
const errors = [];
|
|
21458
|
+
const matchedBySurfaceKind = {
|
|
21459
|
+
live_runtime: 0,
|
|
21460
|
+
recovery_snapshot: 0,
|
|
21461
|
+
inactive_record: 0
|
|
21462
|
+
};
|
|
21463
|
+
for (const record of matched) {
|
|
21464
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21465
|
+
matchedBySurfaceKind[surfaceKind] += 1;
|
|
21466
|
+
}
|
|
21467
|
+
for (const record of matched) {
|
|
21468
|
+
const sessionId = String(record.sessionId);
|
|
21469
|
+
const completed = this.isCompletedHostedSession(record);
|
|
21470
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21471
|
+
const liveRuntime = surfaceKind === "live_runtime";
|
|
21472
|
+
if (!hasExplicitSessionIds && liveRuntime) {
|
|
21473
|
+
skippedSessionIds.push(sessionId);
|
|
21474
|
+
skippedLiveSessionIds.push(sessionId);
|
|
21475
|
+
continue;
|
|
21476
|
+
}
|
|
21477
|
+
try {
|
|
21478
|
+
if (args.mode === "stop") {
|
|
21479
|
+
if (!completed) {
|
|
21480
|
+
if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21481
|
+
stoppedSessionIds.push(sessionId);
|
|
21482
|
+
} else {
|
|
21483
|
+
skippedSessionIds.push(sessionId);
|
|
21484
|
+
}
|
|
21485
|
+
continue;
|
|
21486
|
+
}
|
|
21487
|
+
if (args.mode === "delete_stopped") {
|
|
21488
|
+
if (completed) {
|
|
21489
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
|
|
21490
|
+
deletedSessionIds.push(sessionId);
|
|
21491
|
+
} else {
|
|
21492
|
+
skippedSessionIds.push(sessionId);
|
|
21493
|
+
}
|
|
21494
|
+
continue;
|
|
21495
|
+
}
|
|
21496
|
+
if (args.mode === "stop_and_delete") {
|
|
21497
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
|
|
21498
|
+
deletedSessionIds.push(sessionId);
|
|
21499
|
+
continue;
|
|
21500
|
+
}
|
|
21501
|
+
} catch (e) {
|
|
21502
|
+
const message = e?.message || String(e);
|
|
21503
|
+
if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
|
|
21504
|
+
deleteUnsupportedSessionIds.push(sessionId);
|
|
21505
|
+
recordsRemainSessionIds.push(sessionId);
|
|
21506
|
+
if (args.mode === "stop_and_delete" && !completed) {
|
|
21507
|
+
try {
|
|
21508
|
+
await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21509
|
+
stoppedSessionIds.push(sessionId);
|
|
21510
|
+
} catch (stopError) {
|
|
21511
|
+
errors.push({ sessionId, error: stopError?.message || String(stopError) });
|
|
21512
|
+
continue;
|
|
21513
|
+
}
|
|
21514
|
+
}
|
|
21515
|
+
skippedSessionIds.push(sessionId);
|
|
21516
|
+
continue;
|
|
21517
|
+
}
|
|
21518
|
+
errors.push({ sessionId, error: message });
|
|
21519
|
+
}
|
|
21520
|
+
}
|
|
21521
|
+
const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
|
|
21522
|
+
return {
|
|
21523
|
+
success: errors.length === 0,
|
|
21524
|
+
mode: args.mode,
|
|
21525
|
+
dryRun: args.dryRun === true,
|
|
21526
|
+
matchedCount: matched.length,
|
|
21527
|
+
matchedBySurfaceKind,
|
|
21528
|
+
stoppedSessionIds,
|
|
21529
|
+
deletedSessionIds,
|
|
21530
|
+
skippedSessionIds,
|
|
21531
|
+
skippedLiveSessionIds,
|
|
21532
|
+
...deleteUnsupported ? {
|
|
21533
|
+
deleteUnsupported: true,
|
|
21534
|
+
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
21535
|
+
deleteUnsupportedSessionIds,
|
|
21536
|
+
recordsRemainSessionIds
|
|
21537
|
+
} : {},
|
|
21538
|
+
...errors.length ? { errors } : {}
|
|
21539
|
+
};
|
|
21540
|
+
}
|
|
20717
21541
|
async traceSessionHostAction(action, args, run, summarizeResult) {
|
|
20718
21542
|
const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
|
|
20719
21543
|
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -20833,6 +21657,9 @@ var DaemonCommandRouter = class {
|
|
|
20833
21657
|
async executeDaemonCommand(cmd, args) {
|
|
20834
21658
|
switch (cmd) {
|
|
20835
21659
|
// ─── CLI / ACP commands ───
|
|
21660
|
+
case "mesh_forward_event": {
|
|
21661
|
+
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
21662
|
+
}
|
|
20836
21663
|
case "launch_cli":
|
|
20837
21664
|
case "stop_cli":
|
|
20838
21665
|
case "set_cli_view_mode":
|
|
@@ -21377,7 +22204,26 @@ var DaemonCommandRouter = class {
|
|
|
21377
22204
|
if (!name) return { success: false, error: "name required" };
|
|
21378
22205
|
try {
|
|
21379
22206
|
const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21380
|
-
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
|
|
22207
|
+
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
|
|
22208
|
+
return { success: true, mesh };
|
|
22209
|
+
} catch (e) {
|
|
22210
|
+
return { success: false, error: e.message };
|
|
22211
|
+
}
|
|
22212
|
+
}
|
|
22213
|
+
case "update_mesh": {
|
|
22214
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22215
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22216
|
+
try {
|
|
22217
|
+
const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22218
|
+
const patch = {};
|
|
22219
|
+
if (typeof args?.name === "string") patch.name = args.name;
|
|
22220
|
+
if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
|
|
22221
|
+
if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
|
|
22222
|
+
if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
|
|
22223
|
+
if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
|
|
22224
|
+
const mesh = updateMesh2(meshId, patch);
|
|
22225
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22226
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21381
22227
|
return { success: true, mesh };
|
|
21382
22228
|
} catch (e) {
|
|
21383
22229
|
return { success: false, error: e.message };
|
|
@@ -21401,21 +22247,164 @@ var DaemonCommandRouter = class {
|
|
|
21401
22247
|
if (!workspace) return { success: false, error: "workspace required" };
|
|
21402
22248
|
try {
|
|
21403
22249
|
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21404
|
-
const
|
|
22250
|
+
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
22251
|
+
const readOnly = args?.readOnly === true;
|
|
22252
|
+
const policy = {
|
|
22253
|
+
...readOnly ? { readOnly: true } : {},
|
|
22254
|
+
...providerPriority.length ? { providerPriority } : {}
|
|
22255
|
+
};
|
|
22256
|
+
const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
|
|
21405
22257
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
21406
22258
|
return { success: true, node };
|
|
21407
22259
|
} catch (e) {
|
|
21408
22260
|
return { success: false, error: e.message };
|
|
21409
22261
|
}
|
|
21410
22262
|
}
|
|
22263
|
+
case "update_mesh_node": {
|
|
22264
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22265
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22266
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22267
|
+
try {
|
|
22268
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22269
|
+
const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
|
|
22270
|
+
if (Array.isArray(args?.providerPriority)) {
|
|
22271
|
+
const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
|
|
22272
|
+
delete policy.provider_priority;
|
|
22273
|
+
if (providerPriority.length) {
|
|
22274
|
+
policy.providerPriority = providerPriority;
|
|
22275
|
+
} else {
|
|
22276
|
+
delete policy.providerPriority;
|
|
22277
|
+
}
|
|
22278
|
+
}
|
|
22279
|
+
const node = updateNode2(meshId, nodeId, { policy });
|
|
22280
|
+
if (!node) return { success: false, error: "Mesh node not found" };
|
|
22281
|
+
return { success: true, node };
|
|
22282
|
+
} catch (e) {
|
|
22283
|
+
return { success: false, error: e.message };
|
|
22284
|
+
}
|
|
22285
|
+
}
|
|
22286
|
+
case "cleanup_mesh_sessions": {
|
|
22287
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22288
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22289
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22290
|
+
try {
|
|
22291
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22292
|
+
const mesh = meshRecord?.mesh;
|
|
22293
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22294
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22295
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
22296
|
+
const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
|
|
22297
|
+
const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
|
|
22298
|
+
const result = await this.cleanupMeshSessions({
|
|
22299
|
+
meshId,
|
|
22300
|
+
nodeId,
|
|
22301
|
+
node,
|
|
22302
|
+
mode,
|
|
22303
|
+
sessionIds,
|
|
22304
|
+
dryRun: args?.dryRun === true
|
|
22305
|
+
});
|
|
22306
|
+
return result;
|
|
22307
|
+
} catch (e) {
|
|
22308
|
+
return { success: false, error: e.message };
|
|
22309
|
+
}
|
|
22310
|
+
}
|
|
21411
22311
|
case "remove_mesh_node": {
|
|
21412
22312
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21413
22313
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
21414
22314
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
21415
22315
|
try {
|
|
21416
|
-
const
|
|
21417
|
-
const
|
|
21418
|
-
|
|
22316
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22317
|
+
const mesh = meshRecord?.mesh;
|
|
22318
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22319
|
+
const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
|
|
22320
|
+
args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
|
|
22321
|
+
);
|
|
22322
|
+
let sessionCleanup;
|
|
22323
|
+
if (node && sessionCleanupMode !== "preserve") {
|
|
22324
|
+
sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
|
|
22325
|
+
if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
|
|
22326
|
+
}
|
|
22327
|
+
if (node?.isLocalWorktree && node.workspace) {
|
|
22328
|
+
try {
|
|
22329
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
22330
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
22331
|
+
if (repoRoot) {
|
|
22332
|
+
const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22333
|
+
await removeWorktree2(repoRoot, node.workspace);
|
|
22334
|
+
}
|
|
22335
|
+
} catch (e) {
|
|
22336
|
+
LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
|
|
22337
|
+
}
|
|
22338
|
+
}
|
|
22339
|
+
let removed = false;
|
|
22340
|
+
if (meshRecord?.inline) {
|
|
22341
|
+
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
22342
|
+
} else {
|
|
22343
|
+
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22344
|
+
removed = removeNode3(meshId, nodeId);
|
|
22345
|
+
}
|
|
22346
|
+
return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
|
|
22347
|
+
} catch (e) {
|
|
22348
|
+
return { success: false, error: e.message };
|
|
22349
|
+
}
|
|
22350
|
+
}
|
|
22351
|
+
case "clone_mesh_node": {
|
|
22352
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22353
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
22354
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
22355
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
22356
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22357
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
22358
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
22359
|
+
try {
|
|
22360
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22361
|
+
const mesh = meshRecord?.mesh;
|
|
22362
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22363
|
+
const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
|
|
22364
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
22365
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
22366
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22367
|
+
const result = await createWorktree2({
|
|
22368
|
+
repoRoot,
|
|
22369
|
+
branch,
|
|
22370
|
+
baseBranch,
|
|
22371
|
+
meshName: mesh.name
|
|
22372
|
+
});
|
|
22373
|
+
let node;
|
|
22374
|
+
if (meshRecord.inline) {
|
|
22375
|
+
const { randomUUID: randomUUID8 } = await import("crypto");
|
|
22376
|
+
node = {
|
|
22377
|
+
id: `node_${randomUUID8().replace(/-/g, "")}`,
|
|
22378
|
+
workspace: result.worktreePath,
|
|
22379
|
+
repoRoot: result.worktreePath,
|
|
22380
|
+
daemonId: sourceNode.daemonId,
|
|
22381
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22382
|
+
policy: { ...sourceNode.policy || {} },
|
|
22383
|
+
isLocalWorktree: true,
|
|
22384
|
+
worktreeBranch: result.branch,
|
|
22385
|
+
clonedFromNodeId: sourceNodeId
|
|
22386
|
+
};
|
|
22387
|
+
this.updateInlineMeshNode(meshId, mesh, node);
|
|
22388
|
+
} else {
|
|
22389
|
+
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22390
|
+
node = addNode3(meshId, {
|
|
22391
|
+
workspace: result.worktreePath,
|
|
22392
|
+
repoRoot: result.worktreePath,
|
|
22393
|
+
daemonId: sourceNode.daemonId,
|
|
22394
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22395
|
+
isLocalWorktree: true,
|
|
22396
|
+
worktreeBranch: result.branch,
|
|
22397
|
+
clonedFromNodeId: sourceNodeId,
|
|
22398
|
+
policy: { ...sourceNode.policy || {} }
|
|
22399
|
+
});
|
|
22400
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
22401
|
+
}
|
|
22402
|
+
return {
|
|
22403
|
+
success: true,
|
|
22404
|
+
node,
|
|
22405
|
+
worktreePath: result.worktreePath,
|
|
22406
|
+
branch: result.branch
|
|
22407
|
+
};
|
|
21419
22408
|
} catch (e) {
|
|
21420
22409
|
return { success: false, error: e.message };
|
|
21421
22410
|
}
|
|
@@ -21423,7 +22412,7 @@ var DaemonCommandRouter = class {
|
|
|
21423
22412
|
// ─── Mesh Coordinator Launch ───
|
|
21424
22413
|
case "launch_mesh_coordinator": {
|
|
21425
22414
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21426
|
-
|
|
22415
|
+
let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
|
|
21427
22416
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
21428
22417
|
try {
|
|
21429
22418
|
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
@@ -21451,9 +22440,29 @@ var DaemonCommandRouter = class {
|
|
|
21451
22440
|
}
|
|
21452
22441
|
const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
|
|
21453
22442
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
22443
|
+
if (!cliType) {
|
|
22444
|
+
const resolved = await resolveProviderTypeFromPriority({
|
|
22445
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
|
|
22446
|
+
providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
|
|
22447
|
+
providerLoader: this.deps.providerLoader,
|
|
22448
|
+
onStatusChange: this.deps.onStatusChange
|
|
22449
|
+
});
|
|
22450
|
+
if (!resolved.providerType) {
|
|
22451
|
+
return {
|
|
22452
|
+
success: false,
|
|
22453
|
+
code: "mesh_coordinator_provider_priority_unusable",
|
|
22454
|
+
error: resolved.error || "No usable provider found from node providerPriority",
|
|
22455
|
+
meshId,
|
|
22456
|
+
cliType,
|
|
22457
|
+
workspace
|
|
22458
|
+
};
|
|
22459
|
+
}
|
|
22460
|
+
cliType = resolved.providerType;
|
|
22461
|
+
}
|
|
21454
22462
|
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
21455
22463
|
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
21456
22464
|
provider: providerMeta,
|
|
22465
|
+
cliType,
|
|
21457
22466
|
meshId,
|
|
21458
22467
|
workspace
|
|
21459
22468
|
});
|
|
@@ -21478,7 +22487,8 @@ var DaemonCommandRouter = class {
|
|
|
21478
22487
|
meshCoordinatorSetup: coordinatorSetup
|
|
21479
22488
|
};
|
|
21480
22489
|
}
|
|
21481
|
-
|
|
22490
|
+
const configFormat = coordinatorSetup.configFormat;
|
|
22491
|
+
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
21482
22492
|
return {
|
|
21483
22493
|
success: false,
|
|
21484
22494
|
code: "mesh_coordinator_unsupported",
|
|
@@ -21488,17 +22498,34 @@ var DaemonCommandRouter = class {
|
|
|
21488
22498
|
workspace
|
|
21489
22499
|
};
|
|
21490
22500
|
}
|
|
21491
|
-
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
|
|
22501
|
+
let systemPrompt = "";
|
|
22502
|
+
try {
|
|
22503
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
22504
|
+
} catch (error) {
|
|
22505
|
+
const message = error?.message || String(error);
|
|
22506
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
22507
|
+
return {
|
|
22508
|
+
success: false,
|
|
22509
|
+
code: "mesh_coordinator_prompt_failed",
|
|
22510
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
22511
|
+
meshId,
|
|
22512
|
+
cliType,
|
|
22513
|
+
workspace
|
|
22514
|
+
};
|
|
21501
22515
|
}
|
|
22516
|
+
const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
|
|
22517
|
+
const { dirname: dirname9 } = await import("path");
|
|
22518
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
22519
|
+
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
22520
|
+
const returnManualFallback = (message) => ({
|
|
22521
|
+
success: false,
|
|
22522
|
+
code: "mesh_coordinator_manual_mcp_setup_required",
|
|
22523
|
+
error: message,
|
|
22524
|
+
meshId,
|
|
22525
|
+
cliType,
|
|
22526
|
+
workspace,
|
|
22527
|
+
meshCoordinatorSetup: hermesManualFallback
|
|
22528
|
+
});
|
|
21502
22529
|
const mcpServerEntry = {
|
|
21503
22530
|
command: coordinatorSetup.mcpServer.command,
|
|
21504
22531
|
args: coordinatorSetup.mcpServer.args
|
|
@@ -21509,24 +22536,55 @@ var DaemonCommandRouter = class {
|
|
|
21509
22536
|
ADHDEV_MCP_TRANSPORT: "ipc"
|
|
21510
22537
|
};
|
|
21511
22538
|
}
|
|
22539
|
+
try {
|
|
22540
|
+
mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
|
|
22541
|
+
} catch (error) {
|
|
22542
|
+
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
22543
|
+
LOG.error("MeshCoordinator", message);
|
|
22544
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22545
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
22546
|
+
}
|
|
22547
|
+
const hadExistingMcpConfig = existsSync23(mcpConfigPath);
|
|
22548
|
+
let existingMcpConfig = {};
|
|
22549
|
+
if (hadExistingMcpConfig) {
|
|
22550
|
+
try {
|
|
22551
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
|
|
22552
|
+
copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
|
|
22553
|
+
} catch (error) {
|
|
22554
|
+
LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
22555
|
+
return {
|
|
22556
|
+
success: false,
|
|
22557
|
+
code: "mesh_coordinator_config_parse_failed",
|
|
22558
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`
|
|
22559
|
+
};
|
|
22560
|
+
}
|
|
22561
|
+
}
|
|
22562
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
22563
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
21512
22564
|
const mcpConfig = {
|
|
21513
22565
|
...existingMcpConfig,
|
|
21514
|
-
|
|
21515
|
-
...
|
|
22566
|
+
[mcpServersKey]: {
|
|
22567
|
+
...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
|
|
21516
22568
|
[coordinatorSetup.serverName]: mcpServerEntry
|
|
21517
22569
|
}
|
|
21518
22570
|
};
|
|
21519
|
-
writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
21520
|
-
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21521
|
-
let systemPrompt = "";
|
|
21522
22571
|
try {
|
|
21523
|
-
|
|
21524
|
-
} catch {
|
|
21525
|
-
|
|
22572
|
+
writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
22573
|
+
} catch (error) {
|
|
22574
|
+
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
22575
|
+
LOG.error("MeshCoordinator", message);
|
|
22576
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22577
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21526
22578
|
}
|
|
22579
|
+
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21527
22580
|
const cliArgs = [];
|
|
22581
|
+
const launchEnv = {};
|
|
21528
22582
|
if (systemPrompt) {
|
|
21529
|
-
|
|
22583
|
+
if (configFormat === "hermes_config_yaml") {
|
|
22584
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
22585
|
+
} else {
|
|
22586
|
+
cliArgs.push("--append-system-prompt", systemPrompt);
|
|
22587
|
+
}
|
|
21530
22588
|
}
|
|
21531
22589
|
if (cliType === "claude-cli") {
|
|
21532
22590
|
cliArgs.push("--mcp-config", coordinatorSetup.configPath);
|
|
@@ -21535,6 +22593,7 @@ var DaemonCommandRouter = class {
|
|
|
21535
22593
|
cliType,
|
|
21536
22594
|
dir: workspace,
|
|
21537
22595
|
cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
|
|
22596
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
21538
22597
|
settings: {
|
|
21539
22598
|
meshCoordinatorFor: meshId
|
|
21540
22599
|
}
|
|
@@ -21714,6 +22773,12 @@ var DaemonStatusReporter = class {
|
|
|
21714
22773
|
if (providerType) {
|
|
21715
22774
|
payload.providerType = providerType;
|
|
21716
22775
|
}
|
|
22776
|
+
if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
|
|
22777
|
+
payload.providerSessionId = event.providerSessionId.trim();
|
|
22778
|
+
}
|
|
22779
|
+
if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
|
|
22780
|
+
payload.workspaceName = event.workspaceName.trim();
|
|
22781
|
+
}
|
|
21717
22782
|
if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
|
|
21718
22783
|
payload.duration = event.duration;
|
|
21719
22784
|
}
|
|
@@ -22961,7 +24026,10 @@ var ProviderInstanceManager = class {
|
|
|
22961
24026
|
this.instances.get(id).dispose();
|
|
22962
24027
|
}
|
|
22963
24028
|
this.instances.set(id, instance);
|
|
22964
|
-
await instance.init(
|
|
24029
|
+
await instance.init({
|
|
24030
|
+
...context,
|
|
24031
|
+
emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
|
|
24032
|
+
});
|
|
22965
24033
|
}
|
|
22966
24034
|
/**
|
|
22967
24035
|
* Instance remove
|
|
@@ -23123,6 +24191,17 @@ var ProviderInstanceManager = class {
|
|
|
23123
24191
|
onEvent(listener) {
|
|
23124
24192
|
this.eventListeners.push(listener);
|
|
23125
24193
|
}
|
|
24194
|
+
emitProviderEvent(providerType, instanceId, event) {
|
|
24195
|
+
const payload = {
|
|
24196
|
+
...event,
|
|
24197
|
+
providerType,
|
|
24198
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
|
|
24199
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
|
|
24200
|
+
};
|
|
24201
|
+
for (const listener of this.eventListeners) {
|
|
24202
|
+
listener(payload);
|
|
24203
|
+
}
|
|
24204
|
+
}
|
|
23126
24205
|
emitPendingEvents(providerType, state, extra = {}) {
|
|
23127
24206
|
for (const event of state.pendingEvents) {
|
|
23128
24207
|
for (const listener of this.eventListeners) {
|
|
@@ -23195,11 +24274,11 @@ var ProviderInstanceManager = class {
|
|
|
23195
24274
|
|
|
23196
24275
|
// src/providers/version-archive.ts
|
|
23197
24276
|
import * as fs11 from "fs";
|
|
23198
|
-
import * as
|
|
23199
|
-
import * as
|
|
24277
|
+
import * as path22 from "path";
|
|
24278
|
+
import * as os20 from "os";
|
|
23200
24279
|
import { execSync as execSync5 } from "child_process";
|
|
23201
24280
|
import { platform as platform8 } from "os";
|
|
23202
|
-
var ARCHIVE_PATH =
|
|
24281
|
+
var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
|
|
23203
24282
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
23204
24283
|
var VersionArchive = class {
|
|
23205
24284
|
history = {};
|
|
@@ -23246,7 +24325,7 @@ var VersionArchive = class {
|
|
|
23246
24325
|
}
|
|
23247
24326
|
save() {
|
|
23248
24327
|
try {
|
|
23249
|
-
fs11.mkdirSync(
|
|
24328
|
+
fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
|
|
23250
24329
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
23251
24330
|
} catch {
|
|
23252
24331
|
}
|
|
@@ -23302,8 +24381,8 @@ function getVersion(binary, versionCommand) {
|
|
|
23302
24381
|
function checkPathExists2(paths) {
|
|
23303
24382
|
for (const p of paths) {
|
|
23304
24383
|
if (p.includes("*")) {
|
|
23305
|
-
const home =
|
|
23306
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
24384
|
+
const home = os20.homedir();
|
|
24385
|
+
const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
|
|
23307
24386
|
if (fs11.existsSync(resolved)) return resolved;
|
|
23308
24387
|
} else {
|
|
23309
24388
|
if (fs11.existsSync(p)) return p;
|
|
@@ -23313,7 +24392,7 @@ function checkPathExists2(paths) {
|
|
|
23313
24392
|
}
|
|
23314
24393
|
function getMacAppVersion(appPath) {
|
|
23315
24394
|
if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
23316
|
-
const plistPath =
|
|
24395
|
+
const plistPath = path22.join(appPath, "Contents", "Info.plist");
|
|
23317
24396
|
if (!fs11.existsSync(plistPath)) return null;
|
|
23318
24397
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
23319
24398
|
return raw || null;
|
|
@@ -23339,7 +24418,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23339
24418
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
23340
24419
|
let resolvedBin = cliBin;
|
|
23341
24420
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
23342
|
-
const bundled =
|
|
24421
|
+
const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
23343
24422
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
23344
24423
|
}
|
|
23345
24424
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -23380,7 +24459,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23380
24459
|
// src/daemon/dev-server.ts
|
|
23381
24460
|
import * as http2 from "http";
|
|
23382
24461
|
import * as fs15 from "fs";
|
|
23383
|
-
import * as
|
|
24462
|
+
import * as path26 from "path";
|
|
23384
24463
|
init_config();
|
|
23385
24464
|
|
|
23386
24465
|
// src/daemon/scaffold-template.ts
|
|
@@ -23732,7 +24811,7 @@ init_logger();
|
|
|
23732
24811
|
// src/daemon/dev-cdp-handlers.ts
|
|
23733
24812
|
init_logger();
|
|
23734
24813
|
import * as fs12 from "fs";
|
|
23735
|
-
import * as
|
|
24814
|
+
import * as path23 from "path";
|
|
23736
24815
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
23737
24816
|
const body = await ctx.readBody(req);
|
|
23738
24817
|
const { expression, timeout, ideType } = body;
|
|
@@ -23910,17 +24989,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
23910
24989
|
return;
|
|
23911
24990
|
}
|
|
23912
24991
|
let scriptsPath = "";
|
|
23913
|
-
const directScripts =
|
|
24992
|
+
const directScripts = path23.join(dir, "scripts.js");
|
|
23914
24993
|
if (fs12.existsSync(directScripts)) {
|
|
23915
24994
|
scriptsPath = directScripts;
|
|
23916
24995
|
} else {
|
|
23917
|
-
const scriptsDir =
|
|
24996
|
+
const scriptsDir = path23.join(dir, "scripts");
|
|
23918
24997
|
if (fs12.existsSync(scriptsDir)) {
|
|
23919
24998
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
23920
|
-
return fs12.statSync(
|
|
24999
|
+
return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
|
|
23921
25000
|
}).sort().reverse();
|
|
23922
25001
|
for (const ver of versions) {
|
|
23923
|
-
const p =
|
|
25002
|
+
const p = path23.join(scriptsDir, ver, "scripts.js");
|
|
23924
25003
|
if (fs12.existsSync(p)) {
|
|
23925
25004
|
scriptsPath = p;
|
|
23926
25005
|
break;
|
|
@@ -24749,7 +25828,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
24749
25828
|
|
|
24750
25829
|
// src/daemon/dev-cli-debug.ts
|
|
24751
25830
|
import * as fs13 from "fs";
|
|
24752
|
-
import * as
|
|
25831
|
+
import * as path24 from "path";
|
|
24753
25832
|
function slugifyFixtureName(value) {
|
|
24754
25833
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24755
25834
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -24759,11 +25838,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
24759
25838
|
if (!providerDir) {
|
|
24760
25839
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
24761
25840
|
}
|
|
24762
|
-
return
|
|
25841
|
+
return path24.join(providerDir, "fixtures");
|
|
24763
25842
|
}
|
|
24764
25843
|
function readCliFixture(ctx, type, name) {
|
|
24765
25844
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
24766
|
-
const filePath =
|
|
25845
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
24767
25846
|
if (!fs13.existsSync(filePath)) {
|
|
24768
25847
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
24769
25848
|
}
|
|
@@ -24931,7 +26010,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
|
|
|
24931
26010
|
if (!adapter) return null;
|
|
24932
26011
|
return { target, instance, adapter };
|
|
24933
26012
|
}
|
|
24934
|
-
function
|
|
26013
|
+
function sleep2(ms) {
|
|
24935
26014
|
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
24936
26015
|
}
|
|
24937
26016
|
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
@@ -24948,7 +26027,7 @@ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
|
24948
26027
|
return bundle;
|
|
24949
26028
|
}
|
|
24950
26029
|
}
|
|
24951
|
-
await
|
|
26030
|
+
await sleep2(100);
|
|
24952
26031
|
}
|
|
24953
26032
|
return getCliTargetBundle(ctx, type, instanceId);
|
|
24954
26033
|
}
|
|
@@ -25004,7 +26083,7 @@ async function runCliExerciseInternal(ctx, body) {
|
|
|
25004
26083
|
const message = String(lastLaunchError.message || "");
|
|
25005
26084
|
const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
|
|
25006
26085
|
if (!retryable || attempt === 2) break;
|
|
25007
|
-
await
|
|
26086
|
+
await sleep2(1e3);
|
|
25008
26087
|
}
|
|
25009
26088
|
}
|
|
25010
26089
|
if (!launched) {
|
|
@@ -25067,16 +26146,16 @@ async function runCliExerciseInternal(ctx, body) {
|
|
|
25067
26146
|
const modal = debug?.activeModal || trace?.activeModal || null;
|
|
25068
26147
|
noteStatus(status);
|
|
25069
26148
|
if (resolveActiveModalIfNeeded(status, modal)) {
|
|
25070
|
-
await
|
|
26149
|
+
await sleep2(150);
|
|
25071
26150
|
continue;
|
|
25072
26151
|
}
|
|
25073
26152
|
const startupParseGate = !!debug?.startupParseGate;
|
|
25074
26153
|
if (status === "idle" && !startupParseGate) break;
|
|
25075
|
-
await
|
|
26154
|
+
await sleep2(150);
|
|
25076
26155
|
}
|
|
25077
26156
|
ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
|
|
25078
26157
|
while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
|
|
25079
|
-
await
|
|
26158
|
+
await sleep2(150);
|
|
25080
26159
|
bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
|
|
25081
26160
|
if (!bundle) {
|
|
25082
26161
|
throw new Error("CLI instance disappeared during exercise");
|
|
@@ -25530,7 +26609,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
25530
26609
|
},
|
|
25531
26610
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
25532
26611
|
};
|
|
25533
|
-
const filePath =
|
|
26612
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
25534
26613
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
25535
26614
|
ctx.json(res, 200, {
|
|
25536
26615
|
saved: true,
|
|
@@ -25554,7 +26633,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
25554
26633
|
return;
|
|
25555
26634
|
}
|
|
25556
26635
|
const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
25557
|
-
const fullPath =
|
|
26636
|
+
const fullPath = path24.join(fixtureDir, file);
|
|
25558
26637
|
try {
|
|
25559
26638
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
25560
26639
|
return {
|
|
@@ -25690,8 +26769,8 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
25690
26769
|
|
|
25691
26770
|
// src/daemon/dev-auto-implement.ts
|
|
25692
26771
|
import * as fs14 from "fs";
|
|
25693
|
-
import * as
|
|
25694
|
-
import * as
|
|
26772
|
+
import * as path25 from "path";
|
|
26773
|
+
import * as os21 from "os";
|
|
25695
26774
|
function getAutoImplPid(ctx) {
|
|
25696
26775
|
const pid = ctx.autoImplProcess?.pid;
|
|
25697
26776
|
return typeof pid === "number" && pid > 0 ? pid : null;
|
|
@@ -25740,22 +26819,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
25740
26819
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
25741
26820
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
25742
26821
|
try {
|
|
25743
|
-
return fs14.statSync(
|
|
26822
|
+
return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
25744
26823
|
} catch {
|
|
25745
26824
|
return false;
|
|
25746
26825
|
}
|
|
25747
26826
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
25748
26827
|
if (versions.length === 0) return null;
|
|
25749
|
-
return
|
|
26828
|
+
return path25.join(scriptsDir, versions[0]);
|
|
25750
26829
|
}
|
|
25751
26830
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
25752
|
-
const canonicalUserDir =
|
|
25753
|
-
const desiredDir = requestedDir ?
|
|
25754
|
-
const upstreamRoot =
|
|
25755
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
26831
|
+
const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
26832
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
26833
|
+
const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
|
|
26834
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
25756
26835
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
25757
26836
|
}
|
|
25758
|
-
if (
|
|
26837
|
+
if (path25.basename(desiredDir) !== type) {
|
|
25759
26838
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
25760
26839
|
}
|
|
25761
26840
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -25763,11 +26842,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
25763
26842
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
25764
26843
|
}
|
|
25765
26844
|
if (!fs14.existsSync(desiredDir)) {
|
|
25766
|
-
fs14.mkdirSync(
|
|
26845
|
+
fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
25767
26846
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
25768
26847
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
25769
26848
|
}
|
|
25770
|
-
const providerJson =
|
|
26849
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
25771
26850
|
if (!fs14.existsSync(providerJson)) {
|
|
25772
26851
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
25773
26852
|
}
|
|
@@ -25778,13 +26857,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
25778
26857
|
const refDir = ctx.findProviderDir(referenceType);
|
|
25779
26858
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
25780
26859
|
const referenceScripts = {};
|
|
25781
|
-
const scriptsDir =
|
|
26860
|
+
const scriptsDir = path25.join(refDir, "scripts");
|
|
25782
26861
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
25783
26862
|
if (!latestDir) return referenceScripts;
|
|
25784
26863
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
25785
26864
|
if (!file.endsWith(".js")) continue;
|
|
25786
26865
|
try {
|
|
25787
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
26866
|
+
referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
|
|
25788
26867
|
} catch {
|
|
25789
26868
|
}
|
|
25790
26869
|
}
|
|
@@ -25892,9 +26971,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
25892
26971
|
});
|
|
25893
26972
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
25894
26973
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
25895
|
-
const tmpDir =
|
|
26974
|
+
const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
|
|
25896
26975
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
25897
|
-
const promptFile =
|
|
26976
|
+
const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
25898
26977
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
25899
26978
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
25900
26979
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -26047,7 +27126,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26047
27126
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
26048
27127
|
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
26049
27128
|
let shellCmd;
|
|
26050
|
-
const isWin =
|
|
27129
|
+
const isWin = os21.platform() === "win32";
|
|
26051
27130
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
26052
27131
|
const promptMode = autoImpl?.promptMode ?? "stdin";
|
|
26053
27132
|
const extraArgs = autoImpl?.extraArgs ?? [];
|
|
@@ -26086,7 +27165,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26086
27165
|
try {
|
|
26087
27166
|
const pty = __require("node-pty");
|
|
26088
27167
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
26089
|
-
const isWin2 =
|
|
27168
|
+
const isWin2 = os21.platform() === "win32";
|
|
26090
27169
|
child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
26091
27170
|
name: "xterm-256color",
|
|
26092
27171
|
cols: 120,
|
|
@@ -26326,7 +27405,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26326
27405
|
setMode: "set_mode.js"
|
|
26327
27406
|
};
|
|
26328
27407
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26329
|
-
const scriptsDir =
|
|
27408
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26330
27409
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26331
27410
|
if (latestScriptsDir) {
|
|
26332
27411
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26337,7 +27416,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26337
27416
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
26338
27417
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26339
27418
|
try {
|
|
26340
|
-
const content = fs14.readFileSync(
|
|
27419
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26341
27420
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26342
27421
|
lines.push("```javascript");
|
|
26343
27422
|
lines.push(content);
|
|
@@ -26354,7 +27433,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26354
27433
|
lines.push("");
|
|
26355
27434
|
for (const file of refFiles) {
|
|
26356
27435
|
try {
|
|
26357
|
-
const content = fs14.readFileSync(
|
|
27436
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26358
27437
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26359
27438
|
lines.push("```javascript");
|
|
26360
27439
|
lines.push(content);
|
|
@@ -26395,10 +27474,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26395
27474
|
lines.push("");
|
|
26396
27475
|
}
|
|
26397
27476
|
}
|
|
26398
|
-
const docsDir =
|
|
27477
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26399
27478
|
const loadGuide = (name) => {
|
|
26400
27479
|
try {
|
|
26401
|
-
const p =
|
|
27480
|
+
const p = path25.join(docsDir, name);
|
|
26402
27481
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26403
27482
|
} catch {
|
|
26404
27483
|
}
|
|
@@ -26635,7 +27714,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26635
27714
|
parseApproval: "parse_approval.js"
|
|
26636
27715
|
};
|
|
26637
27716
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26638
|
-
const scriptsDir =
|
|
27717
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26639
27718
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26640
27719
|
if (latestScriptsDir) {
|
|
26641
27720
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26647,7 +27726,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26647
27726
|
if (!file.endsWith(".js")) continue;
|
|
26648
27727
|
if (!targetFileNames.has(file)) continue;
|
|
26649
27728
|
try {
|
|
26650
|
-
const content = fs14.readFileSync(
|
|
27729
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26651
27730
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26652
27731
|
lines.push("```javascript");
|
|
26653
27732
|
lines.push(content);
|
|
@@ -26663,7 +27742,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26663
27742
|
lines.push("");
|
|
26664
27743
|
for (const file of refFiles) {
|
|
26665
27744
|
try {
|
|
26666
|
-
const content = fs14.readFileSync(
|
|
27745
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26667
27746
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26668
27747
|
lines.push("```javascript");
|
|
26669
27748
|
lines.push(content);
|
|
@@ -26696,10 +27775,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26696
27775
|
lines.push("");
|
|
26697
27776
|
}
|
|
26698
27777
|
}
|
|
26699
|
-
const docsDir =
|
|
27778
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26700
27779
|
const loadGuide = (name) => {
|
|
26701
27780
|
try {
|
|
26702
|
-
const p =
|
|
27781
|
+
const p = path25.join(docsDir, name);
|
|
26703
27782
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26704
27783
|
} catch {
|
|
26705
27784
|
}
|
|
@@ -27146,8 +28225,8 @@ var DevServer = class _DevServer {
|
|
|
27146
28225
|
}
|
|
27147
28226
|
getEndpointList() {
|
|
27148
28227
|
return this.routes.map((r) => {
|
|
27149
|
-
const
|
|
27150
|
-
return `${r.method.padEnd(5)} ${
|
|
28228
|
+
const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
28229
|
+
return `${r.method.padEnd(5)} ${path27}`;
|
|
27151
28230
|
});
|
|
27152
28231
|
}
|
|
27153
28232
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -27435,12 +28514,12 @@ var DevServer = class _DevServer {
|
|
|
27435
28514
|
// ─── DevConsole SPA ───
|
|
27436
28515
|
getConsoleDistDir() {
|
|
27437
28516
|
const candidates = [
|
|
27438
|
-
|
|
27439
|
-
|
|
27440
|
-
|
|
28517
|
+
path26.resolve(__dirname, "../../web-devconsole/dist"),
|
|
28518
|
+
path26.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
28519
|
+
path26.join(process.cwd(), "packages/web-devconsole/dist")
|
|
27441
28520
|
];
|
|
27442
28521
|
for (const dir of candidates) {
|
|
27443
|
-
if (fs15.existsSync(
|
|
28522
|
+
if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
|
|
27444
28523
|
}
|
|
27445
28524
|
return null;
|
|
27446
28525
|
}
|
|
@@ -27450,7 +28529,7 @@ var DevServer = class _DevServer {
|
|
|
27450
28529
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
27451
28530
|
return;
|
|
27452
28531
|
}
|
|
27453
|
-
const htmlPath =
|
|
28532
|
+
const htmlPath = path26.join(distDir, "index.html");
|
|
27454
28533
|
try {
|
|
27455
28534
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
27456
28535
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -27475,15 +28554,15 @@ var DevServer = class _DevServer {
|
|
|
27475
28554
|
this.json(res, 404, { error: "Not found" });
|
|
27476
28555
|
return;
|
|
27477
28556
|
}
|
|
27478
|
-
const safePath =
|
|
27479
|
-
const filePath =
|
|
28557
|
+
const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
|
|
28558
|
+
const filePath = path26.join(distDir, safePath);
|
|
27480
28559
|
if (!filePath.startsWith(distDir)) {
|
|
27481
28560
|
this.json(res, 403, { error: "Forbidden" });
|
|
27482
28561
|
return;
|
|
27483
28562
|
}
|
|
27484
28563
|
try {
|
|
27485
28564
|
const content = fs15.readFileSync(filePath);
|
|
27486
|
-
const ext =
|
|
28565
|
+
const ext = path26.extname(filePath);
|
|
27487
28566
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
27488
28567
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
27489
28568
|
res.end(content);
|
|
@@ -27596,9 +28675,9 @@ var DevServer = class _DevServer {
|
|
|
27596
28675
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27597
28676
|
if (entry.isDirectory()) {
|
|
27598
28677
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
27599
|
-
scan(
|
|
28678
|
+
scan(path26.join(d, entry.name), rel);
|
|
27600
28679
|
} else {
|
|
27601
|
-
const stat2 = fs15.statSync(
|
|
28680
|
+
const stat2 = fs15.statSync(path26.join(d, entry.name));
|
|
27602
28681
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
27603
28682
|
}
|
|
27604
28683
|
}
|
|
@@ -27621,7 +28700,7 @@ var DevServer = class _DevServer {
|
|
|
27621
28700
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27622
28701
|
return;
|
|
27623
28702
|
}
|
|
27624
|
-
const fullPath =
|
|
28703
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27625
28704
|
if (!fullPath.startsWith(dir)) {
|
|
27626
28705
|
this.json(res, 403, { error: "Forbidden" });
|
|
27627
28706
|
return;
|
|
@@ -27646,14 +28725,14 @@ var DevServer = class _DevServer {
|
|
|
27646
28725
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27647
28726
|
return;
|
|
27648
28727
|
}
|
|
27649
|
-
const fullPath =
|
|
28728
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27650
28729
|
if (!fullPath.startsWith(dir)) {
|
|
27651
28730
|
this.json(res, 403, { error: "Forbidden" });
|
|
27652
28731
|
return;
|
|
27653
28732
|
}
|
|
27654
28733
|
try {
|
|
27655
28734
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
27656
|
-
fs15.mkdirSync(
|
|
28735
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27657
28736
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27658
28737
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
27659
28738
|
this.providerLoader.reload();
|
|
@@ -27670,7 +28749,7 @@ var DevServer = class _DevServer {
|
|
|
27670
28749
|
return;
|
|
27671
28750
|
}
|
|
27672
28751
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
27673
|
-
const p =
|
|
28752
|
+
const p = path26.join(dir, name);
|
|
27674
28753
|
if (fs15.existsSync(p)) {
|
|
27675
28754
|
const source = fs15.readFileSync(p, "utf-8");
|
|
27676
28755
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -27691,8 +28770,8 @@ var DevServer = class _DevServer {
|
|
|
27691
28770
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
27692
28771
|
return;
|
|
27693
28772
|
}
|
|
27694
|
-
const target = fs15.existsSync(
|
|
27695
|
-
const targetPath =
|
|
28773
|
+
const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
28774
|
+
const targetPath = path26.join(dir, target);
|
|
27696
28775
|
try {
|
|
27697
28776
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
27698
28777
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -27839,7 +28918,7 @@ var DevServer = class _DevServer {
|
|
|
27839
28918
|
}
|
|
27840
28919
|
let targetDir;
|
|
27841
28920
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
27842
|
-
const jsonPath =
|
|
28921
|
+
const jsonPath = path26.join(targetDir, "provider.json");
|
|
27843
28922
|
if (fs15.existsSync(jsonPath)) {
|
|
27844
28923
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
27845
28924
|
return;
|
|
@@ -27851,8 +28930,8 @@ var DevServer = class _DevServer {
|
|
|
27851
28930
|
const createdFiles = ["provider.json"];
|
|
27852
28931
|
if (result.files) {
|
|
27853
28932
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
27854
|
-
const fullPath =
|
|
27855
|
-
fs15.mkdirSync(
|
|
28933
|
+
const fullPath = path26.join(targetDir, relPath);
|
|
28934
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27856
28935
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27857
28936
|
createdFiles.push(relPath);
|
|
27858
28937
|
}
|
|
@@ -27905,22 +28984,22 @@ var DevServer = class _DevServer {
|
|
|
27905
28984
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
27906
28985
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
27907
28986
|
try {
|
|
27908
|
-
return fs15.statSync(
|
|
28987
|
+
return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
|
|
27909
28988
|
} catch {
|
|
27910
28989
|
return false;
|
|
27911
28990
|
}
|
|
27912
28991
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
27913
28992
|
if (versions.length === 0) return null;
|
|
27914
|
-
return
|
|
28993
|
+
return path26.join(scriptsDir, versions[0]);
|
|
27915
28994
|
}
|
|
27916
28995
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
27917
|
-
const canonicalUserDir =
|
|
27918
|
-
const desiredDir = requestedDir ?
|
|
27919
|
-
const upstreamRoot =
|
|
27920
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
28996
|
+
const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
28997
|
+
const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
|
|
28998
|
+
const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
|
|
28999
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
|
|
27921
29000
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
27922
29001
|
}
|
|
27923
|
-
if (
|
|
29002
|
+
if (path26.basename(desiredDir) !== type) {
|
|
27924
29003
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
27925
29004
|
}
|
|
27926
29005
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -27928,11 +29007,11 @@ var DevServer = class _DevServer {
|
|
|
27928
29007
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
27929
29008
|
}
|
|
27930
29009
|
if (!fs15.existsSync(desiredDir)) {
|
|
27931
|
-
fs15.mkdirSync(
|
|
29010
|
+
fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
|
|
27932
29011
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
27933
29012
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
27934
29013
|
}
|
|
27935
|
-
const providerJson =
|
|
29014
|
+
const providerJson = path26.join(desiredDir, "provider.json");
|
|
27936
29015
|
if (!fs15.existsSync(providerJson)) {
|
|
27937
29016
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
27938
29017
|
}
|
|
@@ -27968,7 +29047,7 @@ var DevServer = class _DevServer {
|
|
|
27968
29047
|
setMode: "set_mode.js"
|
|
27969
29048
|
};
|
|
27970
29049
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
27971
|
-
const scriptsDir =
|
|
29050
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
27972
29051
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
27973
29052
|
if (latestScriptsDir) {
|
|
27974
29053
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -27979,7 +29058,7 @@ var DevServer = class _DevServer {
|
|
|
27979
29058
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
27980
29059
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
27981
29060
|
try {
|
|
27982
|
-
const content = fs15.readFileSync(
|
|
29061
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
27983
29062
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
27984
29063
|
lines.push("```javascript");
|
|
27985
29064
|
lines.push(content);
|
|
@@ -27996,7 +29075,7 @@ var DevServer = class _DevServer {
|
|
|
27996
29075
|
lines.push("");
|
|
27997
29076
|
for (const file of refFiles) {
|
|
27998
29077
|
try {
|
|
27999
|
-
const content = fs15.readFileSync(
|
|
29078
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28000
29079
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28001
29080
|
lines.push("```javascript");
|
|
28002
29081
|
lines.push(content);
|
|
@@ -28037,10 +29116,10 @@ var DevServer = class _DevServer {
|
|
|
28037
29116
|
lines.push("");
|
|
28038
29117
|
}
|
|
28039
29118
|
}
|
|
28040
|
-
const docsDir =
|
|
29119
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28041
29120
|
const loadGuide = (name) => {
|
|
28042
29121
|
try {
|
|
28043
|
-
const p =
|
|
29122
|
+
const p = path26.join(docsDir, name);
|
|
28044
29123
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28045
29124
|
} catch {
|
|
28046
29125
|
}
|
|
@@ -28214,7 +29293,7 @@ var DevServer = class _DevServer {
|
|
|
28214
29293
|
parseApproval: "parse_approval.js"
|
|
28215
29294
|
};
|
|
28216
29295
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28217
|
-
const scriptsDir =
|
|
29296
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28218
29297
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28219
29298
|
if (latestScriptsDir) {
|
|
28220
29299
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28226,7 +29305,7 @@ var DevServer = class _DevServer {
|
|
|
28226
29305
|
if (!file.endsWith(".js")) continue;
|
|
28227
29306
|
if (!targetFileNames.has(file)) continue;
|
|
28228
29307
|
try {
|
|
28229
|
-
const content = fs15.readFileSync(
|
|
29308
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28230
29309
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28231
29310
|
lines.push("```javascript");
|
|
28232
29311
|
lines.push(content);
|
|
@@ -28242,7 +29321,7 @@ var DevServer = class _DevServer {
|
|
|
28242
29321
|
lines.push("");
|
|
28243
29322
|
for (const file of refFiles) {
|
|
28244
29323
|
try {
|
|
28245
|
-
const content = fs15.readFileSync(
|
|
29324
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28246
29325
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28247
29326
|
lines.push("```javascript");
|
|
28248
29327
|
lines.push(content);
|
|
@@ -28275,10 +29354,10 @@ var DevServer = class _DevServer {
|
|
|
28275
29354
|
lines.push("");
|
|
28276
29355
|
}
|
|
28277
29356
|
}
|
|
28278
|
-
const docsDir =
|
|
29357
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28279
29358
|
const loadGuide = (name) => {
|
|
28280
29359
|
try {
|
|
28281
|
-
const p =
|
|
29360
|
+
const p = path26.join(docsDir, name);
|
|
28282
29361
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28283
29362
|
} catch {
|
|
28284
29363
|
}
|
|
@@ -28969,29 +30048,58 @@ import {
|
|
|
28969
30048
|
} from "@adhdev/session-host-core";
|
|
28970
30049
|
var STARTUP_TIMEOUT_MS = DEFAULT_SESSION_HOST_READY_TIMEOUT_MS;
|
|
28971
30050
|
var STARTUP_POLL_MS = 200;
|
|
28972
|
-
|
|
30051
|
+
var SessionHostCompatibilityError = class extends Error {
|
|
30052
|
+
constructor(message) {
|
|
30053
|
+
super(message);
|
|
30054
|
+
this.name = "SessionHostCompatibilityError";
|
|
30055
|
+
}
|
|
30056
|
+
};
|
|
30057
|
+
function getMissingRequestTypes(diagnostics, requiredRequestTypes) {
|
|
30058
|
+
const supported = new Set(diagnostics?.supportedRequestTypes || []);
|
|
30059
|
+
return requiredRequestTypes.filter((requestType) => !supported.has(requestType));
|
|
30060
|
+
}
|
|
30061
|
+
async function assertRequiredRequestTypes(client, requiredRequestTypes) {
|
|
30062
|
+
if (requiredRequestTypes.length === 0) return;
|
|
30063
|
+
const response = await client.request({
|
|
30064
|
+
type: "get_host_diagnostics",
|
|
30065
|
+
payload: { includeSessions: false }
|
|
30066
|
+
});
|
|
30067
|
+
const missing = getMissingRequestTypes(response.success ? response.result : void 0, requiredRequestTypes);
|
|
30068
|
+
if (missing.length > 0) {
|
|
30069
|
+
const detail = response.success ? "" : ` (${response.error || "capability probe failed"})`;
|
|
30070
|
+
throw new SessionHostCompatibilityError(
|
|
30071
|
+
`Session host does not support required request types: ${missing.join(", ")}${detail}`
|
|
30072
|
+
);
|
|
30073
|
+
}
|
|
30074
|
+
}
|
|
30075
|
+
async function canConnect(endpoint, requiredRequestTypes = []) {
|
|
28973
30076
|
const client = new SessionHostClient2({ endpoint });
|
|
28974
30077
|
try {
|
|
28975
30078
|
await client.connect();
|
|
28976
|
-
await client
|
|
30079
|
+
await assertRequiredRequestTypes(client, requiredRequestTypes);
|
|
28977
30080
|
return true;
|
|
28978
|
-
} catch {
|
|
30081
|
+
} catch (error) {
|
|
30082
|
+
if (error instanceof SessionHostCompatibilityError) throw error;
|
|
28979
30083
|
return false;
|
|
30084
|
+
} finally {
|
|
30085
|
+
await client.close().catch(() => {
|
|
30086
|
+
});
|
|
28980
30087
|
}
|
|
28981
30088
|
}
|
|
28982
|
-
async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
|
|
30089
|
+
async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS, requiredRequestTypes = []) {
|
|
28983
30090
|
const deadline = Date.now() + timeoutMs;
|
|
28984
30091
|
while (Date.now() < deadline) {
|
|
28985
|
-
if (await canConnect(endpoint)) return;
|
|
30092
|
+
if (await canConnect(endpoint, requiredRequestTypes)) return;
|
|
28986
30093
|
await new Promise((resolve16) => setTimeout(resolve16, STARTUP_POLL_MS));
|
|
28987
30094
|
}
|
|
28988
30095
|
throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
|
|
28989
30096
|
}
|
|
28990
30097
|
async function ensureSessionHostReady(options) {
|
|
28991
30098
|
const endpoint = getDefaultSessionHostEndpoint(options.appName || "adhdev");
|
|
28992
|
-
|
|
30099
|
+
const requiredRequestTypes = options.requiredRequestTypes || [];
|
|
30100
|
+
if (await canConnect(endpoint, requiredRequestTypes)) return endpoint;
|
|
28993
30101
|
options.spawnHost();
|
|
28994
|
-
await waitForReady(endpoint, options.timeoutMs);
|
|
30102
|
+
await waitForReady(endpoint, options.timeoutMs, requiredRequestTypes);
|
|
28995
30103
|
return endpoint;
|
|
28996
30104
|
}
|
|
28997
30105
|
async function listHostedCliRuntimes(endpoint) {
|
|
@@ -29283,48 +30391,6 @@ var SessionRegistry = class {
|
|
|
29283
30391
|
// src/boot/daemon-lifecycle.ts
|
|
29284
30392
|
init_logger();
|
|
29285
30393
|
init_config();
|
|
29286
|
-
|
|
29287
|
-
// src/mesh/mesh-events.ts
|
|
29288
|
-
init_mesh_config();
|
|
29289
|
-
init_logger();
|
|
29290
|
-
function setupMeshEventForwarding(components) {
|
|
29291
|
-
components.instanceManager.onEvent((event) => {
|
|
29292
|
-
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
29293
|
-
const instanceId = event.instanceId;
|
|
29294
|
-
if (!instanceId) return;
|
|
29295
|
-
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
29296
|
-
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
29297
|
-
const state = sourceInstance.getState();
|
|
29298
|
-
const workspace = state.workspace;
|
|
29299
|
-
if (!workspace) return;
|
|
29300
|
-
const mesh = getMeshByRepo(workspace);
|
|
29301
|
-
if (!mesh) return;
|
|
29302
|
-
const allInstances = components.instanceManager.getByCategory("cli");
|
|
29303
|
-
const coordinatorInstances = allInstances.filter((inst) => {
|
|
29304
|
-
const instState = inst.getState();
|
|
29305
|
-
if (instState.settings?.meshCoordinatorFor !== mesh.id) return false;
|
|
29306
|
-
if (instState.instanceId === instanceId) return false;
|
|
29307
|
-
return true;
|
|
29308
|
-
});
|
|
29309
|
-
if (coordinatorInstances.length === 0) return;
|
|
29310
|
-
const targetNode = mesh.nodes.find((n) => n.workspace === workspace);
|
|
29311
|
-
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : `Agent at ${workspace}`;
|
|
29312
|
-
let messageText = "";
|
|
29313
|
-
if (event.event === "agent:generating_completed") {
|
|
29314
|
-
messageText = `[System] ${nodeLabel} has completed its task and is now idle. You may use mesh_read_chat to review its progress.`;
|
|
29315
|
-
} else if (event.event === "agent:waiting_approval") {
|
|
29316
|
-
messageText = `[System] ${nodeLabel} is waiting for approval to proceed. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
29317
|
-
}
|
|
29318
|
-
if (!messageText) return;
|
|
29319
|
-
for (const coord of coordinatorInstances) {
|
|
29320
|
-
const coordState = coord.getState();
|
|
29321
|
-
LOG.info("MeshEvents", `Forwarding event from ${workspace} to coordinator ${coordState.instanceId}`);
|
|
29322
|
-
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
29323
|
-
}
|
|
29324
|
-
});
|
|
29325
|
-
}
|
|
29326
|
-
|
|
29327
|
-
// src/boot/daemon-lifecycle.ts
|
|
29328
30394
|
async function initDaemonComponents(config) {
|
|
29329
30395
|
installGlobalInterceptor();
|
|
29330
30396
|
const appConfig = loadConfig();
|
|
@@ -29630,12 +30696,14 @@ export {
|
|
|
29630
30696
|
createGitWorkspaceMonitor,
|
|
29631
30697
|
createInteractionId,
|
|
29632
30698
|
createMesh,
|
|
30699
|
+
createWorktree,
|
|
29633
30700
|
deleteMesh,
|
|
29634
30701
|
detectAllVersions,
|
|
29635
30702
|
detectCLIs,
|
|
29636
30703
|
detectIDEs,
|
|
29637
30704
|
ensureSessionHostReady,
|
|
29638
30705
|
execNpmCommandSync,
|
|
30706
|
+
filterUserFacingChatMessages,
|
|
29639
30707
|
findCdpManager,
|
|
29640
30708
|
flattenMessageParts,
|
|
29641
30709
|
forwardAgentStreamsToIdeInstance,
|
|
@@ -29677,11 +30745,13 @@ export {
|
|
|
29677
30745
|
isSessionHostLiveRuntime,
|
|
29678
30746
|
isSessionHostRecoverySnapshot,
|
|
29679
30747
|
isSetupComplete,
|
|
30748
|
+
isUserFacingChatMessage,
|
|
29680
30749
|
killIdeProcess,
|
|
29681
30750
|
launchIDE,
|
|
29682
30751
|
launchWithCdp,
|
|
29683
30752
|
listHostedCliRuntimes,
|
|
29684
30753
|
listMeshes,
|
|
30754
|
+
listWorktrees,
|
|
29685
30755
|
loadConfig,
|
|
29686
30756
|
loadState,
|
|
29687
30757
|
logCommand,
|
|
@@ -29701,6 +30771,7 @@ export {
|
|
|
29701
30771
|
normalizeSessionModalFields,
|
|
29702
30772
|
parsePorcelainV2Status,
|
|
29703
30773
|
parseProviderSourceConfigUpdate,
|
|
30774
|
+
parseWorktreeListOutput,
|
|
29704
30775
|
partitionSessionHostDiagnosticsSessions,
|
|
29705
30776
|
partitionSessionHostRecords,
|
|
29706
30777
|
prepareSessionChatTailUpdate,
|
|
@@ -29710,6 +30781,7 @@ export {
|
|
|
29710
30781
|
recordDebugTrace,
|
|
29711
30782
|
registerExtensionProviders,
|
|
29712
30783
|
removeNode,
|
|
30784
|
+
removeWorktree,
|
|
29713
30785
|
resetConfig,
|
|
29714
30786
|
resetDebugRuntimeConfig,
|
|
29715
30787
|
resetState,
|
|
@@ -29719,6 +30791,7 @@ export {
|
|
|
29719
30791
|
resolveGitRepository,
|
|
29720
30792
|
resolveSessionHostAppName,
|
|
29721
30793
|
resolveSessionHostAppNameResolution,
|
|
30794
|
+
resolveWorktreePath,
|
|
29722
30795
|
runAsyncBatch,
|
|
29723
30796
|
runGit,
|
|
29724
30797
|
saveConfig,
|