@adhdev/daemon-core 0.9.76-rc.6 → 0.9.76-rc.61
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 +3 -3
- package/dist/index.js +1690 -447
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1703 -478
- 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 +40 -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/chat/subscription-updates.ts +3 -1
- 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 +16 -1
- package/src/mesh/coordinator-prompt.ts +29 -14
- package/src/mesh/mesh-events.ts +109 -43
- package/src/providers/chat-message-normalization.ts +241 -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
|
}
|
|
@@ -7641,6 +7815,20 @@ var StatusMonitor = class {
|
|
|
7641
7815
|
|
|
7642
7816
|
// src/providers/chat-message-normalization.ts
|
|
7643
7817
|
var BUILTIN_CHAT_MESSAGE_KINDS = ["standard", "thought", "tool", "terminal", "system"];
|
|
7818
|
+
var CHAT_MESSAGE_VISIBILITIES = ["user", "debug", "internal", "hidden"];
|
|
7819
|
+
var CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES = ["visible", "chat", "user", "debug", "internal", "hidden"];
|
|
7820
|
+
var CHAT_MESSAGE_AUDIENCES = ["chat", "debug", "trace", "internal"];
|
|
7821
|
+
var CHAT_MESSAGE_SOURCES = [
|
|
7822
|
+
"assistant_text",
|
|
7823
|
+
"tool_call",
|
|
7824
|
+
"terminal_command",
|
|
7825
|
+
"runtime_activity",
|
|
7826
|
+
"runtime_status",
|
|
7827
|
+
"provider_chrome",
|
|
7828
|
+
"control"
|
|
7829
|
+
];
|
|
7830
|
+
var CHAT_MESSAGE_ACTIVITY_SOURCES = ["tool_call", "terminal_command", "runtime_activity"];
|
|
7831
|
+
var CHAT_MESSAGE_INTERNAL_SOURCES = ["runtime_status", "provider_chrome", "control"];
|
|
7644
7832
|
var KNOWN_CHAT_MESSAGE_KINDS = new Set(BUILTIN_CHAT_MESSAGE_KINDS);
|
|
7645
7833
|
var CHAT_MESSAGE_KIND_ALIASES = {
|
|
7646
7834
|
text: "standard",
|
|
@@ -7782,6 +7970,169 @@ function normalizeChatMessage(message) {
|
|
|
7782
7970
|
function normalizeChatMessages(messages) {
|
|
7783
7971
|
return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
|
|
7784
7972
|
}
|
|
7973
|
+
function readMessageMeta(message) {
|
|
7974
|
+
const meta = message?.meta;
|
|
7975
|
+
return meta && typeof meta === "object" && !Array.isArray(meta) ? meta : null;
|
|
7976
|
+
}
|
|
7977
|
+
function readStringField(value) {
|
|
7978
|
+
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
7979
|
+
}
|
|
7980
|
+
function readRecordField(message, meta, key) {
|
|
7981
|
+
const record = message;
|
|
7982
|
+
return record[key] ?? meta?.[key];
|
|
7983
|
+
}
|
|
7984
|
+
function readVisibilityField(message, meta) {
|
|
7985
|
+
return readStringField(readRecordField(message, meta, "visibility"));
|
|
7986
|
+
}
|
|
7987
|
+
function readTranscriptVisibilityField(message, meta) {
|
|
7988
|
+
const record = message;
|
|
7989
|
+
return readStringField(record.transcriptVisibility ?? meta?.transcriptVisibility ?? record.visibility ?? meta?.visibility);
|
|
7990
|
+
}
|
|
7991
|
+
var EXPLICIT_HIDDEN_VISIBILITIES = /* @__PURE__ */ new Set(["hidden", "debug", "internal"]);
|
|
7992
|
+
var EXPLICIT_VISIBLE_VISIBILITIES = /* @__PURE__ */ new Set(["visible", "user", "chat"]);
|
|
7993
|
+
var HIDDEN_AUDIENCES = /* @__PURE__ */ new Set(["debug", "trace", "internal"]);
|
|
7994
|
+
var ACTIVITY_SOURCE_SET = new Set(CHAT_MESSAGE_ACTIVITY_SOURCES);
|
|
7995
|
+
var INTERNAL_SOURCE_SET = new Set(CHAT_MESSAGE_INTERNAL_SOURCES);
|
|
7996
|
+
function hasBooleanMarker(message, meta, keys) {
|
|
7997
|
+
const record = message;
|
|
7998
|
+
return keys.some((key) => record[key] === true || meta?.[key] === true);
|
|
7999
|
+
}
|
|
8000
|
+
function isActivityKind(kind) {
|
|
8001
|
+
return kind === "thought" || kind === "tool" || kind === "terminal";
|
|
8002
|
+
}
|
|
8003
|
+
function isOrdinaryVisibleTurn(message, role, kind) {
|
|
8004
|
+
if (role === "user" || role === "human") return kind === "standard" || kind === "";
|
|
8005
|
+
if (role === "assistant") return kind === "standard" || kind === "";
|
|
8006
|
+
return false;
|
|
8007
|
+
}
|
|
8008
|
+
function classifyChatMessageVisibility(message) {
|
|
8009
|
+
if (!message) {
|
|
8010
|
+
return {
|
|
8011
|
+
surface: "internal",
|
|
8012
|
+
isUserFacing: false,
|
|
8013
|
+
isActivityFacing: false,
|
|
8014
|
+
isInternal: true,
|
|
8015
|
+
explicitUserFacing: false,
|
|
8016
|
+
explicitHidden: true,
|
|
8017
|
+
role: "",
|
|
8018
|
+
kind: "standard",
|
|
8019
|
+
visibility: "",
|
|
8020
|
+
transcriptVisibility: "",
|
|
8021
|
+
audience: "",
|
|
8022
|
+
source: ""
|
|
8023
|
+
};
|
|
8024
|
+
}
|
|
8025
|
+
const meta = readMessageMeta(message);
|
|
8026
|
+
const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
8027
|
+
const kind = resolveChatMessageKind(message);
|
|
8028
|
+
const visibility = readVisibilityField(message, meta);
|
|
8029
|
+
const transcriptVisibility = readTranscriptVisibilityField(message, meta);
|
|
8030
|
+
const audience = readStringField(readRecordField(message, meta, "audience"));
|
|
8031
|
+
const source = readStringField(readRecordField(message, meta, "source"));
|
|
8032
|
+
const explicitHidden = EXPLICIT_HIDDEN_VISIBILITIES.has(visibility) || EXPLICIT_HIDDEN_VISIBILITIES.has(transcriptVisibility) || HIDDEN_AUDIENCES.has(audience) || hasBooleanMarker(message, meta, ["internal", "isInternal", "debug", "statusOnly", "controlOnly"]);
|
|
8033
|
+
const explicitUserFacing = EXPLICIT_VISIBLE_VISIBILITIES.has(visibility) || EXPLICIT_VISIBLE_VISIBILITIES.has(transcriptVisibility) || audience === "chat" || hasBooleanMarker(message, meta, ["userFacing"]);
|
|
8034
|
+
if (explicitHidden) {
|
|
8035
|
+
const activityLike = isActivityKind(kind) || ACTIVITY_SOURCE_SET.has(source);
|
|
8036
|
+
return {
|
|
8037
|
+
surface: activityLike ? "activity" : "internal",
|
|
8038
|
+
isUserFacing: false,
|
|
8039
|
+
isActivityFacing: activityLike,
|
|
8040
|
+
isInternal: !activityLike,
|
|
8041
|
+
explicitUserFacing,
|
|
8042
|
+
explicitHidden,
|
|
8043
|
+
role,
|
|
8044
|
+
kind,
|
|
8045
|
+
visibility,
|
|
8046
|
+
transcriptVisibility,
|
|
8047
|
+
audience,
|
|
8048
|
+
source
|
|
8049
|
+
};
|
|
8050
|
+
}
|
|
8051
|
+
if (explicitUserFacing) {
|
|
8052
|
+
return {
|
|
8053
|
+
surface: "chat",
|
|
8054
|
+
isUserFacing: true,
|
|
8055
|
+
isActivityFacing: false,
|
|
8056
|
+
isInternal: false,
|
|
8057
|
+
explicitUserFacing,
|
|
8058
|
+
explicitHidden,
|
|
8059
|
+
role,
|
|
8060
|
+
kind,
|
|
8061
|
+
visibility,
|
|
8062
|
+
transcriptVisibility,
|
|
8063
|
+
audience,
|
|
8064
|
+
source
|
|
8065
|
+
};
|
|
8066
|
+
}
|
|
8067
|
+
if (INTERNAL_SOURCE_SET.has(source) || role === "system" || kind === "system") {
|
|
8068
|
+
return {
|
|
8069
|
+
surface: "internal",
|
|
8070
|
+
isUserFacing: false,
|
|
8071
|
+
isActivityFacing: false,
|
|
8072
|
+
isInternal: true,
|
|
8073
|
+
explicitUserFacing,
|
|
8074
|
+
explicitHidden,
|
|
8075
|
+
role,
|
|
8076
|
+
kind,
|
|
8077
|
+
visibility,
|
|
8078
|
+
transcriptVisibility,
|
|
8079
|
+
audience,
|
|
8080
|
+
source
|
|
8081
|
+
};
|
|
8082
|
+
}
|
|
8083
|
+
if (ACTIVITY_SOURCE_SET.has(source) || isActivityKind(kind)) {
|
|
8084
|
+
return {
|
|
8085
|
+
surface: "activity",
|
|
8086
|
+
isUserFacing: false,
|
|
8087
|
+
isActivityFacing: true,
|
|
8088
|
+
isInternal: false,
|
|
8089
|
+
explicitUserFacing,
|
|
8090
|
+
explicitHidden,
|
|
8091
|
+
role,
|
|
8092
|
+
kind,
|
|
8093
|
+
visibility,
|
|
8094
|
+
transcriptVisibility,
|
|
8095
|
+
audience,
|
|
8096
|
+
source
|
|
8097
|
+
};
|
|
8098
|
+
}
|
|
8099
|
+
const isUserFacing = isOrdinaryVisibleTurn(message, role, kind);
|
|
8100
|
+
return {
|
|
8101
|
+
surface: isUserFacing ? "chat" : "internal",
|
|
8102
|
+
isUserFacing,
|
|
8103
|
+
isActivityFacing: false,
|
|
8104
|
+
isInternal: !isUserFacing,
|
|
8105
|
+
explicitUserFacing,
|
|
8106
|
+
explicitHidden,
|
|
8107
|
+
role,
|
|
8108
|
+
kind,
|
|
8109
|
+
visibility,
|
|
8110
|
+
transcriptVisibility,
|
|
8111
|
+
audience,
|
|
8112
|
+
source
|
|
8113
|
+
};
|
|
8114
|
+
}
|
|
8115
|
+
function isUserFacingChatMessage(message) {
|
|
8116
|
+
return classifyChatMessageVisibility(message).isUserFacing;
|
|
8117
|
+
}
|
|
8118
|
+
function isActivityChatMessage(message) {
|
|
8119
|
+
return classifyChatMessageVisibility(message).isActivityFacing;
|
|
8120
|
+
}
|
|
8121
|
+
function isInternalChatMessage(message) {
|
|
8122
|
+
return classifyChatMessageVisibility(message).isInternal;
|
|
8123
|
+
}
|
|
8124
|
+
function filterUserFacingChatMessages(messages) {
|
|
8125
|
+
return (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
|
|
8126
|
+
}
|
|
8127
|
+
function filterActivityChatMessages(messages) {
|
|
8128
|
+
return (Array.isArray(messages) ? messages : []).filter((message) => isActivityChatMessage(message));
|
|
8129
|
+
}
|
|
8130
|
+
function filterInternalChatMessages(messages) {
|
|
8131
|
+
return (Array.isArray(messages) ? messages : []).filter((message) => isInternalChatMessage(message));
|
|
8132
|
+
}
|
|
8133
|
+
function filterChatMessagesByVisibility(messages, surface) {
|
|
8134
|
+
return (Array.isArray(messages) ? messages : []).filter((message) => classifyChatMessageVisibility(message).surface === surface);
|
|
8135
|
+
}
|
|
7785
8136
|
|
|
7786
8137
|
// src/providers/control-effects.ts
|
|
7787
8138
|
function extractProviderControlValues(controls, data) {
|
|
@@ -7978,9 +8329,9 @@ ${cleanBody}`;
|
|
|
7978
8329
|
|
|
7979
8330
|
// src/config/chat-history.ts
|
|
7980
8331
|
import * as fs3 from "fs";
|
|
7981
|
-
import * as
|
|
8332
|
+
import * as path11 from "path";
|
|
7982
8333
|
import * as os5 from "os";
|
|
7983
|
-
var HISTORY_DIR =
|
|
8334
|
+
var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
|
|
7984
8335
|
var RETAIN_DAYS = 30;
|
|
7985
8336
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
7986
8337
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -8143,7 +8494,7 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
8143
8494
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
8144
8495
|
return new Map(files.map((file) => {
|
|
8145
8496
|
try {
|
|
8146
|
-
const stat2 = fs3.statSync(
|
|
8497
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8147
8498
|
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
8148
8499
|
} catch {
|
|
8149
8500
|
return [file, `${file}:missing`];
|
|
@@ -8154,7 +8505,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
8154
8505
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
8155
8506
|
}
|
|
8156
8507
|
function getSavedHistoryIndexFilePath(dir) {
|
|
8157
|
-
return
|
|
8508
|
+
return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
8158
8509
|
}
|
|
8159
8510
|
function getSavedHistoryIndexLockPath(dir) {
|
|
8160
8511
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -8256,7 +8607,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
8256
8607
|
}
|
|
8257
8608
|
for (const file of Array.from(currentEntries.keys())) {
|
|
8258
8609
|
if (incomingFiles.has(file)) continue;
|
|
8259
|
-
if (!fs3.existsSync(
|
|
8610
|
+
if (!fs3.existsSync(path11.join(dir, file))) {
|
|
8260
8611
|
currentEntries.delete(file);
|
|
8261
8612
|
}
|
|
8262
8613
|
}
|
|
@@ -8282,7 +8633,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8282
8633
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8283
8634
|
const files = listHistoryFiles(dir);
|
|
8284
8635
|
for (const file of files) {
|
|
8285
|
-
const stat2 = fs3.statSync(
|
|
8636
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8286
8637
|
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
8287
8638
|
}
|
|
8288
8639
|
return false;
|
|
@@ -8292,14 +8643,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8292
8643
|
}
|
|
8293
8644
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
8294
8645
|
try {
|
|
8295
|
-
const stat2 = fs3.statSync(
|
|
8646
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8296
8647
|
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
8297
8648
|
} catch {
|
|
8298
8649
|
return `${file}:missing`;
|
|
8299
8650
|
}
|
|
8300
8651
|
}
|
|
8301
8652
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
8302
|
-
const filePath =
|
|
8653
|
+
const filePath = path11.join(dir, file);
|
|
8303
8654
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
8304
8655
|
const currentEntry = entries.get(file) || null;
|
|
8305
8656
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -8372,7 +8723,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
8372
8723
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
8373
8724
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
8374
8725
|
if (!historySessionId) return null;
|
|
8375
|
-
const filePath =
|
|
8726
|
+
const filePath = path11.join(dir, file);
|
|
8376
8727
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8377
8728
|
const lines = content.split("\n").filter(Boolean);
|
|
8378
8729
|
let messageCount = 0;
|
|
@@ -8459,7 +8810,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
8459
8810
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
8460
8811
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
8461
8812
|
for (const file of files.slice().sort()) {
|
|
8462
|
-
const filePath =
|
|
8813
|
+
const filePath = path11.join(dir, file);
|
|
8463
8814
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
8464
8815
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
8465
8816
|
const persisted = persistedEntries.get(file);
|
|
@@ -8579,12 +8930,12 @@ var ChatHistoryWriter = class {
|
|
|
8579
8930
|
});
|
|
8580
8931
|
}
|
|
8581
8932
|
if (newMessages.length === 0) return;
|
|
8582
|
-
const dir =
|
|
8933
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8583
8934
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8584
8935
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8585
8936
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
8586
8937
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
8587
|
-
const filePath =
|
|
8938
|
+
const filePath = path11.join(dir, fileName);
|
|
8588
8939
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
8589
8940
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
8590
8941
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -8675,11 +9026,11 @@ var ChatHistoryWriter = class {
|
|
|
8675
9026
|
const ws = String(workspace || "").trim();
|
|
8676
9027
|
if (!id || !ws) return;
|
|
8677
9028
|
try {
|
|
8678
|
-
const dir =
|
|
9029
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8679
9030
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8680
9031
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8681
9032
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
8682
|
-
const filePath =
|
|
9033
|
+
const filePath = path11.join(dir, fileName);
|
|
8683
9034
|
const record = {
|
|
8684
9035
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8685
9036
|
receivedAt: Date.now(),
|
|
@@ -8725,14 +9076,14 @@ var ChatHistoryWriter = class {
|
|
|
8725
9076
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8726
9077
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8727
9078
|
}
|
|
8728
|
-
const dir =
|
|
9079
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8729
9080
|
if (!fs3.existsSync(dir)) return;
|
|
8730
9081
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8731
9082
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8732
9083
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8733
9084
|
for (const file of files) {
|
|
8734
|
-
const sourcePath =
|
|
8735
|
-
const targetPath =
|
|
9085
|
+
const sourcePath = path11.join(dir, file);
|
|
9086
|
+
const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8736
9087
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8737
9088
|
const rewritten = sourceLines.map((line) => {
|
|
8738
9089
|
try {
|
|
@@ -8766,13 +9117,13 @@ var ChatHistoryWriter = class {
|
|
|
8766
9117
|
const sessionId = String(historySessionId || "").trim();
|
|
8767
9118
|
if (!sessionId) return;
|
|
8768
9119
|
try {
|
|
8769
|
-
const dir =
|
|
9120
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8770
9121
|
if (!fs3.existsSync(dir)) return;
|
|
8771
9122
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8772
9123
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8773
9124
|
const seen = /* @__PURE__ */ new Set();
|
|
8774
9125
|
for (const file of files) {
|
|
8775
|
-
const filePath =
|
|
9126
|
+
const filePath = path11.join(dir, file);
|
|
8776
9127
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8777
9128
|
const next = [];
|
|
8778
9129
|
for (const line of lines) {
|
|
@@ -8826,11 +9177,11 @@ var ChatHistoryWriter = class {
|
|
|
8826
9177
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
8827
9178
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
8828
9179
|
for (const dir of agentDirs) {
|
|
8829
|
-
const dirPath =
|
|
9180
|
+
const dirPath = path11.join(HISTORY_DIR, dir.name);
|
|
8830
9181
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
8831
9182
|
let removedAny = false;
|
|
8832
9183
|
for (const file of files) {
|
|
8833
|
-
const filePath =
|
|
9184
|
+
const filePath = path11.join(dirPath, file);
|
|
8834
9185
|
const stat2 = fs3.statSync(filePath);
|
|
8835
9186
|
if (stat2.mtimeMs < cutoff) {
|
|
8836
9187
|
fs3.unlinkSync(filePath);
|
|
@@ -8880,13 +9231,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8880
9231
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8881
9232
|
try {
|
|
8882
9233
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8883
|
-
const dir =
|
|
9234
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8884
9235
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
8885
9236
|
const files = listHistoryFiles(dir, historySessionId);
|
|
8886
9237
|
const allMessages = [];
|
|
8887
9238
|
const seen = /* @__PURE__ */ new Set();
|
|
8888
9239
|
for (const file of files) {
|
|
8889
|
-
const filePath =
|
|
9240
|
+
const filePath = path11.join(dir, file);
|
|
8890
9241
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8891
9242
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
8892
9243
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8910,7 +9261,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8910
9261
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
8911
9262
|
try {
|
|
8912
9263
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8913
|
-
const dir =
|
|
9264
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8914
9265
|
if (!fs3.existsSync(dir)) {
|
|
8915
9266
|
savedHistorySessionCache.delete(sanitized);
|
|
8916
9267
|
return { sessions: [], hasMore: false };
|
|
@@ -8971,11 +9322,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8971
9322
|
}
|
|
8972
9323
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8973
9324
|
try {
|
|
8974
|
-
const dir =
|
|
9325
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8975
9326
|
if (!fs3.existsSync(dir)) return null;
|
|
8976
9327
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
8977
9328
|
for (const file of files) {
|
|
8978
|
-
const lines = fs3.readFileSync(
|
|
9329
|
+
const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
8979
9330
|
for (const line of lines) {
|
|
8980
9331
|
try {
|
|
8981
9332
|
const parsed = JSON.parse(line);
|
|
@@ -8995,16 +9346,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
8995
9346
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
8996
9347
|
if (records.length === 0) return false;
|
|
8997
9348
|
try {
|
|
8998
|
-
const dir =
|
|
9349
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8999
9350
|
fs3.mkdirSync(dir, { recursive: true });
|
|
9000
9351
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
9001
9352
|
for (const file of fs3.readdirSync(dir)) {
|
|
9002
9353
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
9003
|
-
fs3.unlinkSync(
|
|
9354
|
+
fs3.unlinkSync(path11.join(dir, file));
|
|
9004
9355
|
}
|
|
9005
9356
|
}
|
|
9006
9357
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
9007
|
-
const filePath =
|
|
9358
|
+
const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
9008
9359
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
9009
9360
|
`, "utf-8");
|
|
9010
9361
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -9754,6 +10105,14 @@ function validateMessage(message, source, index) {
|
|
|
9754
10105
|
if (typeof message.senderName === "string") normalized.senderName = message.senderName;
|
|
9755
10106
|
if (typeof message._type === "string") normalized._type = message._type;
|
|
9756
10107
|
if (typeof message._sub === "string") normalized._sub = message._sub;
|
|
10108
|
+
if (typeof message.visibility === "string") normalized.visibility = message.visibility;
|
|
10109
|
+
if (typeof message.transcriptVisibility === "string") normalized.transcriptVisibility = message.transcriptVisibility;
|
|
10110
|
+
if (typeof message.audience === "string") normalized.audience = message.audience;
|
|
10111
|
+
if (typeof message.source === "string") normalized.source = message.source;
|
|
10112
|
+
if (typeof message.userFacing === "boolean") normalized.userFacing = message.userFacing;
|
|
10113
|
+
if (typeof message.internal === "boolean") normalized.internal = message.internal;
|
|
10114
|
+
if (typeof message.isInternal === "boolean") normalized.isInternal = message.isInternal;
|
|
10115
|
+
if (typeof message.debug === "boolean") normalized.debug = message.debug;
|
|
9757
10116
|
return normalized;
|
|
9758
10117
|
}
|
|
9759
10118
|
function validateModal(activeModal, status, source) {
|
|
@@ -10999,6 +11358,14 @@ function getActiveChatOptions(profile) {
|
|
|
10999
11358
|
if (profile === "full") return {};
|
|
11000
11359
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
11001
11360
|
}
|
|
11361
|
+
function resolveSessionStatus(activeChat, providerStatus) {
|
|
11362
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
11363
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
11364
|
+
if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
|
|
11365
|
+
if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
|
|
11366
|
+
if (topLevelStatus !== "idle") return topLevelStatus;
|
|
11367
|
+
return chatStatus;
|
|
11368
|
+
}
|
|
11002
11369
|
function shouldIncludeSessionControls(profile) {
|
|
11003
11370
|
return profile !== "live";
|
|
11004
11371
|
}
|
|
@@ -11077,9 +11444,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11077
11444
|
providerName: state.name,
|
|
11078
11445
|
kind: "workspace",
|
|
11079
11446
|
transport: "cdp-page",
|
|
11080
|
-
status:
|
|
11081
|
-
activeModal: activeChat?.activeModal || null
|
|
11082
|
-
}),
|
|
11447
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11083
11448
|
title,
|
|
11084
11449
|
workspace,
|
|
11085
11450
|
...git && { git },
|
|
@@ -11114,9 +11479,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11114
11479
|
providerSessionId: ext.providerSessionId,
|
|
11115
11480
|
kind: "agent",
|
|
11116
11481
|
transport: "cdp-webview",
|
|
11117
|
-
status:
|
|
11118
|
-
activeModal: activeChat?.activeModal || null
|
|
11119
|
-
}),
|
|
11482
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
11120
11483
|
title: activeChat?.title || ext.name,
|
|
11121
11484
|
workspace,
|
|
11122
11485
|
...git && { git },
|
|
@@ -11166,9 +11529,7 @@ function buildCliSession(state, options) {
|
|
|
11166
11529
|
providerSessionId: state.providerSessionId,
|
|
11167
11530
|
kind: "agent",
|
|
11168
11531
|
transport: "pty",
|
|
11169
|
-
status:
|
|
11170
|
-
activeModal: activeChat?.activeModal || null
|
|
11171
|
-
}),
|
|
11532
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11172
11533
|
title: activeChat?.title || state.name,
|
|
11173
11534
|
workspace,
|
|
11174
11535
|
...git && { git },
|
|
@@ -11216,9 +11577,7 @@ function buildAcpSession(state, options) {
|
|
|
11216
11577
|
providerName: state.name,
|
|
11217
11578
|
kind: "agent",
|
|
11218
11579
|
transport: "acp",
|
|
11219
|
-
status:
|
|
11220
|
-
activeModal: activeChat?.activeModal || null
|
|
11221
|
-
}),
|
|
11580
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11222
11581
|
title: activeChat?.title || state.name,
|
|
11223
11582
|
workspace,
|
|
11224
11583
|
...git && { git },
|
|
@@ -11341,7 +11700,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
11341
11700
|
// src/commands/chat-commands.ts
|
|
11342
11701
|
import * as fs4 from "fs";
|
|
11343
11702
|
import * as os6 from "os";
|
|
11344
|
-
import * as
|
|
11703
|
+
import * as path12 from "path";
|
|
11345
11704
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
11346
11705
|
|
|
11347
11706
|
// src/providers/provider-input-support.ts
|
|
@@ -11544,6 +11903,7 @@ function buildSessionModalDeliverySignature(payload) {
|
|
|
11544
11903
|
// src/commands/chat-commands.ts
|
|
11545
11904
|
var RECENT_SEND_WINDOW_MS = 1200;
|
|
11546
11905
|
var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
|
|
11906
|
+
var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
|
|
11547
11907
|
var recentSendByTarget = /* @__PURE__ */ new Map();
|
|
11548
11908
|
function getCurrentProviderType(h, fallback = "") {
|
|
11549
11909
|
return h.currentSession?.providerType || h.currentProviderType || fallback;
|
|
@@ -11596,6 +11956,16 @@ function buildSendInputSignature(input) {
|
|
|
11596
11956
|
function getSendChatInputEnvelope(args) {
|
|
11597
11957
|
return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
|
|
11598
11958
|
}
|
|
11959
|
+
function sleep(ms) {
|
|
11960
|
+
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
11961
|
+
}
|
|
11962
|
+
async function waitOnceForFreshHermesCliStart(adapter, log) {
|
|
11963
|
+
if (adapter.cliType !== "hermes-cli") return;
|
|
11964
|
+
const status = typeof adapter.getStatus === "function" ? adapter.getStatus()?.status : void 0;
|
|
11965
|
+
if (status !== "starting") return;
|
|
11966
|
+
log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
|
|
11967
|
+
await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
|
|
11968
|
+
}
|
|
11599
11969
|
function getHistorySessionId(h, args) {
|
|
11600
11970
|
const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
|
|
11601
11971
|
if (explicit) return explicit;
|
|
@@ -11650,7 +12020,7 @@ function normalizeReadChatTailLimit(args) {
|
|
|
11650
12020
|
}
|
|
11651
12021
|
function normalizeReadChatMessages(payload) {
|
|
11652
12022
|
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
11653
|
-
return messages;
|
|
12023
|
+
return normalizeChatMessages(messages);
|
|
11654
12024
|
}
|
|
11655
12025
|
function deriveHistoryDedupKey(message) {
|
|
11656
12026
|
const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
|
|
@@ -11704,6 +12074,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
11704
12074
|
return raw;
|
|
11705
12075
|
}
|
|
11706
12076
|
}
|
|
12077
|
+
function isGeneratingLikeStatus(status) {
|
|
12078
|
+
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
12079
|
+
}
|
|
12080
|
+
function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
12081
|
+
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
12082
|
+
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
12083
|
+
const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
|
|
12084
|
+
if (adapterRawStatus !== "idle") return false;
|
|
12085
|
+
if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
|
|
12086
|
+
return true;
|
|
12087
|
+
}
|
|
12088
|
+
function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
12089
|
+
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
12090
|
+
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
12091
|
+
}
|
|
12092
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
12093
|
+
if (status !== "idle") return messages;
|
|
12094
|
+
return messages.map((message) => {
|
|
12095
|
+
const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
12096
|
+
const hasStreamingMeta = meta?.streaming === true;
|
|
12097
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
12098
|
+
return {
|
|
12099
|
+
...message,
|
|
12100
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
12101
|
+
...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
|
|
12102
|
+
};
|
|
12103
|
+
});
|
|
12104
|
+
}
|
|
11707
12105
|
function buildReadChatCommandResult(payload, args) {
|
|
11708
12106
|
let validatedPayload;
|
|
11709
12107
|
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
@@ -11716,13 +12114,22 @@ function buildReadChatCommandResult(payload, args) {
|
|
|
11716
12114
|
return { success: false, error: error?.message || String(error) };
|
|
11717
12115
|
}
|
|
11718
12116
|
const messages = normalizeReadChatMessages(validatedPayload);
|
|
11719
|
-
const
|
|
12117
|
+
const visibleMessages = filterUserFacingChatMessages(messages);
|
|
12118
|
+
const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
|
|
12119
|
+
const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
|
|
12120
|
+
const returnedDebugReadChat = debugReadChat ? {
|
|
12121
|
+
...debugReadChat,
|
|
12122
|
+
fullMsgCount: typeof debugReadChat.fullMsgCount === "number" ? debugReadChat.fullMsgCount : messages.length,
|
|
12123
|
+
visibleMsgCount: visibleMessages.length,
|
|
12124
|
+
hiddenMsgCount,
|
|
12125
|
+
returnedMsgCount: sync.messages.length
|
|
12126
|
+
} : void 0;
|
|
11720
12127
|
return {
|
|
11721
12128
|
success: true,
|
|
11722
12129
|
...validatedPayload,
|
|
11723
12130
|
messages: sync.messages,
|
|
11724
12131
|
totalMessages: sync.totalMessages,
|
|
11725
|
-
...
|
|
12132
|
+
...returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}
|
|
11726
12133
|
};
|
|
11727
12134
|
}
|
|
11728
12135
|
var DEFAULT_DEBUG_SANITIZE_OPTIONS = {
|
|
@@ -11852,7 +12259,7 @@ function buildDebugBundleText(bundle) {
|
|
|
11852
12259
|
}
|
|
11853
12260
|
function getChatDebugBundleDir() {
|
|
11854
12261
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
11855
|
-
return override ||
|
|
12262
|
+
return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
11856
12263
|
}
|
|
11857
12264
|
function safeBundleIdSegment(value, fallback) {
|
|
11858
12265
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -11868,6 +12275,14 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
11868
12275
|
const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
|
|
11869
12276
|
const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
|
|
11870
12277
|
const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
|
|
12278
|
+
const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
|
|
12279
|
+
const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
|
|
12280
|
+
const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
|
|
12281
|
+
const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
|
|
12282
|
+
const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
|
|
12283
|
+
const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
|
|
12284
|
+
const cliStatus = typeof cli?.status === "string" ? cli.status : "";
|
|
12285
|
+
const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
|
|
11871
12286
|
return {
|
|
11872
12287
|
createdAt: bundle.createdAt,
|
|
11873
12288
|
targetSessionId: target.targetSessionId,
|
|
@@ -11876,8 +12291,22 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
11876
12291
|
readChatSuccess: readChat.success,
|
|
11877
12292
|
readChatStatus: readChat.status,
|
|
11878
12293
|
readChatTotalMessages: readChat.totalMessages,
|
|
12294
|
+
readChatReturnedMessages,
|
|
11879
12295
|
cliStatus: cli?.status,
|
|
12296
|
+
cliParsedStatus: cliParsedStatus || void 0,
|
|
11880
12297
|
cliMessageCount: cli?.messageCount,
|
|
12298
|
+
cliParsedMessageCount,
|
|
12299
|
+
cliPartialResponseChars: cliPartialResponse.length,
|
|
12300
|
+
parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
|
|
12301
|
+
parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
|
|
12302
|
+
readChatDebug: Object.keys(debugReadChat).length ? {
|
|
12303
|
+
adapterStatus: debugReadChat.adapterStatus,
|
|
12304
|
+
parsedStatus: debugReadChat.parsedStatus,
|
|
12305
|
+
returnedStatus: debugReadChat.returnedStatus,
|
|
12306
|
+
parsedMsgCount: debugReadChat.parsedMsgCount,
|
|
12307
|
+
returnedMsgCount: debugReadChat.returnedMsgCount,
|
|
12308
|
+
shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
|
|
12309
|
+
} : void 0,
|
|
11881
12310
|
hasFrontendSnapshot: !!frontend
|
|
11882
12311
|
};
|
|
11883
12312
|
}
|
|
@@ -11885,7 +12314,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
11885
12314
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
11886
12315
|
const dir = getChatDebugBundleDir();
|
|
11887
12316
|
fs4.mkdirSync(dir, { recursive: true });
|
|
11888
|
-
const savedPath =
|
|
12317
|
+
const savedPath = path12.join(dir, `${bundleId}.json`);
|
|
11889
12318
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
11890
12319
|
`;
|
|
11891
12320
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -12115,7 +12544,7 @@ async function handleChatHistory(h, args) {
|
|
|
12115
12544
|
}
|
|
12116
12545
|
}
|
|
12117
12546
|
async function handleReadChat(h, args) {
|
|
12118
|
-
const provider = h.getProvider(args?.agentType);
|
|
12547
|
+
const provider = h.getProvider(args?.agentType || args?.providerType);
|
|
12119
12548
|
const transport = getTargetTransport(h, provider);
|
|
12120
12549
|
const historySessionId = getHistorySessionId(h, args);
|
|
12121
12550
|
const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
|
|
@@ -12142,10 +12571,13 @@ async function handleReadChat(h, args) {
|
|
|
12142
12571
|
const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
12143
12572
|
const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
12144
12573
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
12145
|
-
const returnedStatus = parsedRecord.status
|
|
12146
|
-
|
|
12574
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
12575
|
+
const runtimeMessageMerger = getTargetInstance(h, args);
|
|
12576
|
+
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
|
|
12577
|
+
const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
|
|
12578
|
+
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
12579
|
return buildReadChatCommandResult({
|
|
12148
|
-
messages:
|
|
12580
|
+
messages: returnedMessages,
|
|
12149
12581
|
status: returnedStatus,
|
|
12150
12582
|
activeModal,
|
|
12151
12583
|
debugReadChat: {
|
|
@@ -12156,7 +12588,7 @@ async function handleReadChat(h, args) {
|
|
|
12156
12588
|
returnedStatus: String(returnedStatus || ""),
|
|
12157
12589
|
shouldPreferAdapterMessages: false,
|
|
12158
12590
|
parsedMsgCount: parsedRecord.messages.length,
|
|
12159
|
-
returnedMsgCount:
|
|
12591
|
+
returnedMsgCount: returnedMessages.length
|
|
12160
12592
|
},
|
|
12161
12593
|
...title ? { title } : {},
|
|
12162
12594
|
...providerSessionId ? { providerSessionId } : {},
|
|
@@ -12402,6 +12834,7 @@ async function handleSendChat(h, args) {
|
|
|
12402
12834
|
try {
|
|
12403
12835
|
assertTextOnlyInput(provider, input);
|
|
12404
12836
|
if (!text) return { success: false, error: "text required for PTY send" };
|
|
12837
|
+
await waitOnceForFreshHermesCliStart(adapter, _log);
|
|
12405
12838
|
await adapter.sendMessage(text);
|
|
12406
12839
|
return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
|
|
12407
12840
|
} catch (e) {
|
|
@@ -12901,9 +13334,17 @@ async function handleResolveAction(h, args) {
|
|
|
12901
13334
|
const targetState = targetInstance?.getState?.();
|
|
12902
13335
|
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
13336
|
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
|
-
|
|
13337
|
+
const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
|
|
13338
|
+
try {
|
|
13339
|
+
return parseMaybeJson(adapter.getScriptParsedStatus());
|
|
13340
|
+
} catch {
|
|
13341
|
+
return null;
|
|
13342
|
+
}
|
|
13343
|
+
})() : null;
|
|
13344
|
+
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;
|
|
13345
|
+
const effectiveModal = statusModal || surfacedModal || parsedModal;
|
|
13346
|
+
const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
|
|
13347
|
+
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
13348
|
if (!effectiveModal) {
|
|
12908
13349
|
return { success: false, error: "Not in approval state" };
|
|
12909
13350
|
}
|
|
@@ -13029,7 +13470,7 @@ async function handleResolveAction(h, args) {
|
|
|
13029
13470
|
|
|
13030
13471
|
// src/commands/cdp-commands.ts
|
|
13031
13472
|
import * as fs5 from "fs";
|
|
13032
|
-
import * as
|
|
13473
|
+
import * as path13 from "path";
|
|
13033
13474
|
import * as os7 from "os";
|
|
13034
13475
|
var KEY_TO_VK = {
|
|
13035
13476
|
Backspace: 8,
|
|
@@ -13286,25 +13727,25 @@ function resolveSafePath(requestedPath) {
|
|
|
13286
13727
|
const inputPath = rawPath || ".";
|
|
13287
13728
|
const home = os7.homedir();
|
|
13288
13729
|
if (inputPath.startsWith("~")) {
|
|
13289
|
-
return
|
|
13730
|
+
return path13.resolve(path13.join(home, inputPath.slice(1)));
|
|
13290
13731
|
}
|
|
13291
13732
|
if (process.platform === "win32") {
|
|
13292
13733
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
13293
|
-
if (
|
|
13294
|
-
return
|
|
13734
|
+
if (path13.win32.isAbsolute(normalized)) {
|
|
13735
|
+
return path13.win32.normalize(normalized);
|
|
13295
13736
|
}
|
|
13296
|
-
return
|
|
13737
|
+
return path13.win32.resolve(normalized);
|
|
13297
13738
|
}
|
|
13298
|
-
if (
|
|
13299
|
-
return
|
|
13739
|
+
if (path13.isAbsolute(inputPath)) {
|
|
13740
|
+
return path13.normalize(inputPath);
|
|
13300
13741
|
}
|
|
13301
|
-
return
|
|
13742
|
+
return path13.resolve(inputPath);
|
|
13302
13743
|
}
|
|
13303
13744
|
function listDirectoryEntriesSafe(dirPath) {
|
|
13304
13745
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
13305
13746
|
const files = [];
|
|
13306
13747
|
for (const entry of entries) {
|
|
13307
|
-
const entryPath =
|
|
13748
|
+
const entryPath = path13.join(dirPath, entry.name);
|
|
13308
13749
|
try {
|
|
13309
13750
|
if (entry.isDirectory()) {
|
|
13310
13751
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -13358,7 +13799,7 @@ async function handleFileRead(h, args) {
|
|
|
13358
13799
|
async function handleFileWrite(h, args) {
|
|
13359
13800
|
try {
|
|
13360
13801
|
const filePath = resolveSafePath(args?.path);
|
|
13361
|
-
fs5.mkdirSync(
|
|
13802
|
+
fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
13362
13803
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
13363
13804
|
return { success: true, path: filePath };
|
|
13364
13805
|
} catch (e) {
|
|
@@ -14142,9 +14583,11 @@ var DaemonCommandHandler = class {
|
|
|
14142
14583
|
}
|
|
14143
14584
|
const sessionLookupFailed = !!targetSessionId && !session;
|
|
14144
14585
|
const managerKey = this.extractIdeType(args, sessionLookupFailed);
|
|
14145
|
-
let providerType;
|
|
14586
|
+
let providerType = args?.agentType || args?.providerType;
|
|
14146
14587
|
if (!sessionLookupFailed) {
|
|
14147
|
-
providerType = session?.providerType ||
|
|
14588
|
+
providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
|
|
14589
|
+
} else if (!providerType) {
|
|
14590
|
+
providerType = this.inferProviderType(managerKey);
|
|
14148
14591
|
}
|
|
14149
14592
|
return { session, managerKey, providerType, sessionLookupFailed };
|
|
14150
14593
|
}
|
|
@@ -14224,7 +14667,8 @@ var DaemonCommandHandler = class {
|
|
|
14224
14667
|
"pty_resize",
|
|
14225
14668
|
"invoke_provider_script"
|
|
14226
14669
|
]);
|
|
14227
|
-
|
|
14670
|
+
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);
|
|
14671
|
+
if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
|
|
14228
14672
|
const result2 = {
|
|
14229
14673
|
success: false,
|
|
14230
14674
|
error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
|
|
@@ -14478,16 +14922,16 @@ var DaemonCommandHandler = class {
|
|
|
14478
14922
|
// src/commands/cli-manager.ts
|
|
14479
14923
|
init_provider_cli_adapter();
|
|
14480
14924
|
import * as os13 from "os";
|
|
14481
|
-
import * as
|
|
14925
|
+
import * as path17 from "path";
|
|
14482
14926
|
import * as crypto4 from "crypto";
|
|
14483
|
-
import { existsSync as
|
|
14927
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
14484
14928
|
import { execFileSync } from "child_process";
|
|
14485
14929
|
import chalk from "chalk";
|
|
14486
14930
|
init_config();
|
|
14487
14931
|
|
|
14488
14932
|
// src/providers/cli-provider-instance.ts
|
|
14489
14933
|
import * as os12 from "os";
|
|
14490
|
-
import * as
|
|
14934
|
+
import * as path16 from "path";
|
|
14491
14935
|
import * as crypto3 from "crypto";
|
|
14492
14936
|
import * as fs6 from "fs";
|
|
14493
14937
|
import { createRequire } from "module";
|
|
@@ -14546,7 +14990,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
14546
14990
|
var CachedDatabaseSync = null;
|
|
14547
14991
|
function getDatabaseSync() {
|
|
14548
14992
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
14549
|
-
const requireFn = typeof __require === "function" ? __require : createRequire(
|
|
14993
|
+
const requireFn = typeof __require === "function" ? __require : createRequire(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
14550
14994
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
14551
14995
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
14552
14996
|
if (!CachedDatabaseSync) {
|
|
@@ -14599,7 +15043,7 @@ var CliProviderInstance = class {
|
|
|
14599
15043
|
this.providerSessionId = options?.providerSessionId;
|
|
14600
15044
|
this.launchMode = options?.launchMode || "new";
|
|
14601
15045
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
14602
|
-
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
|
|
15046
|
+
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
14603
15047
|
this.monitor = new StatusMonitor();
|
|
14604
15048
|
this.historyWriter = new ChatHistoryWriter();
|
|
14605
15049
|
}
|
|
@@ -15076,7 +15520,19 @@ var CliProviderInstance = class {
|
|
|
15076
15520
|
}
|
|
15077
15521
|
}
|
|
15078
15522
|
pushEvent(event) {
|
|
15079
|
-
|
|
15523
|
+
const enrichedEvent = {
|
|
15524
|
+
...event,
|
|
15525
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
|
|
15526
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
|
|
15527
|
+
providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
|
|
15528
|
+
workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
|
|
15529
|
+
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
15530
|
+
};
|
|
15531
|
+
if (this.context?.emitProviderEvent) {
|
|
15532
|
+
this.context.emitProviderEvent(enrichedEvent);
|
|
15533
|
+
return;
|
|
15534
|
+
}
|
|
15535
|
+
this.events.push(enrichedEvent);
|
|
15080
15536
|
}
|
|
15081
15537
|
flushEvents() {
|
|
15082
15538
|
const events = [...this.events];
|
|
@@ -15283,12 +15739,59 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15283
15739
|
);
|
|
15284
15740
|
}
|
|
15285
15741
|
}
|
|
15742
|
+
mergeRuntimeChatMessages(parsedMessages) {
|
|
15743
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
15744
|
+
}
|
|
15286
15745
|
mergeConversationMessages(parsedMessages) {
|
|
15287
15746
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15747
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
15748
|
+
message,
|
|
15749
|
+
index,
|
|
15750
|
+
source: "parsed"
|
|
15751
|
+
}));
|
|
15752
|
+
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
15753
|
+
message: entry.message,
|
|
15754
|
+
index: parsedMessages.length + index,
|
|
15755
|
+
source: "runtime",
|
|
15756
|
+
runtimeKey: entry.key
|
|
15757
|
+
}));
|
|
15758
|
+
const getTime = (message) => {
|
|
15759
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
15760
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
15761
|
+
};
|
|
15762
|
+
const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
15763
|
+
const isRuntimeOverlay = (entry) => {
|
|
15764
|
+
if (entry.source !== "runtime") return false;
|
|
15765
|
+
const key = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
|
|
15766
|
+
if (key.startsWith("auto_approval:")) return true;
|
|
15767
|
+
return !isUserFacingChatMessage(entry.message);
|
|
15768
|
+
};
|
|
15769
|
+
const shouldKeepParsedBeforeUntimedRuntime = (message) => {
|
|
15770
|
+
const role = getRole(message);
|
|
15771
|
+
return role === "user" || role === "human";
|
|
15772
|
+
};
|
|
15773
|
+
const shouldKeepParsedAfterUntimedRuntime = (message) => {
|
|
15774
|
+
const role = getRole(message);
|
|
15775
|
+
if (role !== "assistant") return false;
|
|
15776
|
+
const kind = resolveChatMessageKind(message);
|
|
15777
|
+
return kind === "standard" || kind === "terminal";
|
|
15778
|
+
};
|
|
15779
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
15780
|
+
const aTime = getTime(a.message);
|
|
15781
|
+
const bTime = getTime(b.message);
|
|
15782
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
15783
|
+
if (a.source !== b.source && aTime !== bTime) {
|
|
15784
|
+
const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
|
|
15785
|
+
const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
|
|
15786
|
+
if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
|
|
15787
|
+
if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
|
|
15788
|
+
return a.source === "parsed" ? -1 : 1;
|
|
15789
|
+
}
|
|
15790
|
+
if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
|
|
15791
|
+
return a.source === "parsed" ? 1 : -1;
|
|
15792
|
+
}
|
|
15793
|
+
}
|
|
15794
|
+
}
|
|
15292
15795
|
return a.index - b.index;
|
|
15293
15796
|
}).map((entry) => entry.message));
|
|
15294
15797
|
}
|
|
@@ -16617,17 +17120,17 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
16617
17120
|
// src/commands/cli-manager.ts
|
|
16618
17121
|
function isExplicitCommand(command) {
|
|
16619
17122
|
const trimmed = command.trim();
|
|
16620
|
-
return
|
|
17123
|
+
return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
16621
17124
|
}
|
|
16622
17125
|
function expandExecutable(command) {
|
|
16623
17126
|
const trimmed = command.trim();
|
|
16624
|
-
return trimmed.startsWith("~") ?
|
|
17127
|
+
return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
16625
17128
|
}
|
|
16626
17129
|
function commandExists(command) {
|
|
16627
17130
|
const trimmed = command.trim();
|
|
16628
17131
|
if (!trimmed) return false;
|
|
16629
17132
|
if (isExplicitCommand(trimmed)) {
|
|
16630
|
-
return
|
|
17133
|
+
return existsSync12(expandExecutable(trimmed));
|
|
16631
17134
|
}
|
|
16632
17135
|
try {
|
|
16633
17136
|
execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -16645,6 +17148,35 @@ function colorize(color, text) {
|
|
|
16645
17148
|
const fn = chalkApi?.[color];
|
|
16646
17149
|
return typeof fn === "function" ? fn(text) : text;
|
|
16647
17150
|
}
|
|
17151
|
+
var COORDINATOR_DELEGATED_ENV_UNSETS = {
|
|
17152
|
+
ADHDEV_INLINE_MESH: "",
|
|
17153
|
+
ADHDEV_MCP_TRANSPORT: "",
|
|
17154
|
+
ADHDEV_MESH_ID: "",
|
|
17155
|
+
HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
|
|
17156
|
+
};
|
|
17157
|
+
function hasCliArg(args, flag) {
|
|
17158
|
+
return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
17159
|
+
}
|
|
17160
|
+
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
17161
|
+
const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
17162
|
+
mkdirSync7(baseDir, { recursive: true });
|
|
17163
|
+
const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
17164
|
+
const filePath = path17.join(baseDir, `${workspaceHash}.json`);
|
|
17165
|
+
writeFileSync7(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
17166
|
+
return filePath;
|
|
17167
|
+
}
|
|
17168
|
+
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
17169
|
+
const cliType = String(input.cliType || "").trim();
|
|
17170
|
+
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
17171
|
+
const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
|
|
17172
|
+
if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
|
|
17173
|
+
cliArgs.unshift("--ignore-user-config");
|
|
17174
|
+
}
|
|
17175
|
+
if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
|
|
17176
|
+
cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
17177
|
+
}
|
|
17178
|
+
return { cliArgs, env };
|
|
17179
|
+
}
|
|
16648
17180
|
function isUuid(value) {
|
|
16649
17181
|
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
17182
|
}
|
|
@@ -16815,7 +17347,7 @@ var DaemonCliManager = class {
|
|
|
16815
17347
|
attachExisting
|
|
16816
17348
|
}) || void 0;
|
|
16817
17349
|
}
|
|
16818
|
-
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
|
|
17350
|
+
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
|
|
16819
17351
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16820
17352
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
16821
17353
|
if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
|
|
@@ -16829,7 +17361,7 @@ var DaemonCliManager = class {
|
|
|
16829
17361
|
providerSessionId,
|
|
16830
17362
|
attachExisting
|
|
16831
17363
|
);
|
|
16832
|
-
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
|
|
17364
|
+
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
16833
17365
|
}
|
|
16834
17366
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
16835
17367
|
}
|
|
@@ -16902,7 +17434,7 @@ var DaemonCliManager = class {
|
|
|
16902
17434
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
16903
17435
|
const trimmed = (workingDir || "").trim();
|
|
16904
17436
|
if (!trimmed) throw new Error("working directory required");
|
|
16905
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17437
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
|
|
16906
17438
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16907
17439
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
16908
17440
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -17032,6 +17564,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17032
17564
|
{
|
|
17033
17565
|
providerSessionId: sessionBinding.providerSessionId,
|
|
17034
17566
|
launchMode: sessionBinding.launchMode,
|
|
17567
|
+
extraEnv: options?.extraEnv,
|
|
17035
17568
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
17036
17569
|
this.persistRecentActivity({
|
|
17037
17570
|
kind: "cli",
|
|
@@ -17052,7 +17585,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17052
17585
|
resolvedCliArgs,
|
|
17053
17586
|
key,
|
|
17054
17587
|
sessionBinding.providerSessionId,
|
|
17055
|
-
false
|
|
17588
|
+
false,
|
|
17589
|
+
options?.extraEnv
|
|
17056
17590
|
);
|
|
17057
17591
|
try {
|
|
17058
17592
|
await adapter.spawn();
|
|
@@ -17276,12 +17810,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17276
17810
|
const dir = resolved.path;
|
|
17277
17811
|
const launchSource = resolved.source;
|
|
17278
17812
|
if (!cliType) throw new Error("cliType required");
|
|
17813
|
+
const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
|
|
17814
|
+
const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
|
|
17815
|
+
cliType,
|
|
17816
|
+
workspace: dir,
|
|
17817
|
+
cliArgs: args?.cliArgs,
|
|
17818
|
+
env: args?.env
|
|
17819
|
+
}) : null;
|
|
17279
17820
|
const started = await this.startSession(
|
|
17280
17821
|
cliType,
|
|
17281
17822
|
dir,
|
|
17282
|
-
args?.cliArgs,
|
|
17823
|
+
delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
|
|
17283
17824
|
args?.initialModel,
|
|
17284
|
-
{
|
|
17825
|
+
{
|
|
17826
|
+
resumeSessionId: args?.resumeSessionId,
|
|
17827
|
+
settingsOverride,
|
|
17828
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
17829
|
+
}
|
|
17285
17830
|
);
|
|
17286
17831
|
return {
|
|
17287
17832
|
success: true,
|
|
@@ -17403,11 +17948,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17403
17948
|
import { execSync as execSync4, spawn as spawn2 } from "child_process";
|
|
17404
17949
|
import * as net from "net";
|
|
17405
17950
|
import * as os15 from "os";
|
|
17406
|
-
import * as
|
|
17951
|
+
import * as path19 from "path";
|
|
17407
17952
|
|
|
17408
17953
|
// src/providers/provider-loader.ts
|
|
17409
17954
|
import * as fs7 from "fs";
|
|
17410
|
-
import * as
|
|
17955
|
+
import * as path18 from "path";
|
|
17411
17956
|
import * as os14 from "os";
|
|
17412
17957
|
import * as chokidar from "chokidar";
|
|
17413
17958
|
init_logger();
|
|
@@ -17731,7 +18276,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17731
18276
|
try {
|
|
17732
18277
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
17733
18278
|
return ["ide", "extension", "cli", "acp"].some(
|
|
17734
|
-
(category) => fs7.existsSync(
|
|
18279
|
+
(category) => fs7.existsSync(path18.join(candidate, category))
|
|
17735
18280
|
);
|
|
17736
18281
|
} catch {
|
|
17737
18282
|
return false;
|
|
@@ -17739,20 +18284,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17739
18284
|
}
|
|
17740
18285
|
static hasProviderRootMarker(candidate) {
|
|
17741
18286
|
try {
|
|
17742
|
-
return fs7.existsSync(
|
|
18287
|
+
return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
17743
18288
|
} catch {
|
|
17744
18289
|
return false;
|
|
17745
18290
|
}
|
|
17746
18291
|
}
|
|
17747
18292
|
detectDefaultUserDir() {
|
|
17748
|
-
const fallback =
|
|
18293
|
+
const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17749
18294
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17750
18295
|
const visited = /* @__PURE__ */ new Set();
|
|
17751
18296
|
for (const start of this.probeStarts) {
|
|
17752
|
-
let current =
|
|
18297
|
+
let current = path18.resolve(start);
|
|
17753
18298
|
while (!visited.has(current)) {
|
|
17754
18299
|
visited.add(current);
|
|
17755
|
-
const siblingCandidate =
|
|
18300
|
+
const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17756
18301
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17757
18302
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17758
18303
|
if (envOptIn || hasMarker) {
|
|
@@ -17774,7 +18319,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17774
18319
|
return { path: siblingCandidate, source };
|
|
17775
18320
|
}
|
|
17776
18321
|
}
|
|
17777
|
-
const parent =
|
|
18322
|
+
const parent = path18.dirname(current);
|
|
17778
18323
|
if (parent === current) break;
|
|
17779
18324
|
current = parent;
|
|
17780
18325
|
}
|
|
@@ -17784,11 +18329,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17784
18329
|
constructor(options) {
|
|
17785
18330
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17786
18331
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17787
|
-
this.defaultProvidersDir =
|
|
18332
|
+
this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17788
18333
|
const detected = this.detectDefaultUserDir();
|
|
17789
18334
|
this.userDir = detected.path;
|
|
17790
18335
|
this.userDirSource = detected.source;
|
|
17791
|
-
this.upstreamDir =
|
|
18336
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17792
18337
|
this.disableUpstream = false;
|
|
17793
18338
|
this.applySourceConfig({
|
|
17794
18339
|
userDir: options?.userDir,
|
|
@@ -17847,7 +18392,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17847
18392
|
this.userDir = detected.path;
|
|
17848
18393
|
this.userDirSource = detected.source;
|
|
17849
18394
|
}
|
|
17850
|
-
this.upstreamDir =
|
|
18395
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17851
18396
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
17852
18397
|
if (this.explicitProviderDir) {
|
|
17853
18398
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -17861,7 +18406,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17861
18406
|
* Canonical provider directory shape for a given root.
|
|
17862
18407
|
*/
|
|
17863
18408
|
getProviderDir(root, category, type) {
|
|
17864
|
-
return
|
|
18409
|
+
return path18.join(root, category, type);
|
|
17865
18410
|
}
|
|
17866
18411
|
/**
|
|
17867
18412
|
* Canonical user override directory for a provider.
|
|
@@ -17888,7 +18433,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17888
18433
|
resolveProviderFile(type, ...segments) {
|
|
17889
18434
|
const dir = this.findProviderDirInternal(type);
|
|
17890
18435
|
if (!dir) return null;
|
|
17891
|
-
return
|
|
18436
|
+
return path18.join(dir, ...segments);
|
|
17892
18437
|
}
|
|
17893
18438
|
/**
|
|
17894
18439
|
* Load all providers (3-tier priority)
|
|
@@ -17927,7 +18472,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17927
18472
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
17928
18473
|
try {
|
|
17929
18474
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
17930
|
-
(d) => fs7.statSync(
|
|
18475
|
+
(d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
|
|
17931
18476
|
);
|
|
17932
18477
|
} catch {
|
|
17933
18478
|
return false;
|
|
@@ -18424,8 +18969,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18424
18969
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
18425
18970
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
18426
18971
|
if (providerDir) {
|
|
18427
|
-
const fullDir =
|
|
18428
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18972
|
+
const fullDir = path18.join(providerDir, entry.scriptDir);
|
|
18973
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18429
18974
|
}
|
|
18430
18975
|
matched = true;
|
|
18431
18976
|
}
|
|
@@ -18440,8 +18985,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18440
18985
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18441
18986
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
18442
18987
|
if (providerDir) {
|
|
18443
|
-
const fullDir =
|
|
18444
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18988
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18989
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18445
18990
|
}
|
|
18446
18991
|
}
|
|
18447
18992
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -18458,8 +19003,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18458
19003
|
resolved._resolvedScriptDir = dirOverride;
|
|
18459
19004
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
18460
19005
|
if (providerDir) {
|
|
18461
|
-
const fullDir =
|
|
18462
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
19006
|
+
const fullDir = path18.join(providerDir, dirOverride);
|
|
19007
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18463
19008
|
}
|
|
18464
19009
|
}
|
|
18465
19010
|
} else if (override.scripts) {
|
|
@@ -18475,8 +19020,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18475
19020
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18476
19021
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
18477
19022
|
if (providerDir) {
|
|
18478
|
-
const fullDir =
|
|
18479
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
19023
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
19024
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18480
19025
|
}
|
|
18481
19026
|
}
|
|
18482
19027
|
}
|
|
@@ -18508,14 +19053,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18508
19053
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
18509
19054
|
return null;
|
|
18510
19055
|
}
|
|
18511
|
-
const dir =
|
|
19056
|
+
const dir = path18.join(providerDir, scriptDir);
|
|
18512
19057
|
if (!fs7.existsSync(dir)) {
|
|
18513
19058
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
18514
19059
|
return null;
|
|
18515
19060
|
}
|
|
18516
19061
|
const cached = this.scriptsCache.get(dir);
|
|
18517
19062
|
if (cached) return cached;
|
|
18518
|
-
const scriptsJs =
|
|
19063
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
18519
19064
|
if (fs7.existsSync(scriptsJs)) {
|
|
18520
19065
|
try {
|
|
18521
19066
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -18557,7 +19102,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18557
19102
|
return;
|
|
18558
19103
|
}
|
|
18559
19104
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
18560
|
-
this.log(`File changed: ${
|
|
19105
|
+
this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
|
|
18561
19106
|
this.reload();
|
|
18562
19107
|
}
|
|
18563
19108
|
};
|
|
@@ -18612,7 +19157,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18612
19157
|
}
|
|
18613
19158
|
const https = __require("https");
|
|
18614
19159
|
const { execSync: execSync7 } = __require("child_process");
|
|
18615
|
-
const metaPath =
|
|
19160
|
+
const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
18616
19161
|
let prevEtag = "";
|
|
18617
19162
|
let prevTimestamp = 0;
|
|
18618
19163
|
try {
|
|
@@ -18672,17 +19217,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18672
19217
|
return { updated: false };
|
|
18673
19218
|
}
|
|
18674
19219
|
this.log("Downloading latest providers from GitHub...");
|
|
18675
|
-
const tmpTar =
|
|
18676
|
-
const tmpExtract =
|
|
19220
|
+
const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
19221
|
+
const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
18677
19222
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
18678
19223
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
18679
19224
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
18680
19225
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
18681
19226
|
const rootDir = extracted.find(
|
|
18682
|
-
(d) => fs7.statSync(
|
|
19227
|
+
(d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
18683
19228
|
);
|
|
18684
19229
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
18685
|
-
const sourceDir =
|
|
19230
|
+
const sourceDir = path18.join(tmpExtract, rootDir);
|
|
18686
19231
|
const backupDir = this.upstreamDir + ".bak";
|
|
18687
19232
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
18688
19233
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -18757,8 +19302,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18757
19302
|
copyDirRecursive(src, dest) {
|
|
18758
19303
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18759
19304
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18760
|
-
const srcPath =
|
|
18761
|
-
const destPath =
|
|
19305
|
+
const srcPath = path18.join(src, entry.name);
|
|
19306
|
+
const destPath = path18.join(dest, entry.name);
|
|
18762
19307
|
if (entry.isDirectory()) {
|
|
18763
19308
|
this.copyDirRecursive(srcPath, destPath);
|
|
18764
19309
|
} else {
|
|
@@ -18769,7 +19314,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18769
19314
|
/** .meta.json save */
|
|
18770
19315
|
writeMeta(metaPath, etag, timestamp) {
|
|
18771
19316
|
try {
|
|
18772
|
-
fs7.mkdirSync(
|
|
19317
|
+
fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
|
|
18773
19318
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18774
19319
|
etag,
|
|
18775
19320
|
timestamp,
|
|
@@ -18786,7 +19331,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18786
19331
|
const scan = (d) => {
|
|
18787
19332
|
try {
|
|
18788
19333
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18789
|
-
if (entry.isDirectory()) scan(
|
|
19334
|
+
if (entry.isDirectory()) scan(path18.join(d, entry.name));
|
|
18790
19335
|
else if (entry.name === "provider.json") count++;
|
|
18791
19336
|
}
|
|
18792
19337
|
} catch {
|
|
@@ -19014,17 +19559,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19014
19559
|
for (const root of searchRoots) {
|
|
19015
19560
|
if (!fs7.existsSync(root)) continue;
|
|
19016
19561
|
const candidate = this.getProviderDir(root, cat, type);
|
|
19017
|
-
if (fs7.existsSync(
|
|
19018
|
-
const catDir =
|
|
19562
|
+
if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
|
|
19563
|
+
const catDir = path18.join(root, cat);
|
|
19019
19564
|
if (fs7.existsSync(catDir)) {
|
|
19020
19565
|
try {
|
|
19021
19566
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
19022
19567
|
if (!entry.isDirectory()) continue;
|
|
19023
|
-
const jsonPath =
|
|
19568
|
+
const jsonPath = path18.join(catDir, entry.name, "provider.json");
|
|
19024
19569
|
if (fs7.existsSync(jsonPath)) {
|
|
19025
19570
|
try {
|
|
19026
19571
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
19027
|
-
if (data.type === type) return
|
|
19572
|
+
if (data.type === type) return path18.join(catDir, entry.name);
|
|
19028
19573
|
} catch {
|
|
19029
19574
|
}
|
|
19030
19575
|
}
|
|
@@ -19041,7 +19586,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19041
19586
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
19042
19587
|
*/
|
|
19043
19588
|
buildScriptWrappersFromDir(dir) {
|
|
19044
|
-
const scriptsJs =
|
|
19589
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
19045
19590
|
if (fs7.existsSync(scriptsJs)) {
|
|
19046
19591
|
try {
|
|
19047
19592
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -19055,7 +19600,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19055
19600
|
for (const file of fs7.readdirSync(dir)) {
|
|
19056
19601
|
if (!file.endsWith(".js")) continue;
|
|
19057
19602
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
19058
|
-
const filePath =
|
|
19603
|
+
const filePath = path18.join(dir, file);
|
|
19059
19604
|
result[scriptName] = (...args) => {
|
|
19060
19605
|
try {
|
|
19061
19606
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -19115,7 +19660,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19115
19660
|
}
|
|
19116
19661
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
19117
19662
|
if (hasJson) {
|
|
19118
|
-
const jsonPath =
|
|
19663
|
+
const jsonPath = path18.join(d, "provider.json");
|
|
19119
19664
|
try {
|
|
19120
19665
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
19121
19666
|
const mod = JSON.parse(raw);
|
|
@@ -19136,7 +19681,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19136
19681
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
19137
19682
|
} else {
|
|
19138
19683
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
19139
|
-
const scriptsPath =
|
|
19684
|
+
const scriptsPath = path18.join(d, "scripts.js");
|
|
19140
19685
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
19141
19686
|
try {
|
|
19142
19687
|
delete __require.cache[__require.resolve(scriptsPath)];
|
|
@@ -19162,7 +19707,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19162
19707
|
if (!entry.isDirectory()) continue;
|
|
19163
19708
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
19164
19709
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
19165
|
-
scan(
|
|
19710
|
+
scan(path18.join(d, entry.name));
|
|
19166
19711
|
}
|
|
19167
19712
|
}
|
|
19168
19713
|
};
|
|
@@ -19487,8 +20032,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
19487
20032
|
const appNameMap = getMacAppIdentifiers();
|
|
19488
20033
|
const appName = appNameMap[ideId];
|
|
19489
20034
|
if (appName) {
|
|
19490
|
-
const storagePath =
|
|
19491
|
-
process.env.APPDATA ||
|
|
20035
|
+
const storagePath = path19.join(
|
|
20036
|
+
process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
|
|
19492
20037
|
appName,
|
|
19493
20038
|
"storage.json"
|
|
19494
20039
|
);
|
|
@@ -19677,9 +20222,9 @@ init_logger();
|
|
|
19677
20222
|
|
|
19678
20223
|
// src/logging/command-log.ts
|
|
19679
20224
|
import * as fs8 from "fs";
|
|
19680
|
-
import * as
|
|
20225
|
+
import * as path20 from "path";
|
|
19681
20226
|
import * as os16 from "os";
|
|
19682
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
20227
|
+
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
20228
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
19684
20229
|
var MAX_DAYS = 7;
|
|
19685
20230
|
try {
|
|
@@ -19717,13 +20262,13 @@ function getDateStr2() {
|
|
|
19717
20262
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19718
20263
|
}
|
|
19719
20264
|
var currentDate2 = getDateStr2();
|
|
19720
|
-
var currentFile =
|
|
20265
|
+
var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19721
20266
|
var writeCount2 = 0;
|
|
19722
20267
|
function checkRotation() {
|
|
19723
20268
|
const today = getDateStr2();
|
|
19724
20269
|
if (today !== currentDate2) {
|
|
19725
20270
|
currentDate2 = today;
|
|
19726
|
-
currentFile =
|
|
20271
|
+
currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19727
20272
|
cleanOldFiles();
|
|
19728
20273
|
}
|
|
19729
20274
|
}
|
|
@@ -19737,7 +20282,7 @@ function cleanOldFiles() {
|
|
|
19737
20282
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
19738
20283
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
19739
20284
|
try {
|
|
19740
|
-
fs8.unlinkSync(
|
|
20285
|
+
fs8.unlinkSync(path20.join(LOG_DIR2, file));
|
|
19741
20286
|
} catch {
|
|
19742
20287
|
}
|
|
19743
20288
|
}
|
|
@@ -19821,13 +20366,65 @@ cleanOldFiles();
|
|
|
19821
20366
|
|
|
19822
20367
|
// src/commands/router.ts
|
|
19823
20368
|
init_logger();
|
|
20369
|
+
import * as yaml from "js-yaml";
|
|
19824
20370
|
|
|
19825
20371
|
// src/commands/mesh-coordinator.ts
|
|
19826
|
-
import {
|
|
20372
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
20373
|
+
import { existsSync as existsSync15, readdirSync as readdirSync6, realpathSync as realpathSync2 } from "fs";
|
|
19827
20374
|
import { createRequire as createRequire2 } from "module";
|
|
19828
|
-
import
|
|
20375
|
+
import * as os17 from "os";
|
|
20376
|
+
import { dirname as dirname4, isAbsolute as isAbsolute10, join as join18, resolve as resolve13 } from "path";
|
|
19829
20377
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
19830
20378
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20379
|
+
var HERMES_CLI_TYPE = "hermes-cli";
|
|
20380
|
+
var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
|
|
20381
|
+
function isHermesProvider(provider, cliType) {
|
|
20382
|
+
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
20383
|
+
return type === HERMES_CLI_TYPE;
|
|
20384
|
+
}
|
|
20385
|
+
function resolveHermesMeshCoordinatorSetup(options) {
|
|
20386
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
20387
|
+
meshId: options.meshId,
|
|
20388
|
+
nodeExecutable: options.nodeExecutable,
|
|
20389
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath
|
|
20390
|
+
});
|
|
20391
|
+
if (!mcpServer) {
|
|
20392
|
+
return {
|
|
20393
|
+
kind: "unsupported",
|
|
20394
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20395
|
+
};
|
|
20396
|
+
}
|
|
20397
|
+
const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
|
|
20398
|
+
if (!configPath.trim()) {
|
|
20399
|
+
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20400
|
+
}
|
|
20401
|
+
return {
|
|
20402
|
+
kind: "auto_import",
|
|
20403
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20404
|
+
configPath,
|
|
20405
|
+
configFormat: "hermes_config_yaml",
|
|
20406
|
+
mcpServer
|
|
20407
|
+
};
|
|
20408
|
+
}
|
|
20409
|
+
function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
|
|
20410
|
+
return {
|
|
20411
|
+
kind: "manual",
|
|
20412
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20413
|
+
configFormat: "hermes_config_yaml",
|
|
20414
|
+
configPathCommand: HERMES_MCP_CONFIG_PATH,
|
|
20415
|
+
requiresRestart: true,
|
|
20416
|
+
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.",
|
|
20417
|
+
template: renderMeshCoordinatorTemplate(
|
|
20418
|
+
"mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
|
|
20419
|
+
{
|
|
20420
|
+
meshId,
|
|
20421
|
+
workspace,
|
|
20422
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20423
|
+
adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
|
|
20424
|
+
}
|
|
20425
|
+
)
|
|
20426
|
+
};
|
|
20427
|
+
}
|
|
19831
20428
|
function resolveMeshCoordinatorSetup(options) {
|
|
19832
20429
|
const { provider, meshId, workspace } = options;
|
|
19833
20430
|
const config = provider?.meshCoordinator;
|
|
@@ -19837,6 +20434,9 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19837
20434
|
reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
|
|
19838
20435
|
};
|
|
19839
20436
|
}
|
|
20437
|
+
if (isHermesProvider(provider, options.cliType)) {
|
|
20438
|
+
return resolveHermesMeshCoordinatorSetup(options);
|
|
20439
|
+
}
|
|
19840
20440
|
const mcpConfig = config.mcpConfig;
|
|
19841
20441
|
if (!mcpConfig || mcpConfig.mode === "none") {
|
|
19842
20442
|
return {
|
|
@@ -19846,8 +20446,8 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19846
20446
|
}
|
|
19847
20447
|
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
|
|
19848
20448
|
if (mcpConfig.mode === "auto_import") {
|
|
19849
|
-
const
|
|
19850
|
-
if (!
|
|
20449
|
+
const path27 = mcpConfig.path?.trim();
|
|
20450
|
+
if (!path27) {
|
|
19851
20451
|
return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
|
|
19852
20452
|
}
|
|
19853
20453
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
@@ -19858,13 +20458,13 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19858
20458
|
if (!mcpServer) {
|
|
19859
20459
|
return {
|
|
19860
20460
|
kind: "unsupported",
|
|
19861
|
-
reason: "Could not resolve the ADHDev MCP server entrypoint
|
|
20461
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
19862
20462
|
};
|
|
19863
20463
|
}
|
|
19864
20464
|
return {
|
|
19865
20465
|
kind: "auto_import",
|
|
19866
20466
|
serverName,
|
|
19867
|
-
configPath:
|
|
20467
|
+
configPath: resolveMcpConfigPath(path27, workspace),
|
|
19868
20468
|
configFormat: mcpConfig.format,
|
|
19869
20469
|
mcpServer
|
|
19870
20470
|
};
|
|
@@ -19898,14 +20498,85 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19898
20498
|
function renderMeshCoordinatorTemplate(template, values) {
|
|
19899
20499
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
|
|
19900
20500
|
}
|
|
20501
|
+
function resolveMcpConfigPath(configPath, workspace) {
|
|
20502
|
+
const trimmed = configPath.trim();
|
|
20503
|
+
if (trimmed === "~") return os17.homedir();
|
|
20504
|
+
if (trimmed.startsWith("~/")) return join18(os17.homedir(), trimmed.slice(2));
|
|
20505
|
+
if (isAbsolute10(trimmed)) return trimmed;
|
|
20506
|
+
return join18(workspace, trimmed);
|
|
20507
|
+
}
|
|
19901
20508
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
19902
20509
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
19903
20510
|
if (!entryPath) return null;
|
|
20511
|
+
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
|
|
20512
|
+
if (!nodeExecutable) return null;
|
|
19904
20513
|
return {
|
|
19905
|
-
command:
|
|
20514
|
+
command: nodeExecutable,
|
|
19906
20515
|
args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
|
|
19907
20516
|
};
|
|
19908
20517
|
}
|
|
20518
|
+
function resolveMcpNodeExecutable(explicitExecutable) {
|
|
20519
|
+
const explicit = explicitExecutable?.trim();
|
|
20520
|
+
if (explicit) return explicit;
|
|
20521
|
+
const candidates = [];
|
|
20522
|
+
const addCandidate = (candidate) => {
|
|
20523
|
+
const trimmed = candidate?.trim();
|
|
20524
|
+
if (!trimmed) return;
|
|
20525
|
+
const normalized = normalizeExistingPath(trimmed) || trimmed;
|
|
20526
|
+
if (!candidates.includes(normalized)) candidates.push(normalized);
|
|
20527
|
+
};
|
|
20528
|
+
addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
|
|
20529
|
+
addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
|
|
20530
|
+
addCandidate(process.env.npm_node_execpath);
|
|
20531
|
+
addNodeCandidatesFromPath(process.env.PATH, addCandidate);
|
|
20532
|
+
addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
|
|
20533
|
+
addCandidate("/opt/homebrew/bin/node");
|
|
20534
|
+
addCandidate("/usr/local/bin/node");
|
|
20535
|
+
addCandidate("/usr/bin/node");
|
|
20536
|
+
addCandidate(process.execPath);
|
|
20537
|
+
for (const candidate of candidates) {
|
|
20538
|
+
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
|
|
20539
|
+
}
|
|
20540
|
+
return null;
|
|
20541
|
+
}
|
|
20542
|
+
function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
20543
|
+
for (const entry of (pathValue || "").split(":")) {
|
|
20544
|
+
const dir = entry.trim();
|
|
20545
|
+
if (!dir) continue;
|
|
20546
|
+
addCandidate(join18(dir, "node"));
|
|
20547
|
+
}
|
|
20548
|
+
}
|
|
20549
|
+
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
20550
|
+
const versionsDir = join18(homeDir, ".nvm", "versions", "node");
|
|
20551
|
+
try {
|
|
20552
|
+
const versionDirs = readdirSync6(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
20553
|
+
for (const versionDir of versionDirs) {
|
|
20554
|
+
addCandidate(join18(versionsDir, versionDir, "bin", "node"));
|
|
20555
|
+
}
|
|
20556
|
+
} catch {
|
|
20557
|
+
}
|
|
20558
|
+
}
|
|
20559
|
+
function compareNodeVersionNamesDescending(a, b) {
|
|
20560
|
+
const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
20561
|
+
const left = parse(a);
|
|
20562
|
+
const right = parse(b);
|
|
20563
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
20564
|
+
const diff = (right[i] || 0) - (left[i] || 0);
|
|
20565
|
+
if (diff !== 0) return diff;
|
|
20566
|
+
}
|
|
20567
|
+
return b.localeCompare(a);
|
|
20568
|
+
}
|
|
20569
|
+
function nodeRuntimeSupportsWebSocket(nodeExecutable) {
|
|
20570
|
+
try {
|
|
20571
|
+
execFileSync2(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
|
|
20572
|
+
stdio: "ignore",
|
|
20573
|
+
timeout: 3e3
|
|
20574
|
+
});
|
|
20575
|
+
return true;
|
|
20576
|
+
} catch {
|
|
20577
|
+
return false;
|
|
20578
|
+
}
|
|
20579
|
+
}
|
|
19909
20580
|
function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
19910
20581
|
const explicit = explicitPath?.trim();
|
|
19911
20582
|
if (explicit) return normalizeExistingPath(explicit) || explicit;
|
|
@@ -19918,7 +20589,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19918
20589
|
const addPackagedCandidates = (baseFile) => {
|
|
19919
20590
|
if (!baseFile) return;
|
|
19920
20591
|
const realBase = normalizeExistingPath(baseFile) || baseFile;
|
|
19921
|
-
const dir =
|
|
20592
|
+
const dir = dirname4(realBase);
|
|
19922
20593
|
addCandidate(resolve13(dir, "../vendor/mcp-server/index.js"));
|
|
19923
20594
|
addCandidate(resolve13(dir, "../../vendor/mcp-server/index.js"));
|
|
19924
20595
|
addCandidate(resolve13(dir, "../../../vendor/mcp-server/index.js"));
|
|
@@ -19931,7 +20602,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19931
20602
|
if (normalized) return normalized;
|
|
19932
20603
|
}
|
|
19933
20604
|
try {
|
|
19934
|
-
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] :
|
|
20605
|
+
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join18(process.cwd(), "adhdev-daemon.js");
|
|
19935
20606
|
const req = createRequire2(requireBase);
|
|
19936
20607
|
const resolvedModule = req.resolve("@adhdev/mcp-server");
|
|
19937
20608
|
return normalizeExistingPath(resolvedModule) || resolvedModule;
|
|
@@ -19941,16 +20612,110 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19941
20612
|
}
|
|
19942
20613
|
function normalizeExistingPath(filePath) {
|
|
19943
20614
|
try {
|
|
19944
|
-
if (!
|
|
20615
|
+
if (!existsSync15(filePath)) return null;
|
|
19945
20616
|
return realpathSync2.native(filePath);
|
|
19946
20617
|
} catch {
|
|
19947
20618
|
return null;
|
|
19948
20619
|
}
|
|
19949
20620
|
}
|
|
19950
20621
|
|
|
20622
|
+
// src/mesh/mesh-events.ts
|
|
20623
|
+
init_mesh_config();
|
|
20624
|
+
init_logger();
|
|
20625
|
+
function readNonEmptyString(value) {
|
|
20626
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
20627
|
+
}
|
|
20628
|
+
function formatCompletionMetadata(event) {
|
|
20629
|
+
const parts = [
|
|
20630
|
+
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
20631
|
+
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
20632
|
+
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
20633
|
+
].filter(Boolean);
|
|
20634
|
+
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
20635
|
+
}
|
|
20636
|
+
function buildMeshSystemMessage(args) {
|
|
20637
|
+
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
20638
|
+
if (args.event === "agent:generating_completed") {
|
|
20639
|
+
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.`;
|
|
20640
|
+
}
|
|
20641
|
+
if (args.event === "agent:waiting_approval") {
|
|
20642
|
+
return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
20643
|
+
}
|
|
20644
|
+
return "";
|
|
20645
|
+
}
|
|
20646
|
+
function injectMeshSystemMessage(components, args) {
|
|
20647
|
+
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
20648
|
+
const instState = inst.getState();
|
|
20649
|
+
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
20650
|
+
if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
|
|
20651
|
+
return true;
|
|
20652
|
+
});
|
|
20653
|
+
if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
|
|
20654
|
+
const messageText = buildMeshSystemMessage({
|
|
20655
|
+
event: args.event,
|
|
20656
|
+
nodeLabel: args.nodeLabel,
|
|
20657
|
+
metadataEvent: args.metadataEvent
|
|
20658
|
+
});
|
|
20659
|
+
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
20660
|
+
for (const coord of coordinatorInstances) {
|
|
20661
|
+
const coordState = coord.getState();
|
|
20662
|
+
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
20663
|
+
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
20664
|
+
}
|
|
20665
|
+
return { success: true, forwarded: coordinatorInstances.length };
|
|
20666
|
+
}
|
|
20667
|
+
function handleMeshForwardEvent(components, payload) {
|
|
20668
|
+
const eventName = readNonEmptyString(payload.event);
|
|
20669
|
+
if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
|
|
20670
|
+
return { success: false, error: "unsupported mesh event" };
|
|
20671
|
+
}
|
|
20672
|
+
const meshId = readNonEmptyString(payload.meshId);
|
|
20673
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
20674
|
+
const nodeId = readNonEmptyString(payload.nodeId);
|
|
20675
|
+
const workspace = readNonEmptyString(payload.workspace);
|
|
20676
|
+
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
20677
|
+
return injectMeshSystemMessage(components, {
|
|
20678
|
+
meshId,
|
|
20679
|
+
nodeLabel,
|
|
20680
|
+
event: eventName,
|
|
20681
|
+
metadataEvent: {
|
|
20682
|
+
targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
|
|
20683
|
+
providerType: readNonEmptyString(payload.providerType),
|
|
20684
|
+
providerSessionId: readNonEmptyString(payload.providerSessionId)
|
|
20685
|
+
}
|
|
20686
|
+
});
|
|
20687
|
+
}
|
|
20688
|
+
function setupMeshEventForwarding(components) {
|
|
20689
|
+
components.instanceManager.onEvent((event) => {
|
|
20690
|
+
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
20691
|
+
const instanceId = readNonEmptyString(event.instanceId);
|
|
20692
|
+
if (!instanceId) return;
|
|
20693
|
+
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
20694
|
+
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
20695
|
+
const state = sourceInstance.getState();
|
|
20696
|
+
const workspace = readNonEmptyString(state.workspace);
|
|
20697
|
+
if (!workspace) return;
|
|
20698
|
+
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
20699
|
+
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
20700
|
+
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
20701
|
+
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
20702
|
+
if (!meshId) return;
|
|
20703
|
+
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
20704
|
+
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
20705
|
+
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
20706
|
+
injectMeshSystemMessage(components, {
|
|
20707
|
+
meshId,
|
|
20708
|
+
sourceInstanceId: instanceId,
|
|
20709
|
+
nodeLabel,
|
|
20710
|
+
event: event.event,
|
|
20711
|
+
metadataEvent: event
|
|
20712
|
+
});
|
|
20713
|
+
});
|
|
20714
|
+
}
|
|
20715
|
+
|
|
19951
20716
|
// src/status/snapshot.ts
|
|
19952
20717
|
init_config();
|
|
19953
|
-
import * as
|
|
20718
|
+
import * as os18 from "os";
|
|
19954
20719
|
init_terminal_screen();
|
|
19955
20720
|
init_logger();
|
|
19956
20721
|
var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
|
|
@@ -20005,8 +20770,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20005
20770
|
}
|
|
20006
20771
|
function buildMachineInfo(profile = "full") {
|
|
20007
20772
|
const base = {
|
|
20008
|
-
hostname:
|
|
20009
|
-
platform:
|
|
20773
|
+
hostname: os18.hostname(),
|
|
20774
|
+
platform: os18.platform()
|
|
20010
20775
|
};
|
|
20011
20776
|
if (profile === "live") {
|
|
20012
20777
|
return base;
|
|
@@ -20015,23 +20780,23 @@ function buildMachineInfo(profile = "full") {
|
|
|
20015
20780
|
const memSnap2 = getHostMemorySnapshot();
|
|
20016
20781
|
return {
|
|
20017
20782
|
...base,
|
|
20018
|
-
arch:
|
|
20019
|
-
cpus:
|
|
20783
|
+
arch: os18.arch(),
|
|
20784
|
+
cpus: os18.cpus().length,
|
|
20020
20785
|
totalMem: memSnap2.totalMem,
|
|
20021
|
-
release:
|
|
20786
|
+
release: os18.release()
|
|
20022
20787
|
};
|
|
20023
20788
|
}
|
|
20024
20789
|
const memSnap = getHostMemorySnapshot();
|
|
20025
20790
|
return {
|
|
20026
20791
|
...base,
|
|
20027
|
-
arch:
|
|
20028
|
-
cpus:
|
|
20792
|
+
arch: os18.arch(),
|
|
20793
|
+
cpus: os18.cpus().length,
|
|
20029
20794
|
totalMem: memSnap.totalMem,
|
|
20030
20795
|
freeMem: memSnap.freeMem,
|
|
20031
20796
|
availableMem: memSnap.availableMem,
|
|
20032
|
-
loadavg:
|
|
20033
|
-
uptime:
|
|
20034
|
-
release:
|
|
20797
|
+
loadavg: os18.loadavg(),
|
|
20798
|
+
uptime: os18.uptime(),
|
|
20799
|
+
release: os18.release()
|
|
20035
20800
|
};
|
|
20036
20801
|
}
|
|
20037
20802
|
function parseMessageTime(value) {
|
|
@@ -20262,17 +21027,17 @@ function buildStatusSnapshot(options) {
|
|
|
20262
21027
|
}
|
|
20263
21028
|
|
|
20264
21029
|
// src/commands/upgrade-helper.ts
|
|
20265
|
-
import { execFileSync as
|
|
21030
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
20266
21031
|
import { spawn as spawn3 } from "child_process";
|
|
20267
21032
|
import * as fs9 from "fs";
|
|
20268
|
-
import * as
|
|
20269
|
-
import * as
|
|
21033
|
+
import * as os19 from "os";
|
|
21034
|
+
import * as path21 from "path";
|
|
20270
21035
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
20271
21036
|
function getUpgradeLogPath() {
|
|
20272
|
-
const home =
|
|
20273
|
-
const dir =
|
|
21037
|
+
const home = os19.homedir();
|
|
21038
|
+
const dir = path21.join(home, ".adhdev");
|
|
20274
21039
|
fs9.mkdirSync(dir, { recursive: true });
|
|
20275
|
-
return
|
|
21040
|
+
return path21.join(dir, "daemon-upgrade.log");
|
|
20276
21041
|
}
|
|
20277
21042
|
function appendUpgradeLog(message) {
|
|
20278
21043
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -20283,14 +21048,14 @@ function appendUpgradeLog(message) {
|
|
|
20283
21048
|
}
|
|
20284
21049
|
}
|
|
20285
21050
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
20286
|
-
const binDir =
|
|
21051
|
+
const binDir = path21.dirname(nodeExecutable);
|
|
20287
21052
|
if (platform10 === "win32") {
|
|
20288
|
-
const npmCliPath =
|
|
21053
|
+
const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
20289
21054
|
if (fs9.existsSync(npmCliPath)) {
|
|
20290
21055
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20291
21056
|
}
|
|
20292
21057
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
20293
|
-
const candidatePath =
|
|
21058
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20294
21059
|
if (fs9.existsSync(candidatePath)) {
|
|
20295
21060
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20296
21061
|
}
|
|
@@ -20298,7 +21063,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
20298
21063
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20299
21064
|
}
|
|
20300
21065
|
for (const candidate of ["npm"]) {
|
|
20301
|
-
const candidatePath =
|
|
21066
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20302
21067
|
if (fs9.existsSync(candidatePath)) {
|
|
20303
21068
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20304
21069
|
}
|
|
@@ -20315,13 +21080,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20315
21080
|
let currentDir = resolvedPath;
|
|
20316
21081
|
try {
|
|
20317
21082
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
20318
|
-
currentDir =
|
|
21083
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20319
21084
|
}
|
|
20320
21085
|
} catch {
|
|
20321
|
-
currentDir =
|
|
21086
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20322
21087
|
}
|
|
20323
21088
|
while (true) {
|
|
20324
|
-
const packageJsonPath =
|
|
21089
|
+
const packageJsonPath = path21.join(currentDir, "package.json");
|
|
20325
21090
|
try {
|
|
20326
21091
|
if (fs9.existsSync(packageJsonPath)) {
|
|
20327
21092
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -20332,7 +21097,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20332
21097
|
}
|
|
20333
21098
|
} catch {
|
|
20334
21099
|
}
|
|
20335
|
-
const parentDir =
|
|
21100
|
+
const parentDir = path21.dirname(currentDir);
|
|
20336
21101
|
if (parentDir === currentDir) {
|
|
20337
21102
|
return null;
|
|
20338
21103
|
}
|
|
@@ -20340,13 +21105,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20340
21105
|
}
|
|
20341
21106
|
}
|
|
20342
21107
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
20343
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
20344
|
-
if (
|
|
21108
|
+
const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
|
|
21109
|
+
if (path21.basename(nodeModulesDir) !== "node_modules") {
|
|
20345
21110
|
return null;
|
|
20346
21111
|
}
|
|
20347
|
-
const maybeLibDir =
|
|
20348
|
-
if (
|
|
20349
|
-
return
|
|
21112
|
+
const maybeLibDir = path21.dirname(nodeModulesDir);
|
|
21113
|
+
if (path21.basename(maybeLibDir) === "lib") {
|
|
21114
|
+
return path21.dirname(maybeLibDir);
|
|
20350
21115
|
}
|
|
20351
21116
|
return maybeLibDir;
|
|
20352
21117
|
}
|
|
@@ -20382,7 +21147,7 @@ function getNpmExecOptions(platform10 = process.platform) {
|
|
|
20382
21147
|
}
|
|
20383
21148
|
function execNpmCommandSync(args, options = {}, surface) {
|
|
20384
21149
|
const execOptions = surface?.execOptions || getNpmExecOptions();
|
|
20385
|
-
return
|
|
21150
|
+
return execFileSync3(
|
|
20386
21151
|
surface?.npmExecutable || "npm",
|
|
20387
21152
|
[...surface?.npmArgsPrefix || [], ...args],
|
|
20388
21153
|
{
|
|
@@ -20395,7 +21160,7 @@ function execNpmCommandSync(args, options = {}, surface) {
|
|
|
20395
21160
|
function killPid(pid) {
|
|
20396
21161
|
try {
|
|
20397
21162
|
if (process.platform === "win32") {
|
|
20398
|
-
|
|
21163
|
+
execFileSync3("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
|
|
20399
21164
|
} else {
|
|
20400
21165
|
process.kill(pid, "SIGTERM");
|
|
20401
21166
|
}
|
|
@@ -20407,7 +21172,7 @@ function killPid(pid) {
|
|
|
20407
21172
|
function getWindowsProcessCommandLine(pid) {
|
|
20408
21173
|
const pidFilter = `ProcessId=${pid}`;
|
|
20409
21174
|
try {
|
|
20410
|
-
const psOut =
|
|
21175
|
+
const psOut = execFileSync3("powershell.exe", [
|
|
20411
21176
|
"-NoProfile",
|
|
20412
21177
|
"-NonInteractive",
|
|
20413
21178
|
"-ExecutionPolicy",
|
|
@@ -20419,7 +21184,7 @@ function getWindowsProcessCommandLine(pid) {
|
|
|
20419
21184
|
} catch {
|
|
20420
21185
|
}
|
|
20421
21186
|
try {
|
|
20422
|
-
const wmicOut =
|
|
21187
|
+
const wmicOut = execFileSync3("wmic", [
|
|
20423
21188
|
"process",
|
|
20424
21189
|
"where",
|
|
20425
21190
|
pidFilter,
|
|
@@ -20435,7 +21200,7 @@ function getProcessCommandLine(pid) {
|
|
|
20435
21200
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
20436
21201
|
if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
|
|
20437
21202
|
try {
|
|
20438
|
-
const text =
|
|
21203
|
+
const text = execFileSync3("ps", ["-o", "command=", "-p", String(pid)], {
|
|
20439
21204
|
encoding: "utf8",
|
|
20440
21205
|
timeout: 3e3,
|
|
20441
21206
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -20461,7 +21226,7 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
20461
21226
|
}
|
|
20462
21227
|
}
|
|
20463
21228
|
function stopSessionHostProcesses(appName) {
|
|
20464
|
-
const pidFile =
|
|
21229
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
20465
21230
|
try {
|
|
20466
21231
|
if (fs9.existsSync(pidFile)) {
|
|
20467
21232
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -20478,7 +21243,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
20478
21243
|
}
|
|
20479
21244
|
}
|
|
20480
21245
|
function removeDaemonPidFile() {
|
|
20481
|
-
const pidFile =
|
|
21246
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
20482
21247
|
try {
|
|
20483
21248
|
fs9.unlinkSync(pidFile);
|
|
20484
21249
|
} catch {
|
|
@@ -20489,7 +21254,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20489
21254
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20490
21255
|
if (!npmRoot) return;
|
|
20491
21256
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20492
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
21257
|
+
const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
|
|
20493
21258
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
20494
21259
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
20495
21260
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -20497,25 +21262,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20497
21262
|
}
|
|
20498
21263
|
if (pkgName.startsWith("@")) {
|
|
20499
21264
|
const [scope, name] = pkgName.split("/");
|
|
20500
|
-
const scopeDir =
|
|
21265
|
+
const scopeDir = path21.join(npmRoot, scope);
|
|
20501
21266
|
if (!fs9.existsSync(scopeDir)) return;
|
|
20502
21267
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
20503
21268
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
20504
|
-
fs9.rmSync(
|
|
20505
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
21269
|
+
fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
|
|
21270
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
|
|
20506
21271
|
}
|
|
20507
21272
|
} else {
|
|
20508
21273
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
20509
21274
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
20510
|
-
fs9.rmSync(
|
|
20511
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
21275
|
+
fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
|
|
21276
|
+
appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
|
|
20512
21277
|
}
|
|
20513
21278
|
}
|
|
20514
21279
|
if (fs9.existsSync(binDir)) {
|
|
20515
21280
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
20516
21281
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
20517
|
-
fs9.rmSync(
|
|
20518
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
21282
|
+
fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
|
|
21283
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
|
|
20519
21284
|
}
|
|
20520
21285
|
}
|
|
20521
21286
|
}
|
|
@@ -20551,7 +21316,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
20551
21316
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
20552
21317
|
const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
|
|
20553
21318
|
appendUpgradeLog(`Installing ${spec}`);
|
|
20554
|
-
const installOutput =
|
|
21319
|
+
const installOutput = execFileSync3(
|
|
20555
21320
|
installCommand.command,
|
|
20556
21321
|
installCommand.args,
|
|
20557
21322
|
{
|
|
@@ -20616,6 +21381,56 @@ function normalizeReleaseChannel(value) {
|
|
|
20616
21381
|
function resolveUpgradeChannel(args) {
|
|
20617
21382
|
return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
|
|
20618
21383
|
}
|
|
21384
|
+
function readProviderPriorityFromPolicy(policy) {
|
|
21385
|
+
const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
|
|
21386
|
+
const raw = record.providerPriority;
|
|
21387
|
+
if (!Array.isArray(raw)) return [];
|
|
21388
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21389
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
21390
|
+
if (seen.has(type)) return false;
|
|
21391
|
+
seen.add(type);
|
|
21392
|
+
return true;
|
|
21393
|
+
});
|
|
21394
|
+
}
|
|
21395
|
+
async function resolveProviderTypeFromPriority(args) {
|
|
21396
|
+
if (!args.providerPriority.length) {
|
|
21397
|
+
return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
|
|
21398
|
+
}
|
|
21399
|
+
const failed = [];
|
|
21400
|
+
for (const requestedType of args.providerPriority) {
|
|
21401
|
+
const normalizedType = args.providerLoader.resolveAlias(requestedType);
|
|
21402
|
+
if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
21403
|
+
failed.push(`${requestedType}: disabled`);
|
|
21404
|
+
continue;
|
|
21405
|
+
}
|
|
21406
|
+
const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
|
|
21407
|
+
args.providerLoader.setCliDetectionResults([{
|
|
21408
|
+
id: normalizedType,
|
|
21409
|
+
installed: !!detected,
|
|
21410
|
+
path: detected?.path
|
|
21411
|
+
}], false);
|
|
21412
|
+
args.onStatusChange?.();
|
|
21413
|
+
if (detected) return { providerType: normalizedType };
|
|
21414
|
+
failed.push(`${requestedType}: not detected`);
|
|
21415
|
+
}
|
|
21416
|
+
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
21417
|
+
}
|
|
21418
|
+
function loadYamlModule() {
|
|
21419
|
+
return yaml;
|
|
21420
|
+
}
|
|
21421
|
+
function getMcpServersKey(format) {
|
|
21422
|
+
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
21423
|
+
}
|
|
21424
|
+
function parseMeshCoordinatorMcpConfig(text, format) {
|
|
21425
|
+
if (!text.trim()) return {};
|
|
21426
|
+
if (format === "claude_mcp_json") return JSON.parse(text);
|
|
21427
|
+
const parsed = loadYamlModule().load(text);
|
|
21428
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
21429
|
+
}
|
|
21430
|
+
function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
21431
|
+
if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
|
|
21432
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
21433
|
+
}
|
|
20619
21434
|
var CHAT_COMMANDS = [
|
|
20620
21435
|
"send_chat",
|
|
20621
21436
|
"new_chat",
|
|
@@ -20714,6 +21529,154 @@ var DaemonCommandRouter = class {
|
|
|
20714
21529
|
constructor(deps) {
|
|
20715
21530
|
this.deps = deps;
|
|
20716
21531
|
}
|
|
21532
|
+
getCachedInlineMesh(meshId, inlineMesh) {
|
|
21533
|
+
if (inlineMesh && typeof inlineMesh === "object") {
|
|
21534
|
+
this.inlineMeshCache.set(meshId, inlineMesh);
|
|
21535
|
+
return inlineMesh;
|
|
21536
|
+
}
|
|
21537
|
+
return this.inlineMeshCache.get(meshId);
|
|
21538
|
+
}
|
|
21539
|
+
async getMeshForCommand(meshId, inlineMesh) {
|
|
21540
|
+
try {
|
|
21541
|
+
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21542
|
+
const mesh = getMesh3(meshId);
|
|
21543
|
+
if (mesh) return { mesh, inline: false };
|
|
21544
|
+
} catch {
|
|
21545
|
+
}
|
|
21546
|
+
const cached = this.getCachedInlineMesh(meshId, inlineMesh);
|
|
21547
|
+
return cached ? { mesh: cached, inline: true } : null;
|
|
21548
|
+
}
|
|
21549
|
+
updateInlineMeshNode(meshId, mesh, node) {
|
|
21550
|
+
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
21551
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
21552
|
+
if (idx >= 0) mesh.nodes[idx] = node;
|
|
21553
|
+
else mesh.nodes.push(node);
|
|
21554
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21555
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21556
|
+
}
|
|
21557
|
+
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
21558
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
21559
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
|
|
21560
|
+
if (idx === -1) return false;
|
|
21561
|
+
mesh.nodes.splice(idx, 1);
|
|
21562
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21563
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21564
|
+
return true;
|
|
21565
|
+
}
|
|
21566
|
+
normalizeMeshSessionCleanupMode(value) {
|
|
21567
|
+
return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
|
|
21568
|
+
}
|
|
21569
|
+
sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
|
|
21570
|
+
const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
|
|
21571
|
+
if (!sessionId) return false;
|
|
21572
|
+
if (sessionIds?.size) return sessionIds.has(sessionId);
|
|
21573
|
+
const workspace = typeof node?.workspace === "string" ? node.workspace : "";
|
|
21574
|
+
if (workspace && record?.workspace === workspace) return true;
|
|
21575
|
+
if (record?.meta?.meshNodeId === nodeId) return true;
|
|
21576
|
+
return false;
|
|
21577
|
+
}
|
|
21578
|
+
isCompletedHostedSession(record) {
|
|
21579
|
+
return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
|
|
21580
|
+
}
|
|
21581
|
+
async cleanupMeshSessions(args) {
|
|
21582
|
+
if (args.mode === "preserve") {
|
|
21583
|
+
return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
|
|
21584
|
+
}
|
|
21585
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
21586
|
+
const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
|
|
21587
|
+
const sessions = await this.deps.sessionHostControl.listSessions();
|
|
21588
|
+
const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
|
|
21589
|
+
const hasExplicitSessionIds = !!requestedSessionIds?.size;
|
|
21590
|
+
const stoppedSessionIds = [];
|
|
21591
|
+
const deletedSessionIds = [];
|
|
21592
|
+
const skippedSessionIds = [];
|
|
21593
|
+
const skippedLiveSessionIds = [];
|
|
21594
|
+
const deleteUnsupportedSessionIds = [];
|
|
21595
|
+
const recordsRemainSessionIds = [];
|
|
21596
|
+
const errors = [];
|
|
21597
|
+
const matchedBySurfaceKind = {
|
|
21598
|
+
live_runtime: 0,
|
|
21599
|
+
recovery_snapshot: 0,
|
|
21600
|
+
inactive_record: 0
|
|
21601
|
+
};
|
|
21602
|
+
for (const record of matched) {
|
|
21603
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21604
|
+
matchedBySurfaceKind[surfaceKind] += 1;
|
|
21605
|
+
}
|
|
21606
|
+
for (const record of matched) {
|
|
21607
|
+
const sessionId = String(record.sessionId);
|
|
21608
|
+
const completed = this.isCompletedHostedSession(record);
|
|
21609
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21610
|
+
const liveRuntime = surfaceKind === "live_runtime";
|
|
21611
|
+
if (!hasExplicitSessionIds && liveRuntime) {
|
|
21612
|
+
skippedSessionIds.push(sessionId);
|
|
21613
|
+
skippedLiveSessionIds.push(sessionId);
|
|
21614
|
+
continue;
|
|
21615
|
+
}
|
|
21616
|
+
try {
|
|
21617
|
+
if (args.mode === "stop") {
|
|
21618
|
+
if (!completed) {
|
|
21619
|
+
if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21620
|
+
stoppedSessionIds.push(sessionId);
|
|
21621
|
+
} else {
|
|
21622
|
+
skippedSessionIds.push(sessionId);
|
|
21623
|
+
}
|
|
21624
|
+
continue;
|
|
21625
|
+
}
|
|
21626
|
+
if (args.mode === "delete_stopped") {
|
|
21627
|
+
if (completed) {
|
|
21628
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
|
|
21629
|
+
deletedSessionIds.push(sessionId);
|
|
21630
|
+
} else {
|
|
21631
|
+
skippedSessionIds.push(sessionId);
|
|
21632
|
+
}
|
|
21633
|
+
continue;
|
|
21634
|
+
}
|
|
21635
|
+
if (args.mode === "stop_and_delete") {
|
|
21636
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
|
|
21637
|
+
deletedSessionIds.push(sessionId);
|
|
21638
|
+
continue;
|
|
21639
|
+
}
|
|
21640
|
+
} catch (e) {
|
|
21641
|
+
const message = e?.message || String(e);
|
|
21642
|
+
if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
|
|
21643
|
+
deleteUnsupportedSessionIds.push(sessionId);
|
|
21644
|
+
recordsRemainSessionIds.push(sessionId);
|
|
21645
|
+
if (args.mode === "stop_and_delete" && !completed) {
|
|
21646
|
+
try {
|
|
21647
|
+
await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21648
|
+
stoppedSessionIds.push(sessionId);
|
|
21649
|
+
} catch (stopError) {
|
|
21650
|
+
errors.push({ sessionId, error: stopError?.message || String(stopError) });
|
|
21651
|
+
continue;
|
|
21652
|
+
}
|
|
21653
|
+
}
|
|
21654
|
+
skippedSessionIds.push(sessionId);
|
|
21655
|
+
continue;
|
|
21656
|
+
}
|
|
21657
|
+
errors.push({ sessionId, error: message });
|
|
21658
|
+
}
|
|
21659
|
+
}
|
|
21660
|
+
const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
|
|
21661
|
+
return {
|
|
21662
|
+
success: errors.length === 0,
|
|
21663
|
+
mode: args.mode,
|
|
21664
|
+
dryRun: args.dryRun === true,
|
|
21665
|
+
matchedCount: matched.length,
|
|
21666
|
+
matchedBySurfaceKind,
|
|
21667
|
+
stoppedSessionIds,
|
|
21668
|
+
deletedSessionIds,
|
|
21669
|
+
skippedSessionIds,
|
|
21670
|
+
skippedLiveSessionIds,
|
|
21671
|
+
...deleteUnsupported ? {
|
|
21672
|
+
deleteUnsupported: true,
|
|
21673
|
+
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
21674
|
+
deleteUnsupportedSessionIds,
|
|
21675
|
+
recordsRemainSessionIds
|
|
21676
|
+
} : {},
|
|
21677
|
+
...errors.length ? { errors } : {}
|
|
21678
|
+
};
|
|
21679
|
+
}
|
|
20717
21680
|
async traceSessionHostAction(action, args, run, summarizeResult) {
|
|
20718
21681
|
const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
|
|
20719
21682
|
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -20833,6 +21796,9 @@ var DaemonCommandRouter = class {
|
|
|
20833
21796
|
async executeDaemonCommand(cmd, args) {
|
|
20834
21797
|
switch (cmd) {
|
|
20835
21798
|
// ─── CLI / ACP commands ───
|
|
21799
|
+
case "mesh_forward_event": {
|
|
21800
|
+
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
21801
|
+
}
|
|
20836
21802
|
case "launch_cli":
|
|
20837
21803
|
case "stop_cli":
|
|
20838
21804
|
case "set_cli_view_mode":
|
|
@@ -21377,7 +22343,26 @@ var DaemonCommandRouter = class {
|
|
|
21377
22343
|
if (!name) return { success: false, error: "name required" };
|
|
21378
22344
|
try {
|
|
21379
22345
|
const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21380
|
-
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
|
|
22346
|
+
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
|
|
22347
|
+
return { success: true, mesh };
|
|
22348
|
+
} catch (e) {
|
|
22349
|
+
return { success: false, error: e.message };
|
|
22350
|
+
}
|
|
22351
|
+
}
|
|
22352
|
+
case "update_mesh": {
|
|
22353
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22354
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22355
|
+
try {
|
|
22356
|
+
const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22357
|
+
const patch = {};
|
|
22358
|
+
if (typeof args?.name === "string") patch.name = args.name;
|
|
22359
|
+
if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
|
|
22360
|
+
if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
|
|
22361
|
+
if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
|
|
22362
|
+
if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
|
|
22363
|
+
const mesh = updateMesh2(meshId, patch);
|
|
22364
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22365
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21381
22366
|
return { success: true, mesh };
|
|
21382
22367
|
} catch (e) {
|
|
21383
22368
|
return { success: false, error: e.message };
|
|
@@ -21401,21 +22386,164 @@ var DaemonCommandRouter = class {
|
|
|
21401
22386
|
if (!workspace) return { success: false, error: "workspace required" };
|
|
21402
22387
|
try {
|
|
21403
22388
|
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21404
|
-
const
|
|
22389
|
+
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
22390
|
+
const readOnly = args?.readOnly === true;
|
|
22391
|
+
const policy = {
|
|
22392
|
+
...readOnly ? { readOnly: true } : {},
|
|
22393
|
+
...providerPriority.length ? { providerPriority } : {}
|
|
22394
|
+
};
|
|
22395
|
+
const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
|
|
21405
22396
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
21406
22397
|
return { success: true, node };
|
|
21407
22398
|
} catch (e) {
|
|
21408
22399
|
return { success: false, error: e.message };
|
|
21409
22400
|
}
|
|
21410
22401
|
}
|
|
22402
|
+
case "update_mesh_node": {
|
|
22403
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22404
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22405
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22406
|
+
try {
|
|
22407
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22408
|
+
const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
|
|
22409
|
+
if (Array.isArray(args?.providerPriority)) {
|
|
22410
|
+
const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
|
|
22411
|
+
delete policy.provider_priority;
|
|
22412
|
+
if (providerPriority.length) {
|
|
22413
|
+
policy.providerPriority = providerPriority;
|
|
22414
|
+
} else {
|
|
22415
|
+
delete policy.providerPriority;
|
|
22416
|
+
}
|
|
22417
|
+
}
|
|
22418
|
+
const node = updateNode2(meshId, nodeId, { policy });
|
|
22419
|
+
if (!node) return { success: false, error: "Mesh node not found" };
|
|
22420
|
+
return { success: true, node };
|
|
22421
|
+
} catch (e) {
|
|
22422
|
+
return { success: false, error: e.message };
|
|
22423
|
+
}
|
|
22424
|
+
}
|
|
22425
|
+
case "cleanup_mesh_sessions": {
|
|
22426
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22427
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22428
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22429
|
+
try {
|
|
22430
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22431
|
+
const mesh = meshRecord?.mesh;
|
|
22432
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22433
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22434
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
22435
|
+
const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
|
|
22436
|
+
const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
|
|
22437
|
+
const result = await this.cleanupMeshSessions({
|
|
22438
|
+
meshId,
|
|
22439
|
+
nodeId,
|
|
22440
|
+
node,
|
|
22441
|
+
mode,
|
|
22442
|
+
sessionIds,
|
|
22443
|
+
dryRun: args?.dryRun === true
|
|
22444
|
+
});
|
|
22445
|
+
return result;
|
|
22446
|
+
} catch (e) {
|
|
22447
|
+
return { success: false, error: e.message };
|
|
22448
|
+
}
|
|
22449
|
+
}
|
|
21411
22450
|
case "remove_mesh_node": {
|
|
21412
22451
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21413
22452
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
21414
22453
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
21415
22454
|
try {
|
|
21416
|
-
const
|
|
21417
|
-
const
|
|
21418
|
-
|
|
22455
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22456
|
+
const mesh = meshRecord?.mesh;
|
|
22457
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22458
|
+
const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
|
|
22459
|
+
args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
|
|
22460
|
+
);
|
|
22461
|
+
let sessionCleanup;
|
|
22462
|
+
if (node && sessionCleanupMode !== "preserve") {
|
|
22463
|
+
sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
|
|
22464
|
+
if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
|
|
22465
|
+
}
|
|
22466
|
+
if (node?.isLocalWorktree && node.workspace) {
|
|
22467
|
+
try {
|
|
22468
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
22469
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
22470
|
+
if (repoRoot) {
|
|
22471
|
+
const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22472
|
+
await removeWorktree2(repoRoot, node.workspace);
|
|
22473
|
+
}
|
|
22474
|
+
} catch (e) {
|
|
22475
|
+
LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
|
|
22476
|
+
}
|
|
22477
|
+
}
|
|
22478
|
+
let removed = false;
|
|
22479
|
+
if (meshRecord?.inline) {
|
|
22480
|
+
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
22481
|
+
} else {
|
|
22482
|
+
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22483
|
+
removed = removeNode3(meshId, nodeId);
|
|
22484
|
+
}
|
|
22485
|
+
return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
|
|
22486
|
+
} catch (e) {
|
|
22487
|
+
return { success: false, error: e.message };
|
|
22488
|
+
}
|
|
22489
|
+
}
|
|
22490
|
+
case "clone_mesh_node": {
|
|
22491
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22492
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
22493
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
22494
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
22495
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22496
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
22497
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
22498
|
+
try {
|
|
22499
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22500
|
+
const mesh = meshRecord?.mesh;
|
|
22501
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22502
|
+
const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
|
|
22503
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
22504
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
22505
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22506
|
+
const result = await createWorktree2({
|
|
22507
|
+
repoRoot,
|
|
22508
|
+
branch,
|
|
22509
|
+
baseBranch,
|
|
22510
|
+
meshName: mesh.name
|
|
22511
|
+
});
|
|
22512
|
+
let node;
|
|
22513
|
+
if (meshRecord.inline) {
|
|
22514
|
+
const { randomUUID: randomUUID8 } = await import("crypto");
|
|
22515
|
+
node = {
|
|
22516
|
+
id: `node_${randomUUID8().replace(/-/g, "")}`,
|
|
22517
|
+
workspace: result.worktreePath,
|
|
22518
|
+
repoRoot: result.worktreePath,
|
|
22519
|
+
daemonId: sourceNode.daemonId,
|
|
22520
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22521
|
+
policy: { ...sourceNode.policy || {} },
|
|
22522
|
+
isLocalWorktree: true,
|
|
22523
|
+
worktreeBranch: result.branch,
|
|
22524
|
+
clonedFromNodeId: sourceNodeId
|
|
22525
|
+
};
|
|
22526
|
+
this.updateInlineMeshNode(meshId, mesh, node);
|
|
22527
|
+
} else {
|
|
22528
|
+
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22529
|
+
node = addNode3(meshId, {
|
|
22530
|
+
workspace: result.worktreePath,
|
|
22531
|
+
repoRoot: result.worktreePath,
|
|
22532
|
+
daemonId: sourceNode.daemonId,
|
|
22533
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22534
|
+
isLocalWorktree: true,
|
|
22535
|
+
worktreeBranch: result.branch,
|
|
22536
|
+
clonedFromNodeId: sourceNodeId,
|
|
22537
|
+
policy: { ...sourceNode.policy || {} }
|
|
22538
|
+
});
|
|
22539
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
22540
|
+
}
|
|
22541
|
+
return {
|
|
22542
|
+
success: true,
|
|
22543
|
+
node,
|
|
22544
|
+
worktreePath: result.worktreePath,
|
|
22545
|
+
branch: result.branch
|
|
22546
|
+
};
|
|
21419
22547
|
} catch (e) {
|
|
21420
22548
|
return { success: false, error: e.message };
|
|
21421
22549
|
}
|
|
@@ -21423,7 +22551,7 @@ var DaemonCommandRouter = class {
|
|
|
21423
22551
|
// ─── Mesh Coordinator Launch ───
|
|
21424
22552
|
case "launch_mesh_coordinator": {
|
|
21425
22553
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21426
|
-
|
|
22554
|
+
let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
|
|
21427
22555
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
21428
22556
|
try {
|
|
21429
22557
|
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
@@ -21451,9 +22579,29 @@ var DaemonCommandRouter = class {
|
|
|
21451
22579
|
}
|
|
21452
22580
|
const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
|
|
21453
22581
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
22582
|
+
if (!cliType) {
|
|
22583
|
+
const resolved = await resolveProviderTypeFromPriority({
|
|
22584
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
|
|
22585
|
+
providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
|
|
22586
|
+
providerLoader: this.deps.providerLoader,
|
|
22587
|
+
onStatusChange: this.deps.onStatusChange
|
|
22588
|
+
});
|
|
22589
|
+
if (!resolved.providerType) {
|
|
22590
|
+
return {
|
|
22591
|
+
success: false,
|
|
22592
|
+
code: "mesh_coordinator_provider_priority_unusable",
|
|
22593
|
+
error: resolved.error || "No usable provider found from node providerPriority",
|
|
22594
|
+
meshId,
|
|
22595
|
+
cliType,
|
|
22596
|
+
workspace
|
|
22597
|
+
};
|
|
22598
|
+
}
|
|
22599
|
+
cliType = resolved.providerType;
|
|
22600
|
+
}
|
|
21454
22601
|
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
21455
22602
|
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
21456
22603
|
provider: providerMeta,
|
|
22604
|
+
cliType,
|
|
21457
22605
|
meshId,
|
|
21458
22606
|
workspace
|
|
21459
22607
|
});
|
|
@@ -21478,7 +22626,8 @@ var DaemonCommandRouter = class {
|
|
|
21478
22626
|
meshCoordinatorSetup: coordinatorSetup
|
|
21479
22627
|
};
|
|
21480
22628
|
}
|
|
21481
|
-
|
|
22629
|
+
const configFormat = coordinatorSetup.configFormat;
|
|
22630
|
+
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
21482
22631
|
return {
|
|
21483
22632
|
success: false,
|
|
21484
22633
|
code: "mesh_coordinator_unsupported",
|
|
@@ -21488,17 +22637,34 @@ var DaemonCommandRouter = class {
|
|
|
21488
22637
|
workspace
|
|
21489
22638
|
};
|
|
21490
22639
|
}
|
|
21491
|
-
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
|
|
22640
|
+
let systemPrompt = "";
|
|
22641
|
+
try {
|
|
22642
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
22643
|
+
} catch (error) {
|
|
22644
|
+
const message = error?.message || String(error);
|
|
22645
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
22646
|
+
return {
|
|
22647
|
+
success: false,
|
|
22648
|
+
code: "mesh_coordinator_prompt_failed",
|
|
22649
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
22650
|
+
meshId,
|
|
22651
|
+
cliType,
|
|
22652
|
+
workspace
|
|
22653
|
+
};
|
|
21501
22654
|
}
|
|
22655
|
+
const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
|
|
22656
|
+
const { dirname: dirname9 } = await import("path");
|
|
22657
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
22658
|
+
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
22659
|
+
const returnManualFallback = (message) => ({
|
|
22660
|
+
success: false,
|
|
22661
|
+
code: "mesh_coordinator_manual_mcp_setup_required",
|
|
22662
|
+
error: message,
|
|
22663
|
+
meshId,
|
|
22664
|
+
cliType,
|
|
22665
|
+
workspace,
|
|
22666
|
+
meshCoordinatorSetup: hermesManualFallback
|
|
22667
|
+
});
|
|
21502
22668
|
const mcpServerEntry = {
|
|
21503
22669
|
command: coordinatorSetup.mcpServer.command,
|
|
21504
22670
|
args: coordinatorSetup.mcpServer.args
|
|
@@ -21509,24 +22675,55 @@ var DaemonCommandRouter = class {
|
|
|
21509
22675
|
ADHDEV_MCP_TRANSPORT: "ipc"
|
|
21510
22676
|
};
|
|
21511
22677
|
}
|
|
22678
|
+
try {
|
|
22679
|
+
mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
|
|
22680
|
+
} catch (error) {
|
|
22681
|
+
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
22682
|
+
LOG.error("MeshCoordinator", message);
|
|
22683
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22684
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
22685
|
+
}
|
|
22686
|
+
const hadExistingMcpConfig = existsSync23(mcpConfigPath);
|
|
22687
|
+
let existingMcpConfig = {};
|
|
22688
|
+
if (hadExistingMcpConfig) {
|
|
22689
|
+
try {
|
|
22690
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
|
|
22691
|
+
copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
|
|
22692
|
+
} catch (error) {
|
|
22693
|
+
LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
22694
|
+
return {
|
|
22695
|
+
success: false,
|
|
22696
|
+
code: "mesh_coordinator_config_parse_failed",
|
|
22697
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`
|
|
22698
|
+
};
|
|
22699
|
+
}
|
|
22700
|
+
}
|
|
22701
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
22702
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
21512
22703
|
const mcpConfig = {
|
|
21513
22704
|
...existingMcpConfig,
|
|
21514
|
-
|
|
21515
|
-
...
|
|
22705
|
+
[mcpServersKey]: {
|
|
22706
|
+
...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
|
|
21516
22707
|
[coordinatorSetup.serverName]: mcpServerEntry
|
|
21517
22708
|
}
|
|
21518
22709
|
};
|
|
21519
|
-
writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
21520
|
-
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21521
|
-
let systemPrompt = "";
|
|
21522
22710
|
try {
|
|
21523
|
-
|
|
21524
|
-
} catch {
|
|
21525
|
-
|
|
22711
|
+
writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
22712
|
+
} catch (error) {
|
|
22713
|
+
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
22714
|
+
LOG.error("MeshCoordinator", message);
|
|
22715
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22716
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21526
22717
|
}
|
|
22718
|
+
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21527
22719
|
const cliArgs = [];
|
|
22720
|
+
const launchEnv = {};
|
|
21528
22721
|
if (systemPrompt) {
|
|
21529
|
-
|
|
22722
|
+
if (configFormat === "hermes_config_yaml") {
|
|
22723
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
22724
|
+
} else {
|
|
22725
|
+
cliArgs.push("--append-system-prompt", systemPrompt);
|
|
22726
|
+
}
|
|
21530
22727
|
}
|
|
21531
22728
|
if (cliType === "claude-cli") {
|
|
21532
22729
|
cliArgs.push("--mcp-config", coordinatorSetup.configPath);
|
|
@@ -21535,6 +22732,7 @@ var DaemonCommandRouter = class {
|
|
|
21535
22732
|
cliType,
|
|
21536
22733
|
dir: workspace,
|
|
21537
22734
|
cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
|
|
22735
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
21538
22736
|
settings: {
|
|
21539
22737
|
meshCoordinatorFor: meshId
|
|
21540
22738
|
}
|
|
@@ -21714,6 +22912,12 @@ var DaemonStatusReporter = class {
|
|
|
21714
22912
|
if (providerType) {
|
|
21715
22913
|
payload.providerType = providerType;
|
|
21716
22914
|
}
|
|
22915
|
+
if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
|
|
22916
|
+
payload.providerSessionId = event.providerSessionId.trim();
|
|
22917
|
+
}
|
|
22918
|
+
if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
|
|
22919
|
+
payload.workspaceName = event.workspaceName.trim();
|
|
22920
|
+
}
|
|
21717
22921
|
if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
|
|
21718
22922
|
payload.duration = event.duration;
|
|
21719
22923
|
}
|
|
@@ -21935,7 +23139,8 @@ function prepareSessionChatTailUpdate(input) {
|
|
|
21935
23139
|
update: null
|
|
21936
23140
|
};
|
|
21937
23141
|
}
|
|
21938
|
-
const
|
|
23142
|
+
const fullMessages = normalizeChatMessages(Array.isArray(result.messages) ? result.messages : []);
|
|
23143
|
+
const messages = filterUserFacingChatMessages(fullMessages);
|
|
21939
23144
|
const title = typeof result.title === "string" ? result.title : void 0;
|
|
21940
23145
|
const activeModal = normalizeChatTailActiveModal(result.activeModal);
|
|
21941
23146
|
const status = typeof result.status === "string" ? result.status : "idle";
|
|
@@ -22961,7 +24166,10 @@ var ProviderInstanceManager = class {
|
|
|
22961
24166
|
this.instances.get(id).dispose();
|
|
22962
24167
|
}
|
|
22963
24168
|
this.instances.set(id, instance);
|
|
22964
|
-
await instance.init(
|
|
24169
|
+
await instance.init({
|
|
24170
|
+
...context,
|
|
24171
|
+
emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
|
|
24172
|
+
});
|
|
22965
24173
|
}
|
|
22966
24174
|
/**
|
|
22967
24175
|
* Instance remove
|
|
@@ -23123,6 +24331,17 @@ var ProviderInstanceManager = class {
|
|
|
23123
24331
|
onEvent(listener) {
|
|
23124
24332
|
this.eventListeners.push(listener);
|
|
23125
24333
|
}
|
|
24334
|
+
emitProviderEvent(providerType, instanceId, event) {
|
|
24335
|
+
const payload = {
|
|
24336
|
+
...event,
|
|
24337
|
+
providerType,
|
|
24338
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
|
|
24339
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
|
|
24340
|
+
};
|
|
24341
|
+
for (const listener of this.eventListeners) {
|
|
24342
|
+
listener(payload);
|
|
24343
|
+
}
|
|
24344
|
+
}
|
|
23126
24345
|
emitPendingEvents(providerType, state, extra = {}) {
|
|
23127
24346
|
for (const event of state.pendingEvents) {
|
|
23128
24347
|
for (const listener of this.eventListeners) {
|
|
@@ -23195,11 +24414,11 @@ var ProviderInstanceManager = class {
|
|
|
23195
24414
|
|
|
23196
24415
|
// src/providers/version-archive.ts
|
|
23197
24416
|
import * as fs11 from "fs";
|
|
23198
|
-
import * as
|
|
23199
|
-
import * as
|
|
24417
|
+
import * as path22 from "path";
|
|
24418
|
+
import * as os20 from "os";
|
|
23200
24419
|
import { execSync as execSync5 } from "child_process";
|
|
23201
24420
|
import { platform as platform8 } from "os";
|
|
23202
|
-
var ARCHIVE_PATH =
|
|
24421
|
+
var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
|
|
23203
24422
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
23204
24423
|
var VersionArchive = class {
|
|
23205
24424
|
history = {};
|
|
@@ -23246,7 +24465,7 @@ var VersionArchive = class {
|
|
|
23246
24465
|
}
|
|
23247
24466
|
save() {
|
|
23248
24467
|
try {
|
|
23249
|
-
fs11.mkdirSync(
|
|
24468
|
+
fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
|
|
23250
24469
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
23251
24470
|
} catch {
|
|
23252
24471
|
}
|
|
@@ -23302,8 +24521,8 @@ function getVersion(binary, versionCommand) {
|
|
|
23302
24521
|
function checkPathExists2(paths) {
|
|
23303
24522
|
for (const p of paths) {
|
|
23304
24523
|
if (p.includes("*")) {
|
|
23305
|
-
const home =
|
|
23306
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
24524
|
+
const home = os20.homedir();
|
|
24525
|
+
const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
|
|
23307
24526
|
if (fs11.existsSync(resolved)) return resolved;
|
|
23308
24527
|
} else {
|
|
23309
24528
|
if (fs11.existsSync(p)) return p;
|
|
@@ -23313,7 +24532,7 @@ function checkPathExists2(paths) {
|
|
|
23313
24532
|
}
|
|
23314
24533
|
function getMacAppVersion(appPath) {
|
|
23315
24534
|
if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
23316
|
-
const plistPath =
|
|
24535
|
+
const plistPath = path22.join(appPath, "Contents", "Info.plist");
|
|
23317
24536
|
if (!fs11.existsSync(plistPath)) return null;
|
|
23318
24537
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
23319
24538
|
return raw || null;
|
|
@@ -23339,7 +24558,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23339
24558
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
23340
24559
|
let resolvedBin = cliBin;
|
|
23341
24560
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
23342
|
-
const bundled =
|
|
24561
|
+
const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
23343
24562
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
23344
24563
|
}
|
|
23345
24564
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -23380,7 +24599,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23380
24599
|
// src/daemon/dev-server.ts
|
|
23381
24600
|
import * as http2 from "http";
|
|
23382
24601
|
import * as fs15 from "fs";
|
|
23383
|
-
import * as
|
|
24602
|
+
import * as path26 from "path";
|
|
23384
24603
|
init_config();
|
|
23385
24604
|
|
|
23386
24605
|
// src/daemon/scaffold-template.ts
|
|
@@ -23732,7 +24951,7 @@ init_logger();
|
|
|
23732
24951
|
// src/daemon/dev-cdp-handlers.ts
|
|
23733
24952
|
init_logger();
|
|
23734
24953
|
import * as fs12 from "fs";
|
|
23735
|
-
import * as
|
|
24954
|
+
import * as path23 from "path";
|
|
23736
24955
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
23737
24956
|
const body = await ctx.readBody(req);
|
|
23738
24957
|
const { expression, timeout, ideType } = body;
|
|
@@ -23910,17 +25129,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
23910
25129
|
return;
|
|
23911
25130
|
}
|
|
23912
25131
|
let scriptsPath = "";
|
|
23913
|
-
const directScripts =
|
|
25132
|
+
const directScripts = path23.join(dir, "scripts.js");
|
|
23914
25133
|
if (fs12.existsSync(directScripts)) {
|
|
23915
25134
|
scriptsPath = directScripts;
|
|
23916
25135
|
} else {
|
|
23917
|
-
const scriptsDir =
|
|
25136
|
+
const scriptsDir = path23.join(dir, "scripts");
|
|
23918
25137
|
if (fs12.existsSync(scriptsDir)) {
|
|
23919
25138
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
23920
|
-
return fs12.statSync(
|
|
25139
|
+
return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
|
|
23921
25140
|
}).sort().reverse();
|
|
23922
25141
|
for (const ver of versions) {
|
|
23923
|
-
const p =
|
|
25142
|
+
const p = path23.join(scriptsDir, ver, "scripts.js");
|
|
23924
25143
|
if (fs12.existsSync(p)) {
|
|
23925
25144
|
scriptsPath = p;
|
|
23926
25145
|
break;
|
|
@@ -24749,7 +25968,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
24749
25968
|
|
|
24750
25969
|
// src/daemon/dev-cli-debug.ts
|
|
24751
25970
|
import * as fs13 from "fs";
|
|
24752
|
-
import * as
|
|
25971
|
+
import * as path24 from "path";
|
|
24753
25972
|
function slugifyFixtureName(value) {
|
|
24754
25973
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24755
25974
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -24759,11 +25978,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
24759
25978
|
if (!providerDir) {
|
|
24760
25979
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
24761
25980
|
}
|
|
24762
|
-
return
|
|
25981
|
+
return path24.join(providerDir, "fixtures");
|
|
24763
25982
|
}
|
|
24764
25983
|
function readCliFixture(ctx, type, name) {
|
|
24765
25984
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
24766
|
-
const filePath =
|
|
25985
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
24767
25986
|
if (!fs13.existsSync(filePath)) {
|
|
24768
25987
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
24769
25988
|
}
|
|
@@ -24931,7 +26150,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
|
|
|
24931
26150
|
if (!adapter) return null;
|
|
24932
26151
|
return { target, instance, adapter };
|
|
24933
26152
|
}
|
|
24934
|
-
function
|
|
26153
|
+
function sleep2(ms) {
|
|
24935
26154
|
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
24936
26155
|
}
|
|
24937
26156
|
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
@@ -24948,7 +26167,7 @@ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
|
24948
26167
|
return bundle;
|
|
24949
26168
|
}
|
|
24950
26169
|
}
|
|
24951
|
-
await
|
|
26170
|
+
await sleep2(100);
|
|
24952
26171
|
}
|
|
24953
26172
|
return getCliTargetBundle(ctx, type, instanceId);
|
|
24954
26173
|
}
|
|
@@ -25004,7 +26223,7 @@ async function runCliExerciseInternal(ctx, body) {
|
|
|
25004
26223
|
const message = String(lastLaunchError.message || "");
|
|
25005
26224
|
const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
|
|
25006
26225
|
if (!retryable || attempt === 2) break;
|
|
25007
|
-
await
|
|
26226
|
+
await sleep2(1e3);
|
|
25008
26227
|
}
|
|
25009
26228
|
}
|
|
25010
26229
|
if (!launched) {
|
|
@@ -25067,16 +26286,16 @@ async function runCliExerciseInternal(ctx, body) {
|
|
|
25067
26286
|
const modal = debug?.activeModal || trace?.activeModal || null;
|
|
25068
26287
|
noteStatus(status);
|
|
25069
26288
|
if (resolveActiveModalIfNeeded(status, modal)) {
|
|
25070
|
-
await
|
|
26289
|
+
await sleep2(150);
|
|
25071
26290
|
continue;
|
|
25072
26291
|
}
|
|
25073
26292
|
const startupParseGate = !!debug?.startupParseGate;
|
|
25074
26293
|
if (status === "idle" && !startupParseGate) break;
|
|
25075
|
-
await
|
|
26294
|
+
await sleep2(150);
|
|
25076
26295
|
}
|
|
25077
26296
|
ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
|
|
25078
26297
|
while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
|
|
25079
|
-
await
|
|
26298
|
+
await sleep2(150);
|
|
25080
26299
|
bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
|
|
25081
26300
|
if (!bundle) {
|
|
25082
26301
|
throw new Error("CLI instance disappeared during exercise");
|
|
@@ -25530,7 +26749,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
25530
26749
|
},
|
|
25531
26750
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
25532
26751
|
};
|
|
25533
|
-
const filePath =
|
|
26752
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
25534
26753
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
25535
26754
|
ctx.json(res, 200, {
|
|
25536
26755
|
saved: true,
|
|
@@ -25554,7 +26773,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
25554
26773
|
return;
|
|
25555
26774
|
}
|
|
25556
26775
|
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 =
|
|
26776
|
+
const fullPath = path24.join(fixtureDir, file);
|
|
25558
26777
|
try {
|
|
25559
26778
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
25560
26779
|
return {
|
|
@@ -25690,8 +26909,8 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
25690
26909
|
|
|
25691
26910
|
// src/daemon/dev-auto-implement.ts
|
|
25692
26911
|
import * as fs14 from "fs";
|
|
25693
|
-
import * as
|
|
25694
|
-
import * as
|
|
26912
|
+
import * as path25 from "path";
|
|
26913
|
+
import * as os21 from "os";
|
|
25695
26914
|
function getAutoImplPid(ctx) {
|
|
25696
26915
|
const pid = ctx.autoImplProcess?.pid;
|
|
25697
26916
|
return typeof pid === "number" && pid > 0 ? pid : null;
|
|
@@ -25740,22 +26959,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
25740
26959
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
25741
26960
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
25742
26961
|
try {
|
|
25743
|
-
return fs14.statSync(
|
|
26962
|
+
return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
25744
26963
|
} catch {
|
|
25745
26964
|
return false;
|
|
25746
26965
|
}
|
|
25747
26966
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
25748
26967
|
if (versions.length === 0) return null;
|
|
25749
|
-
return
|
|
26968
|
+
return path25.join(scriptsDir, versions[0]);
|
|
25750
26969
|
}
|
|
25751
26970
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
25752
|
-
const canonicalUserDir =
|
|
25753
|
-
const desiredDir = requestedDir ?
|
|
25754
|
-
const upstreamRoot =
|
|
25755
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
26971
|
+
const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
26972
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
26973
|
+
const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
|
|
26974
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
25756
26975
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
25757
26976
|
}
|
|
25758
|
-
if (
|
|
26977
|
+
if (path25.basename(desiredDir) !== type) {
|
|
25759
26978
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
25760
26979
|
}
|
|
25761
26980
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -25763,11 +26982,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
25763
26982
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
25764
26983
|
}
|
|
25765
26984
|
if (!fs14.existsSync(desiredDir)) {
|
|
25766
|
-
fs14.mkdirSync(
|
|
26985
|
+
fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
25767
26986
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
25768
26987
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
25769
26988
|
}
|
|
25770
|
-
const providerJson =
|
|
26989
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
25771
26990
|
if (!fs14.existsSync(providerJson)) {
|
|
25772
26991
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
25773
26992
|
}
|
|
@@ -25778,13 +26997,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
25778
26997
|
const refDir = ctx.findProviderDir(referenceType);
|
|
25779
26998
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
25780
26999
|
const referenceScripts = {};
|
|
25781
|
-
const scriptsDir =
|
|
27000
|
+
const scriptsDir = path25.join(refDir, "scripts");
|
|
25782
27001
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
25783
27002
|
if (!latestDir) return referenceScripts;
|
|
25784
27003
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
25785
27004
|
if (!file.endsWith(".js")) continue;
|
|
25786
27005
|
try {
|
|
25787
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
27006
|
+
referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
|
|
25788
27007
|
} catch {
|
|
25789
27008
|
}
|
|
25790
27009
|
}
|
|
@@ -25892,9 +27111,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
25892
27111
|
});
|
|
25893
27112
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
25894
27113
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
25895
|
-
const tmpDir =
|
|
27114
|
+
const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
|
|
25896
27115
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
25897
|
-
const promptFile =
|
|
27116
|
+
const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
25898
27117
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
25899
27118
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
25900
27119
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -26047,7 +27266,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26047
27266
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
26048
27267
|
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
26049
27268
|
let shellCmd;
|
|
26050
|
-
const isWin =
|
|
27269
|
+
const isWin = os21.platform() === "win32";
|
|
26051
27270
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
26052
27271
|
const promptMode = autoImpl?.promptMode ?? "stdin";
|
|
26053
27272
|
const extraArgs = autoImpl?.extraArgs ?? [];
|
|
@@ -26086,7 +27305,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26086
27305
|
try {
|
|
26087
27306
|
const pty = __require("node-pty");
|
|
26088
27307
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
26089
|
-
const isWin2 =
|
|
27308
|
+
const isWin2 = os21.platform() === "win32";
|
|
26090
27309
|
child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
26091
27310
|
name: "xterm-256color",
|
|
26092
27311
|
cols: 120,
|
|
@@ -26326,7 +27545,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26326
27545
|
setMode: "set_mode.js"
|
|
26327
27546
|
};
|
|
26328
27547
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26329
|
-
const scriptsDir =
|
|
27548
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26330
27549
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26331
27550
|
if (latestScriptsDir) {
|
|
26332
27551
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26337,7 +27556,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26337
27556
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
26338
27557
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26339
27558
|
try {
|
|
26340
|
-
const content = fs14.readFileSync(
|
|
27559
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26341
27560
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26342
27561
|
lines.push("```javascript");
|
|
26343
27562
|
lines.push(content);
|
|
@@ -26354,7 +27573,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26354
27573
|
lines.push("");
|
|
26355
27574
|
for (const file of refFiles) {
|
|
26356
27575
|
try {
|
|
26357
|
-
const content = fs14.readFileSync(
|
|
27576
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26358
27577
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26359
27578
|
lines.push("```javascript");
|
|
26360
27579
|
lines.push(content);
|
|
@@ -26395,10 +27614,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26395
27614
|
lines.push("");
|
|
26396
27615
|
}
|
|
26397
27616
|
}
|
|
26398
|
-
const docsDir =
|
|
27617
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26399
27618
|
const loadGuide = (name) => {
|
|
26400
27619
|
try {
|
|
26401
|
-
const p =
|
|
27620
|
+
const p = path25.join(docsDir, name);
|
|
26402
27621
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26403
27622
|
} catch {
|
|
26404
27623
|
}
|
|
@@ -26635,7 +27854,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26635
27854
|
parseApproval: "parse_approval.js"
|
|
26636
27855
|
};
|
|
26637
27856
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26638
|
-
const scriptsDir =
|
|
27857
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26639
27858
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26640
27859
|
if (latestScriptsDir) {
|
|
26641
27860
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26647,7 +27866,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26647
27866
|
if (!file.endsWith(".js")) continue;
|
|
26648
27867
|
if (!targetFileNames.has(file)) continue;
|
|
26649
27868
|
try {
|
|
26650
|
-
const content = fs14.readFileSync(
|
|
27869
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26651
27870
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26652
27871
|
lines.push("```javascript");
|
|
26653
27872
|
lines.push(content);
|
|
@@ -26663,7 +27882,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26663
27882
|
lines.push("");
|
|
26664
27883
|
for (const file of refFiles) {
|
|
26665
27884
|
try {
|
|
26666
|
-
const content = fs14.readFileSync(
|
|
27885
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26667
27886
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26668
27887
|
lines.push("```javascript");
|
|
26669
27888
|
lines.push(content);
|
|
@@ -26696,10 +27915,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26696
27915
|
lines.push("");
|
|
26697
27916
|
}
|
|
26698
27917
|
}
|
|
26699
|
-
const docsDir =
|
|
27918
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26700
27919
|
const loadGuide = (name) => {
|
|
26701
27920
|
try {
|
|
26702
|
-
const p =
|
|
27921
|
+
const p = path25.join(docsDir, name);
|
|
26703
27922
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26704
27923
|
} catch {
|
|
26705
27924
|
}
|
|
@@ -27146,8 +28365,8 @@ var DevServer = class _DevServer {
|
|
|
27146
28365
|
}
|
|
27147
28366
|
getEndpointList() {
|
|
27148
28367
|
return this.routes.map((r) => {
|
|
27149
|
-
const
|
|
27150
|
-
return `${r.method.padEnd(5)} ${
|
|
28368
|
+
const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
28369
|
+
return `${r.method.padEnd(5)} ${path27}`;
|
|
27151
28370
|
});
|
|
27152
28371
|
}
|
|
27153
28372
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -27435,12 +28654,12 @@ var DevServer = class _DevServer {
|
|
|
27435
28654
|
// ─── DevConsole SPA ───
|
|
27436
28655
|
getConsoleDistDir() {
|
|
27437
28656
|
const candidates = [
|
|
27438
|
-
|
|
27439
|
-
|
|
27440
|
-
|
|
28657
|
+
path26.resolve(__dirname, "../../web-devconsole/dist"),
|
|
28658
|
+
path26.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
28659
|
+
path26.join(process.cwd(), "packages/web-devconsole/dist")
|
|
27441
28660
|
];
|
|
27442
28661
|
for (const dir of candidates) {
|
|
27443
|
-
if (fs15.existsSync(
|
|
28662
|
+
if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
|
|
27444
28663
|
}
|
|
27445
28664
|
return null;
|
|
27446
28665
|
}
|
|
@@ -27450,7 +28669,7 @@ var DevServer = class _DevServer {
|
|
|
27450
28669
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
27451
28670
|
return;
|
|
27452
28671
|
}
|
|
27453
|
-
const htmlPath =
|
|
28672
|
+
const htmlPath = path26.join(distDir, "index.html");
|
|
27454
28673
|
try {
|
|
27455
28674
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
27456
28675
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -27475,15 +28694,15 @@ var DevServer = class _DevServer {
|
|
|
27475
28694
|
this.json(res, 404, { error: "Not found" });
|
|
27476
28695
|
return;
|
|
27477
28696
|
}
|
|
27478
|
-
const safePath =
|
|
27479
|
-
const filePath =
|
|
28697
|
+
const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
|
|
28698
|
+
const filePath = path26.join(distDir, safePath);
|
|
27480
28699
|
if (!filePath.startsWith(distDir)) {
|
|
27481
28700
|
this.json(res, 403, { error: "Forbidden" });
|
|
27482
28701
|
return;
|
|
27483
28702
|
}
|
|
27484
28703
|
try {
|
|
27485
28704
|
const content = fs15.readFileSync(filePath);
|
|
27486
|
-
const ext =
|
|
28705
|
+
const ext = path26.extname(filePath);
|
|
27487
28706
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
27488
28707
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
27489
28708
|
res.end(content);
|
|
@@ -27596,9 +28815,9 @@ var DevServer = class _DevServer {
|
|
|
27596
28815
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27597
28816
|
if (entry.isDirectory()) {
|
|
27598
28817
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
27599
|
-
scan(
|
|
28818
|
+
scan(path26.join(d, entry.name), rel);
|
|
27600
28819
|
} else {
|
|
27601
|
-
const stat2 = fs15.statSync(
|
|
28820
|
+
const stat2 = fs15.statSync(path26.join(d, entry.name));
|
|
27602
28821
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
27603
28822
|
}
|
|
27604
28823
|
}
|
|
@@ -27621,7 +28840,7 @@ var DevServer = class _DevServer {
|
|
|
27621
28840
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27622
28841
|
return;
|
|
27623
28842
|
}
|
|
27624
|
-
const fullPath =
|
|
28843
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27625
28844
|
if (!fullPath.startsWith(dir)) {
|
|
27626
28845
|
this.json(res, 403, { error: "Forbidden" });
|
|
27627
28846
|
return;
|
|
@@ -27646,14 +28865,14 @@ var DevServer = class _DevServer {
|
|
|
27646
28865
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27647
28866
|
return;
|
|
27648
28867
|
}
|
|
27649
|
-
const fullPath =
|
|
28868
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27650
28869
|
if (!fullPath.startsWith(dir)) {
|
|
27651
28870
|
this.json(res, 403, { error: "Forbidden" });
|
|
27652
28871
|
return;
|
|
27653
28872
|
}
|
|
27654
28873
|
try {
|
|
27655
28874
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
27656
|
-
fs15.mkdirSync(
|
|
28875
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27657
28876
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27658
28877
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
27659
28878
|
this.providerLoader.reload();
|
|
@@ -27670,7 +28889,7 @@ var DevServer = class _DevServer {
|
|
|
27670
28889
|
return;
|
|
27671
28890
|
}
|
|
27672
28891
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
27673
|
-
const p =
|
|
28892
|
+
const p = path26.join(dir, name);
|
|
27674
28893
|
if (fs15.existsSync(p)) {
|
|
27675
28894
|
const source = fs15.readFileSync(p, "utf-8");
|
|
27676
28895
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -27691,8 +28910,8 @@ var DevServer = class _DevServer {
|
|
|
27691
28910
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
27692
28911
|
return;
|
|
27693
28912
|
}
|
|
27694
|
-
const target = fs15.existsSync(
|
|
27695
|
-
const targetPath =
|
|
28913
|
+
const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
28914
|
+
const targetPath = path26.join(dir, target);
|
|
27696
28915
|
try {
|
|
27697
28916
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
27698
28917
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -27839,7 +29058,7 @@ var DevServer = class _DevServer {
|
|
|
27839
29058
|
}
|
|
27840
29059
|
let targetDir;
|
|
27841
29060
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
27842
|
-
const jsonPath =
|
|
29061
|
+
const jsonPath = path26.join(targetDir, "provider.json");
|
|
27843
29062
|
if (fs15.existsSync(jsonPath)) {
|
|
27844
29063
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
27845
29064
|
return;
|
|
@@ -27851,8 +29070,8 @@ var DevServer = class _DevServer {
|
|
|
27851
29070
|
const createdFiles = ["provider.json"];
|
|
27852
29071
|
if (result.files) {
|
|
27853
29072
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
27854
|
-
const fullPath =
|
|
27855
|
-
fs15.mkdirSync(
|
|
29073
|
+
const fullPath = path26.join(targetDir, relPath);
|
|
29074
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27856
29075
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27857
29076
|
createdFiles.push(relPath);
|
|
27858
29077
|
}
|
|
@@ -27905,22 +29124,22 @@ var DevServer = class _DevServer {
|
|
|
27905
29124
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
27906
29125
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
27907
29126
|
try {
|
|
27908
|
-
return fs15.statSync(
|
|
29127
|
+
return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
|
|
27909
29128
|
} catch {
|
|
27910
29129
|
return false;
|
|
27911
29130
|
}
|
|
27912
29131
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
27913
29132
|
if (versions.length === 0) return null;
|
|
27914
|
-
return
|
|
29133
|
+
return path26.join(scriptsDir, versions[0]);
|
|
27915
29134
|
}
|
|
27916
29135
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
27917
|
-
const canonicalUserDir =
|
|
27918
|
-
const desiredDir = requestedDir ?
|
|
27919
|
-
const upstreamRoot =
|
|
27920
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
29136
|
+
const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
29137
|
+
const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
|
|
29138
|
+
const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
|
|
29139
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
|
|
27921
29140
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
27922
29141
|
}
|
|
27923
|
-
if (
|
|
29142
|
+
if (path26.basename(desiredDir) !== type) {
|
|
27924
29143
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
27925
29144
|
}
|
|
27926
29145
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -27928,11 +29147,11 @@ var DevServer = class _DevServer {
|
|
|
27928
29147
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
27929
29148
|
}
|
|
27930
29149
|
if (!fs15.existsSync(desiredDir)) {
|
|
27931
|
-
fs15.mkdirSync(
|
|
29150
|
+
fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
|
|
27932
29151
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
27933
29152
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
27934
29153
|
}
|
|
27935
|
-
const providerJson =
|
|
29154
|
+
const providerJson = path26.join(desiredDir, "provider.json");
|
|
27936
29155
|
if (!fs15.existsSync(providerJson)) {
|
|
27937
29156
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
27938
29157
|
}
|
|
@@ -27968,7 +29187,7 @@ var DevServer = class _DevServer {
|
|
|
27968
29187
|
setMode: "set_mode.js"
|
|
27969
29188
|
};
|
|
27970
29189
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
27971
|
-
const scriptsDir =
|
|
29190
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
27972
29191
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
27973
29192
|
if (latestScriptsDir) {
|
|
27974
29193
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -27979,7 +29198,7 @@ var DevServer = class _DevServer {
|
|
|
27979
29198
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
27980
29199
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
27981
29200
|
try {
|
|
27982
|
-
const content = fs15.readFileSync(
|
|
29201
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
27983
29202
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
27984
29203
|
lines.push("```javascript");
|
|
27985
29204
|
lines.push(content);
|
|
@@ -27996,7 +29215,7 @@ var DevServer = class _DevServer {
|
|
|
27996
29215
|
lines.push("");
|
|
27997
29216
|
for (const file of refFiles) {
|
|
27998
29217
|
try {
|
|
27999
|
-
const content = fs15.readFileSync(
|
|
29218
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28000
29219
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28001
29220
|
lines.push("```javascript");
|
|
28002
29221
|
lines.push(content);
|
|
@@ -28037,10 +29256,10 @@ var DevServer = class _DevServer {
|
|
|
28037
29256
|
lines.push("");
|
|
28038
29257
|
}
|
|
28039
29258
|
}
|
|
28040
|
-
const docsDir =
|
|
29259
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28041
29260
|
const loadGuide = (name) => {
|
|
28042
29261
|
try {
|
|
28043
|
-
const p =
|
|
29262
|
+
const p = path26.join(docsDir, name);
|
|
28044
29263
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28045
29264
|
} catch {
|
|
28046
29265
|
}
|
|
@@ -28214,7 +29433,7 @@ var DevServer = class _DevServer {
|
|
|
28214
29433
|
parseApproval: "parse_approval.js"
|
|
28215
29434
|
};
|
|
28216
29435
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28217
|
-
const scriptsDir =
|
|
29436
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28218
29437
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28219
29438
|
if (latestScriptsDir) {
|
|
28220
29439
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28226,7 +29445,7 @@ var DevServer = class _DevServer {
|
|
|
28226
29445
|
if (!file.endsWith(".js")) continue;
|
|
28227
29446
|
if (!targetFileNames.has(file)) continue;
|
|
28228
29447
|
try {
|
|
28229
|
-
const content = fs15.readFileSync(
|
|
29448
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28230
29449
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28231
29450
|
lines.push("```javascript");
|
|
28232
29451
|
lines.push(content);
|
|
@@ -28242,7 +29461,7 @@ var DevServer = class _DevServer {
|
|
|
28242
29461
|
lines.push("");
|
|
28243
29462
|
for (const file of refFiles) {
|
|
28244
29463
|
try {
|
|
28245
|
-
const content = fs15.readFileSync(
|
|
29464
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28246
29465
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28247
29466
|
lines.push("```javascript");
|
|
28248
29467
|
lines.push(content);
|
|
@@ -28275,10 +29494,10 @@ var DevServer = class _DevServer {
|
|
|
28275
29494
|
lines.push("");
|
|
28276
29495
|
}
|
|
28277
29496
|
}
|
|
28278
|
-
const docsDir =
|
|
29497
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28279
29498
|
const loadGuide = (name) => {
|
|
28280
29499
|
try {
|
|
28281
|
-
const p =
|
|
29500
|
+
const p = path26.join(docsDir, name);
|
|
28282
29501
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28283
29502
|
} catch {
|
|
28284
29503
|
}
|
|
@@ -28969,29 +30188,58 @@ import {
|
|
|
28969
30188
|
} from "@adhdev/session-host-core";
|
|
28970
30189
|
var STARTUP_TIMEOUT_MS = DEFAULT_SESSION_HOST_READY_TIMEOUT_MS;
|
|
28971
30190
|
var STARTUP_POLL_MS = 200;
|
|
28972
|
-
|
|
30191
|
+
var SessionHostCompatibilityError = class extends Error {
|
|
30192
|
+
constructor(message) {
|
|
30193
|
+
super(message);
|
|
30194
|
+
this.name = "SessionHostCompatibilityError";
|
|
30195
|
+
}
|
|
30196
|
+
};
|
|
30197
|
+
function getMissingRequestTypes(diagnostics, requiredRequestTypes) {
|
|
30198
|
+
const supported = new Set(diagnostics?.supportedRequestTypes || []);
|
|
30199
|
+
return requiredRequestTypes.filter((requestType) => !supported.has(requestType));
|
|
30200
|
+
}
|
|
30201
|
+
async function assertRequiredRequestTypes(client, requiredRequestTypes) {
|
|
30202
|
+
if (requiredRequestTypes.length === 0) return;
|
|
30203
|
+
const response = await client.request({
|
|
30204
|
+
type: "get_host_diagnostics",
|
|
30205
|
+
payload: { includeSessions: false }
|
|
30206
|
+
});
|
|
30207
|
+
const missing = getMissingRequestTypes(response.success ? response.result : void 0, requiredRequestTypes);
|
|
30208
|
+
if (missing.length > 0) {
|
|
30209
|
+
const detail = response.success ? "" : ` (${response.error || "capability probe failed"})`;
|
|
30210
|
+
throw new SessionHostCompatibilityError(
|
|
30211
|
+
`Session host does not support required request types: ${missing.join(", ")}${detail}`
|
|
30212
|
+
);
|
|
30213
|
+
}
|
|
30214
|
+
}
|
|
30215
|
+
async function canConnect(endpoint, requiredRequestTypes = []) {
|
|
28973
30216
|
const client = new SessionHostClient2({ endpoint });
|
|
28974
30217
|
try {
|
|
28975
30218
|
await client.connect();
|
|
28976
|
-
await client
|
|
30219
|
+
await assertRequiredRequestTypes(client, requiredRequestTypes);
|
|
28977
30220
|
return true;
|
|
28978
|
-
} catch {
|
|
30221
|
+
} catch (error) {
|
|
30222
|
+
if (error instanceof SessionHostCompatibilityError) throw error;
|
|
28979
30223
|
return false;
|
|
30224
|
+
} finally {
|
|
30225
|
+
await client.close().catch(() => {
|
|
30226
|
+
});
|
|
28980
30227
|
}
|
|
28981
30228
|
}
|
|
28982
|
-
async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
|
|
30229
|
+
async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS, requiredRequestTypes = []) {
|
|
28983
30230
|
const deadline = Date.now() + timeoutMs;
|
|
28984
30231
|
while (Date.now() < deadline) {
|
|
28985
|
-
if (await canConnect(endpoint)) return;
|
|
30232
|
+
if (await canConnect(endpoint, requiredRequestTypes)) return;
|
|
28986
30233
|
await new Promise((resolve16) => setTimeout(resolve16, STARTUP_POLL_MS));
|
|
28987
30234
|
}
|
|
28988
30235
|
throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
|
|
28989
30236
|
}
|
|
28990
30237
|
async function ensureSessionHostReady(options) {
|
|
28991
30238
|
const endpoint = getDefaultSessionHostEndpoint(options.appName || "adhdev");
|
|
28992
|
-
|
|
30239
|
+
const requiredRequestTypes = options.requiredRequestTypes || [];
|
|
30240
|
+
if (await canConnect(endpoint, requiredRequestTypes)) return endpoint;
|
|
28993
30241
|
options.spawnHost();
|
|
28994
|
-
await waitForReady(endpoint, options.timeoutMs);
|
|
30242
|
+
await waitForReady(endpoint, options.timeoutMs, requiredRequestTypes);
|
|
28995
30243
|
return endpoint;
|
|
28996
30244
|
}
|
|
28997
30245
|
async function listHostedCliRuntimes(endpoint) {
|
|
@@ -29283,48 +30531,6 @@ var SessionRegistry = class {
|
|
|
29283
30531
|
// src/boot/daemon-lifecycle.ts
|
|
29284
30532
|
init_logger();
|
|
29285
30533
|
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
30534
|
async function initDaemonComponents(config) {
|
|
29329
30535
|
installGlobalInterceptor();
|
|
29330
30536
|
const appConfig = loadConfig();
|
|
@@ -29556,6 +30762,12 @@ export {
|
|
|
29556
30762
|
AcpProviderInstance,
|
|
29557
30763
|
AgentStreamPoller,
|
|
29558
30764
|
BUILTIN_CHAT_MESSAGE_KINDS,
|
|
30765
|
+
CHAT_MESSAGE_ACTIVITY_SOURCES,
|
|
30766
|
+
CHAT_MESSAGE_AUDIENCES,
|
|
30767
|
+
CHAT_MESSAGE_INTERNAL_SOURCES,
|
|
30768
|
+
CHAT_MESSAGE_SOURCES,
|
|
30769
|
+
CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES,
|
|
30770
|
+
CHAT_MESSAGE_VISIBILITIES,
|
|
29559
30771
|
CdpDomHandlers,
|
|
29560
30772
|
CliProviderInstance,
|
|
29561
30773
|
DAEMON_WS_PATH,
|
|
@@ -29618,6 +30830,7 @@ export {
|
|
|
29618
30830
|
buildThoughtChatMessage,
|
|
29619
30831
|
buildToolChatMessage,
|
|
29620
30832
|
buildUserChatMessage,
|
|
30833
|
+
classifyChatMessageVisibility,
|
|
29621
30834
|
classifyHotChatSessionsForSubscriptionFlush,
|
|
29622
30835
|
clearDebugTrace,
|
|
29623
30836
|
compareGitSnapshots,
|
|
@@ -29630,12 +30843,17 @@ export {
|
|
|
29630
30843
|
createGitWorkspaceMonitor,
|
|
29631
30844
|
createInteractionId,
|
|
29632
30845
|
createMesh,
|
|
30846
|
+
createWorktree,
|
|
29633
30847
|
deleteMesh,
|
|
29634
30848
|
detectAllVersions,
|
|
29635
30849
|
detectCLIs,
|
|
29636
30850
|
detectIDEs,
|
|
29637
30851
|
ensureSessionHostReady,
|
|
29638
30852
|
execNpmCommandSync,
|
|
30853
|
+
filterActivityChatMessages,
|
|
30854
|
+
filterChatMessagesByVisibility,
|
|
30855
|
+
filterInternalChatMessages,
|
|
30856
|
+
filterUserFacingChatMessages,
|
|
29639
30857
|
findCdpManager,
|
|
29640
30858
|
flattenMessageParts,
|
|
29641
30859
|
forwardAgentStreamsToIdeInstance,
|
|
@@ -29666,22 +30884,26 @@ export {
|
|
|
29666
30884
|
initDaemonComponents,
|
|
29667
30885
|
installExtensions,
|
|
29668
30886
|
installGlobalInterceptor,
|
|
30887
|
+
isActivityChatMessage,
|
|
29669
30888
|
isBuiltinChatMessageKind,
|
|
29670
30889
|
isCdpConnected,
|
|
29671
30890
|
isExtensionInstalled,
|
|
29672
30891
|
isGitCommandName,
|
|
29673
30892
|
isIdeRunning,
|
|
30893
|
+
isInternalChatMessage,
|
|
29674
30894
|
isManagedStatusWaiting,
|
|
29675
30895
|
isManagedStatusWorking,
|
|
29676
30896
|
isPathInside,
|
|
29677
30897
|
isSessionHostLiveRuntime,
|
|
29678
30898
|
isSessionHostRecoverySnapshot,
|
|
29679
30899
|
isSetupComplete,
|
|
30900
|
+
isUserFacingChatMessage,
|
|
29680
30901
|
killIdeProcess,
|
|
29681
30902
|
launchIDE,
|
|
29682
30903
|
launchWithCdp,
|
|
29683
30904
|
listHostedCliRuntimes,
|
|
29684
30905
|
listMeshes,
|
|
30906
|
+
listWorktrees,
|
|
29685
30907
|
loadConfig,
|
|
29686
30908
|
loadState,
|
|
29687
30909
|
logCommand,
|
|
@@ -29701,6 +30923,7 @@ export {
|
|
|
29701
30923
|
normalizeSessionModalFields,
|
|
29702
30924
|
parsePorcelainV2Status,
|
|
29703
30925
|
parseProviderSourceConfigUpdate,
|
|
30926
|
+
parseWorktreeListOutput,
|
|
29704
30927
|
partitionSessionHostDiagnosticsSessions,
|
|
29705
30928
|
partitionSessionHostRecords,
|
|
29706
30929
|
prepareSessionChatTailUpdate,
|
|
@@ -29710,6 +30933,7 @@ export {
|
|
|
29710
30933
|
recordDebugTrace,
|
|
29711
30934
|
registerExtensionProviders,
|
|
29712
30935
|
removeNode,
|
|
30936
|
+
removeWorktree,
|
|
29713
30937
|
resetConfig,
|
|
29714
30938
|
resetDebugRuntimeConfig,
|
|
29715
30939
|
resetState,
|
|
@@ -29719,6 +30943,7 @@ export {
|
|
|
29719
30943
|
resolveGitRepository,
|
|
29720
30944
|
resolveSessionHostAppName,
|
|
29721
30945
|
resolveSessionHostAppNameResolution,
|
|
30946
|
+
resolveWorktreePath,
|
|
29722
30947
|
runAsyncBatch,
|
|
29723
30948
|
runGit,
|
|
29724
30949
|
saveConfig,
|