@adhdev/daemon-core 0.9.76-rc.5 → 0.9.76-rc.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -1
- package/dist/cli-adapters/provider-cli-runtime.d.ts +1 -0
- package/dist/commands/cli-manager.d.ts +17 -4
- package/dist/commands/mesh-coordinator.d.ts +2 -0
- package/dist/commands/router.d.ts +11 -0
- package/dist/config/mesh-config.d.ts +3 -0
- package/dist/git/git-types.d.ts +1 -1
- package/dist/git/git-worktree.d.ts +64 -0
- package/dist/git/index.d.ts +2 -0
- package/dist/index.js +1398 -436
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1425 -467
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +1 -0
- package/dist/mesh/mesh-events.d.ts +9 -0
- package/dist/providers/chat-message-normalization.d.ts +11 -0
- package/dist/providers/cli-provider-instance.d.ts +3 -0
- package/dist/providers/provider-instance-manager.d.ts +1 -0
- package/dist/providers/provider-instance.d.ts +2 -0
- package/dist/repo-mesh-types.d.ts +13 -0
- package/dist/shared-types.d.ts +4 -0
- package/package.json +4 -5
- package/src/cli-adapters/provider-cli-adapter.ts +28 -7
- package/src/cli-adapters/provider-cli-runtime.ts +3 -2
- package/src/commands/chat-commands.ts +109 -8
- package/src/commands/cli-manager.ts +78 -5
- package/src/commands/handler.ts +13 -4
- package/src/commands/mesh-coordinator.ts +149 -6
- package/src/commands/router.d.ts +1 -0
- package/src/commands/router.ts +554 -34
- package/src/config/mesh-config.ts +23 -2
- package/src/git/git-commands.ts +5 -1
- package/src/git/git-types.ts +1 -0
- package/src/git/git-worktree.ts +214 -0
- package/src/git/index.ts +14 -0
- package/src/mesh/coordinator-prompt.ts +25 -10
- package/src/mesh/mesh-events.ts +109 -43
- package/src/providers/chat-message-normalization.ts +54 -0
- package/src/providers/cli-provider-instance.d.ts +2 -0
- package/src/providers/cli-provider-instance.ts +58 -7
- package/src/providers/provider-instance-manager.ts +20 -1
- package/src/providers/provider-instance.ts +2 -0
- package/src/repo-mesh-types.ts +15 -0
- package/src/shared-types.ts +4 -0
- package/src/status/builders.ts +17 -12
- package/src/status/reporter.ts +6 -0
package/dist/index.js
CHANGED
|
@@ -41,11 +41,140 @@ var init_repo_mesh_types = __esm({
|
|
|
41
41
|
requireApprovalForPush: true,
|
|
42
42
|
requireApprovalForDestructiveGit: true,
|
|
43
43
|
dirtyWorkspaceBehavior: "warn",
|
|
44
|
-
maxParallelTasks: 2
|
|
44
|
+
maxParallelTasks: 2,
|
|
45
|
+
sessionCleanupOnNodeRemove: "preserve"
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
});
|
|
48
49
|
|
|
50
|
+
// src/git/git-worktree.ts
|
|
51
|
+
var git_worktree_exports = {};
|
|
52
|
+
__export(git_worktree_exports, {
|
|
53
|
+
createWorktree: () => createWorktree,
|
|
54
|
+
listWorktrees: () => listWorktrees,
|
|
55
|
+
parseWorktreeListOutput: () => parseWorktreeListOutput,
|
|
56
|
+
removeWorktree: () => removeWorktree,
|
|
57
|
+
resolveWorktreePath: () => resolveWorktreePath
|
|
58
|
+
});
|
|
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 ((0, import_node_fs2.existsSync)(targetDir)) {
|
|
69
|
+
throw new Error(`Worktree target directory already exists: ${targetDir}`);
|
|
70
|
+
}
|
|
71
|
+
await (0, import_promises3.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 (!(0, import_node_fs2.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 path4, import_promises3, import_node_fs2, import_node_child_process2, import_node_util2, 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
|
+
path4 = __toESM(require("path"));
|
|
167
|
+
import_promises3 = require("fs/promises");
|
|
168
|
+
import_node_fs2 = require("fs");
|
|
169
|
+
import_node_child_process2 = require("child_process");
|
|
170
|
+
import_node_util2 = require("util");
|
|
171
|
+
execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
|
|
172
|
+
WORKTREE_DIR_NAME = ".adhdev-worktrees";
|
|
173
|
+
GIT_TIMEOUT_MS = 3e4;
|
|
174
|
+
GIT_MAX_BUFFER = 4 * 1024 * 1024;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
49
178
|
// src/config/config.ts
|
|
50
179
|
var config_exports = {};
|
|
51
180
|
__export(config_exports, {
|
|
@@ -304,10 +433,10 @@ function getMeshConfigPath() {
|
|
|
304
433
|
return (0, import_path2.join)(getConfigDir(), "meshes.json");
|
|
305
434
|
}
|
|
306
435
|
function loadMeshConfig() {
|
|
307
|
-
const
|
|
308
|
-
if (!(0, import_fs2.existsSync)(
|
|
436
|
+
const path27 = getMeshConfigPath();
|
|
437
|
+
if (!(0, import_fs2.existsSync)(path27)) return { meshes: [] };
|
|
309
438
|
try {
|
|
310
|
-
const raw = JSON.parse((0, import_fs2.readFileSync)(
|
|
439
|
+
const raw = JSON.parse((0, import_fs2.readFileSync)(path27, "utf-8"));
|
|
311
440
|
if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
|
|
312
441
|
return raw;
|
|
313
442
|
} catch {
|
|
@@ -315,16 +444,16 @@ function loadMeshConfig() {
|
|
|
315
444
|
}
|
|
316
445
|
}
|
|
317
446
|
function saveMeshConfig(config) {
|
|
318
|
-
const
|
|
319
|
-
(0, import_fs2.writeFileSync)(
|
|
447
|
+
const path27 = getMeshConfigPath();
|
|
448
|
+
(0, import_fs2.writeFileSync)(path27, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
|
|
320
449
|
}
|
|
321
450
|
function normalizeRepoIdentity(remoteUrl) {
|
|
322
451
|
let identity = remoteUrl.trim();
|
|
323
452
|
if (identity.startsWith("http://") || identity.startsWith("https://")) {
|
|
324
453
|
try {
|
|
325
454
|
const url = new URL(identity);
|
|
326
|
-
const
|
|
327
|
-
return `${url.hostname}/${
|
|
455
|
+
const path27 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
|
|
456
|
+
return `${url.hostname}/${path27}`;
|
|
328
457
|
} catch {
|
|
329
458
|
}
|
|
330
459
|
}
|
|
@@ -332,6 +461,18 @@ function normalizeRepoIdentity(remoteUrl) {
|
|
|
332
461
|
if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
|
|
333
462
|
return identity;
|
|
334
463
|
}
|
|
464
|
+
function mergeMeshPolicy(base, patch) {
|
|
465
|
+
const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
|
|
466
|
+
if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
|
|
467
|
+
policy.dirtyWorkspaceBehavior = "warn";
|
|
468
|
+
}
|
|
469
|
+
const maxParallelTasks = Number(policy.maxParallelTasks);
|
|
470
|
+
policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
|
|
471
|
+
if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
|
|
472
|
+
policy.sessionCleanupOnNodeRemove = "preserve";
|
|
473
|
+
}
|
|
474
|
+
return policy;
|
|
475
|
+
}
|
|
335
476
|
function listMeshes() {
|
|
336
477
|
return loadMeshConfig().meshes;
|
|
337
478
|
}
|
|
@@ -355,7 +496,7 @@ function createMesh(opts) {
|
|
|
355
496
|
repoIdentity,
|
|
356
497
|
repoRemoteUrl: opts.repoRemoteUrl,
|
|
357
498
|
defaultBranch: opts.defaultBranch,
|
|
358
|
-
policy:
|
|
499
|
+
policy: mergeMeshPolicy(void 0, opts.policy),
|
|
359
500
|
coordinator: opts.coordinator || {},
|
|
360
501
|
nodes: [],
|
|
361
502
|
createdAt: now,
|
|
@@ -371,7 +512,7 @@ function updateMesh(meshId, opts) {
|
|
|
371
512
|
if (!mesh) return void 0;
|
|
372
513
|
if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
|
|
373
514
|
if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
|
|
374
|
-
if (opts.policy) mesh.policy =
|
|
515
|
+
if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
|
|
375
516
|
if (opts.coordinator) mesh.coordinator = opts.coordinator;
|
|
376
517
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
377
518
|
saveMeshConfig(config);
|
|
@@ -399,9 +540,12 @@ function addNode(meshId, opts) {
|
|
|
399
540
|
id: `node_${(0, import_crypto3.randomUUID)().replace(/-/g, "")}`,
|
|
400
541
|
workspace: opts.workspace.trim(),
|
|
401
542
|
repoRoot: opts.repoRoot,
|
|
543
|
+
daemonId: opts.daemonId,
|
|
402
544
|
userOverrides: opts.userOverrides || {},
|
|
403
545
|
policy: opts.policy || {},
|
|
404
|
-
isLocalWorktree: opts.isLocalWorktree
|
|
546
|
+
isLocalWorktree: opts.isLocalWorktree,
|
|
547
|
+
worktreeBranch: opts.worktreeBranch,
|
|
548
|
+
clonedFromNodeId: opts.clonedFromNodeId
|
|
405
549
|
};
|
|
406
550
|
mesh.nodes.push(node);
|
|
407
551
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -431,7 +575,7 @@ function updateNode(meshId, nodeId, opts) {
|
|
|
431
575
|
saveMeshConfig(config);
|
|
432
576
|
return node;
|
|
433
577
|
}
|
|
434
|
-
var import_fs2, import_path2, import_crypto3;
|
|
578
|
+
var import_fs2, import_path2, import_crypto3, SESSION_CLEANUP_MODES;
|
|
435
579
|
var init_mesh_config = __esm({
|
|
436
580
|
"src/config/mesh-config.ts"() {
|
|
437
581
|
"use strict";
|
|
@@ -440,6 +584,7 @@ var init_mesh_config = __esm({
|
|
|
440
584
|
import_crypto3 = require("crypto");
|
|
441
585
|
init_config();
|
|
442
586
|
init_repo_mesh_types();
|
|
587
|
+
SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
|
|
443
588
|
}
|
|
444
589
|
});
|
|
445
590
|
|
|
@@ -449,7 +594,7 @@ __export(coordinator_prompt_exports, {
|
|
|
449
594
|
buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
|
|
450
595
|
});
|
|
451
596
|
function buildCoordinatorSystemPrompt(ctx) {
|
|
452
|
-
const { mesh, status, userInstruction } = ctx;
|
|
597
|
+
const { mesh, status, userInstruction, coordinatorCliType } = ctx;
|
|
453
598
|
const sections = [];
|
|
454
599
|
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.
|
|
455
600
|
|
|
@@ -463,15 +608,15 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
463
608
|
} else {
|
|
464
609
|
sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
|
|
465
610
|
}
|
|
466
|
-
sections.push(buildPolicySection(mesh.policy));
|
|
611
|
+
sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
|
|
467
612
|
sections.push(TOOLS_SECTION);
|
|
468
613
|
sections.push(WORKFLOW_SECTION);
|
|
469
|
-
sections.push(
|
|
614
|
+
sections.push(buildRulesSection(coordinatorCliType));
|
|
470
615
|
if (userInstruction) {
|
|
471
616
|
sections.push(`## Additional Context
|
|
472
617
|
${userInstruction}`);
|
|
473
618
|
}
|
|
474
|
-
if (mesh.coordinator
|
|
619
|
+
if (mesh.coordinator?.systemPromptSuffix) {
|
|
475
620
|
sections.push(mesh.coordinator.systemPromptSuffix);
|
|
476
621
|
}
|
|
477
622
|
return sections.join("\n\n");
|
|
@@ -516,10 +661,29 @@ function buildPolicySection(policy) {
|
|
|
516
661
|
return `## Policy
|
|
517
662
|
${rules.join("\n")}`;
|
|
518
663
|
}
|
|
519
|
-
|
|
664
|
+
function buildRulesSection(coordinatorCliType) {
|
|
665
|
+
const coordinatorNote = coordinatorCliType ? `
|
|
666
|
+
- **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.` : "";
|
|
667
|
+
return `## Rules
|
|
668
|
+
|
|
669
|
+
- **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.
|
|
670
|
+
- **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.
|
|
671
|
+
- **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.
|
|
672
|
+
- **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.
|
|
673
|
+
- **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
|
|
674
|
+
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
|
|
675
|
+
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
676
|
+
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
677
|
+
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
678
|
+
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.
|
|
679
|
+
- **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
|
|
680
|
+
- **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
|
|
681
|
+
}
|
|
682
|
+
var TOOLS_SECTION, WORKFLOW_SECTION;
|
|
520
683
|
var init_coordinator_prompt = __esm({
|
|
521
684
|
"src/mesh/coordinator-prompt.ts"() {
|
|
522
685
|
"use strict";
|
|
686
|
+
init_repo_mesh_types();
|
|
523
687
|
TOOLS_SECTION = `## Available Tools
|
|
524
688
|
|
|
525
689
|
| Tool | Purpose |
|
|
@@ -531,30 +695,23 @@ var init_coordinator_prompt = __esm({
|
|
|
531
695
|
| \`mesh_read_chat\` | Read an agent's recent messages to check progress |
|
|
532
696
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
533
697
|
| \`mesh_checkpoint\` | Create a git checkpoint on a node |
|
|
534
|
-
| \`mesh_approve\` | Approve/reject a pending agent action
|
|
698
|
+
| \`mesh_approve\` | Approve/reject a pending agent action |
|
|
699
|
+
| \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
|
|
700
|
+
| \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |`;
|
|
535
701
|
WORKFLOW_SECTION = `## Orchestration Workflow
|
|
536
702
|
|
|
537
703
|
1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
|
|
538
704
|
2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
|
|
539
705
|
3. **Delegate** \u2014 For each task:
|
|
540
706
|
a. Pick the best node (consider: health, dirty state, current workload).
|
|
541
|
-
b. If
|
|
542
|
-
c.
|
|
707
|
+
b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
|
|
708
|
+
c. If no session exists, call \`mesh_launch_session\` to start one.
|
|
709
|
+
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.
|
|
543
710
|
4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
|
|
544
711
|
5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
|
|
545
712
|
6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
|
|
546
|
-
7. **
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
- **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.
|
|
550
|
-
- **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.
|
|
551
|
-
- **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.
|
|
552
|
-
- **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
|
|
553
|
-
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
|
|
554
|
-
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
555
|
-
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
556
|
-
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
557
|
-
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
|
|
713
|
+
7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
|
|
714
|
+
8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
|
|
558
715
|
}
|
|
559
716
|
});
|
|
560
717
|
|
|
@@ -573,13 +730,13 @@ function getDaemonLogDir() {
|
|
|
573
730
|
return LOG_DIR;
|
|
574
731
|
}
|
|
575
732
|
function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
|
|
576
|
-
return
|
|
733
|
+
return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
|
|
577
734
|
}
|
|
578
735
|
function checkDateRotation() {
|
|
579
736
|
const today = getDateStr();
|
|
580
737
|
if (today !== currentDate) {
|
|
581
738
|
currentDate = today;
|
|
582
|
-
currentLogFile =
|
|
739
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
583
740
|
cleanOldLogs();
|
|
584
741
|
}
|
|
585
742
|
}
|
|
@@ -593,7 +750,7 @@ function cleanOldLogs() {
|
|
|
593
750
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
594
751
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
595
752
|
try {
|
|
596
|
-
fs2.unlinkSync(
|
|
753
|
+
fs2.unlinkSync(path10.join(LOG_DIR, file));
|
|
597
754
|
} catch {
|
|
598
755
|
}
|
|
599
756
|
}
|
|
@@ -709,17 +866,17 @@ function installGlobalInterceptor() {
|
|
|
709
866
|
writeToFile(`Log file: ${currentLogFile}`);
|
|
710
867
|
writeToFile(`Log level: ${currentLevel}`);
|
|
711
868
|
}
|
|
712
|
-
var fs2,
|
|
869
|
+
var fs2, path10, os4, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
|
|
713
870
|
var init_logger = __esm({
|
|
714
871
|
"src/logging/logger.ts"() {
|
|
715
872
|
"use strict";
|
|
716
873
|
fs2 = __toESM(require("fs"));
|
|
717
|
-
|
|
874
|
+
path10 = __toESM(require("path"));
|
|
718
875
|
os4 = __toESM(require("os"));
|
|
719
876
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
720
877
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
721
878
|
currentLevel = "info";
|
|
722
|
-
LOG_DIR = process.platform === "win32" ?
|
|
879
|
+
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");
|
|
723
880
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
724
881
|
MAX_LOG_DAYS = 7;
|
|
725
882
|
try {
|
|
@@ -727,16 +884,16 @@ var init_logger = __esm({
|
|
|
727
884
|
} catch {
|
|
728
885
|
}
|
|
729
886
|
currentDate = getDateStr();
|
|
730
|
-
currentLogFile =
|
|
887
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
731
888
|
cleanOldLogs();
|
|
732
889
|
try {
|
|
733
|
-
const oldLog =
|
|
890
|
+
const oldLog = path10.join(LOG_DIR, "daemon.log");
|
|
734
891
|
if (fs2.existsSync(oldLog)) {
|
|
735
892
|
const stat2 = fs2.statSync(oldLog);
|
|
736
893
|
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
737
|
-
fs2.renameSync(oldLog,
|
|
894
|
+
fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
738
895
|
}
|
|
739
|
-
const oldLogBackup =
|
|
896
|
+
const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
|
|
740
897
|
if (fs2.existsSync(oldLogBackup)) {
|
|
741
898
|
fs2.unlinkSync(oldLogBackup);
|
|
742
899
|
}
|
|
@@ -768,7 +925,7 @@ var init_logger = __esm({
|
|
|
768
925
|
}
|
|
769
926
|
};
|
|
770
927
|
interceptorInstalled = false;
|
|
771
|
-
LOG_PATH =
|
|
928
|
+
LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
772
929
|
}
|
|
773
930
|
});
|
|
774
931
|
|
|
@@ -1236,9 +1393,9 @@ function buildCliScreenSnapshot(text) {
|
|
|
1236
1393
|
function findBinary(name) {
|
|
1237
1394
|
const trimmed = String(name || "").trim();
|
|
1238
1395
|
if (!trimmed) return trimmed;
|
|
1239
|
-
const expanded = trimmed.startsWith("~") ?
|
|
1240
|
-
if (
|
|
1241
|
-
return
|
|
1396
|
+
const expanded = trimmed.startsWith("~") ? path14.join(os9.homedir(), trimmed.slice(1)) : trimmed;
|
|
1397
|
+
if (path14.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
|
|
1398
|
+
return path14.isAbsolute(expanded) ? expanded : path14.resolve(expanded);
|
|
1242
1399
|
}
|
|
1243
1400
|
const isWin = os9.platform() === "win32";
|
|
1244
1401
|
try {
|
|
@@ -1254,7 +1411,7 @@ function findBinary(name) {
|
|
|
1254
1411
|
}
|
|
1255
1412
|
}
|
|
1256
1413
|
function isScriptBinary(binaryPath) {
|
|
1257
|
-
if (!
|
|
1414
|
+
if (!path14.isAbsolute(binaryPath)) return false;
|
|
1258
1415
|
try {
|
|
1259
1416
|
const fs16 = require("fs");
|
|
1260
1417
|
const resolved = fs16.realpathSync(binaryPath);
|
|
@@ -1270,7 +1427,7 @@ function isScriptBinary(binaryPath) {
|
|
|
1270
1427
|
}
|
|
1271
1428
|
}
|
|
1272
1429
|
function looksLikeMachOOrElf(filePath) {
|
|
1273
|
-
if (!
|
|
1430
|
+
if (!path14.isAbsolute(filePath)) return false;
|
|
1274
1431
|
try {
|
|
1275
1432
|
const fs16 = require("fs");
|
|
1276
1433
|
const resolved = fs16.realpathSync(filePath);
|
|
@@ -1359,12 +1516,12 @@ function normalizeCliProviderForRuntime(raw) {
|
|
|
1359
1516
|
}
|
|
1360
1517
|
};
|
|
1361
1518
|
}
|
|
1362
|
-
var os9,
|
|
1519
|
+
var os9, path14, import_child_process4, buildCliSpawnEnv;
|
|
1363
1520
|
var init_provider_cli_shared = __esm({
|
|
1364
1521
|
"src/cli-adapters/provider-cli-shared.ts"() {
|
|
1365
1522
|
"use strict";
|
|
1366
1523
|
os9 = __toESM(require("os"));
|
|
1367
|
-
|
|
1524
|
+
path14 = __toESM(require("path"));
|
|
1368
1525
|
import_child_process4 = require("child_process");
|
|
1369
1526
|
init_spawn_env();
|
|
1370
1527
|
buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
|
|
@@ -1487,7 +1644,7 @@ var init_provider_cli_config = __esm({
|
|
|
1487
1644
|
|
|
1488
1645
|
// src/cli-adapters/provider-cli-runtime.ts
|
|
1489
1646
|
function resolveCliSpawnPlan(options) {
|
|
1490
|
-
const { provider, runtimeSettings, workingDir, extraArgs } = options;
|
|
1647
|
+
const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
|
|
1491
1648
|
const { spawn: spawnConfig } = provider;
|
|
1492
1649
|
const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
|
|
1493
1650
|
const binaryPath = findBinary(configuredCommand);
|
|
@@ -1495,9 +1652,9 @@ function resolveCliSpawnPlan(options) {
|
|
|
1495
1652
|
const allArgs = [...spawnConfig.args, ...extraArgs];
|
|
1496
1653
|
let shellCmd;
|
|
1497
1654
|
let shellArgs;
|
|
1498
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1655
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1499
1656
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
1500
|
-
const useShellWin = !!spawnConfig.shell || isCmdShim || !
|
|
1657
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
1501
1658
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
1502
1659
|
if (useShell) {
|
|
1503
1660
|
shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
|
|
@@ -1511,7 +1668,7 @@ function resolveCliSpawnPlan(options) {
|
|
|
1511
1668
|
shellCmd = binaryPath;
|
|
1512
1669
|
shellArgs = allArgs;
|
|
1513
1670
|
}
|
|
1514
|
-
const env = buildCliSpawnEnv(process.env, spawnConfig.env);
|
|
1671
|
+
const env = buildCliSpawnEnv(process.env, { ...spawnConfig.env || {}, ...extraEnv || {} });
|
|
1515
1672
|
env.TERMINAL_CWD = workingDir;
|
|
1516
1673
|
return {
|
|
1517
1674
|
binaryPath,
|
|
@@ -1573,12 +1730,12 @@ function respondToCliTerminalQueries(options) {
|
|
|
1573
1730
|
}
|
|
1574
1731
|
return "";
|
|
1575
1732
|
}
|
|
1576
|
-
var os10,
|
|
1733
|
+
var os10, path15, import_session_host_core2;
|
|
1577
1734
|
var init_provider_cli_runtime = __esm({
|
|
1578
1735
|
"src/cli-adapters/provider-cli-runtime.ts"() {
|
|
1579
1736
|
"use strict";
|
|
1580
1737
|
os10 = __toESM(require("os"));
|
|
1581
|
-
|
|
1738
|
+
path15 = __toESM(require("path"));
|
|
1582
1739
|
import_session_host_core2 = require("@adhdev/session-host-core");
|
|
1583
1740
|
init_provider_cli_shared();
|
|
1584
1741
|
}
|
|
@@ -1614,8 +1771,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1614
1771
|
init_provider_cli_runtime();
|
|
1615
1772
|
init_provider_cli_shared();
|
|
1616
1773
|
ProviderCliAdapter = class _ProviderCliAdapter {
|
|
1617
|
-
constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
|
|
1774
|
+
constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
|
|
1618
1775
|
this.extraArgs = extraArgs;
|
|
1776
|
+
this.extraEnv = extraEnv;
|
|
1619
1777
|
this.provider = provider;
|
|
1620
1778
|
this.transportFactory = transportFactory;
|
|
1621
1779
|
this.cliType = provider.type;
|
|
@@ -1766,8 +1924,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1766
1924
|
const currentSnapshot = normalizeScreenSnapshot(screenText);
|
|
1767
1925
|
const lastSnapshot = this.lastScreenSnapshot;
|
|
1768
1926
|
if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
|
|
1769
|
-
const
|
|
1770
|
-
const
|
|
1927
|
+
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;
|
|
1928
|
+
const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
|
|
1929
|
+
const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
|
|
1771
1930
|
if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
|
|
1772
1931
|
if (currentSnapshot.length >= lastSnapshot.length) return screenText;
|
|
1773
1932
|
return `${screenText}
|
|
@@ -1930,7 +2089,8 @@ ${lastSnapshot}`;
|
|
|
1930
2089
|
provider: this.provider,
|
|
1931
2090
|
runtimeSettings: this.runtimeSettings,
|
|
1932
2091
|
workingDir: this.workingDir,
|
|
1933
|
-
extraArgs: this.extraArgs
|
|
2092
|
+
extraArgs: this.extraArgs,
|
|
2093
|
+
extraEnv: this.extraEnv
|
|
1934
2094
|
});
|
|
1935
2095
|
LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
1936
2096
|
this.resetTraceSession();
|
|
@@ -3128,9 +3288,8 @@ ${lastSnapshot}`;
|
|
|
3128
3288
|
};
|
|
3129
3289
|
this.recordTrace("submit_echo_missing", diagnostic);
|
|
3130
3290
|
if (this.requirePromptEchoBeforeSubmit) {
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
completion.rejectOnce(new Error(message));
|
|
3291
|
+
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)}`);
|
|
3292
|
+
this.submitSendKey(state, completion);
|
|
3134
3293
|
return;
|
|
3135
3294
|
}
|
|
3136
3295
|
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
|
|
@@ -3177,7 +3336,14 @@ ${lastSnapshot}`;
|
|
|
3177
3336
|
})() : null;
|
|
3178
3337
|
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
|
|
3179
3338
|
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
|
|
3180
|
-
|
|
3339
|
+
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
3340
|
+
const parsedHasActionableModal = Boolean(
|
|
3341
|
+
parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
|
|
3342
|
+
);
|
|
3343
|
+
const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
|
|
3344
|
+
if (!terminalLooksIdle) {
|
|
3345
|
+
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
3346
|
+
}
|
|
3181
3347
|
}
|
|
3182
3348
|
if (this.isWaitingForResponse && !allowInputDuringGeneration) {
|
|
3183
3349
|
if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
|
|
@@ -3727,6 +3893,7 @@ __export(index_exports, {
|
|
|
3727
3893
|
createGitWorkspaceMonitor: () => createGitWorkspaceMonitor,
|
|
3728
3894
|
createInteractionId: () => createInteractionId,
|
|
3729
3895
|
createMesh: () => createMesh,
|
|
3896
|
+
createWorktree: () => createWorktree,
|
|
3730
3897
|
deleteMesh: () => deleteMesh,
|
|
3731
3898
|
detectAllVersions: () => detectAllVersions,
|
|
3732
3899
|
detectCLIs: () => detectCLIs,
|
|
@@ -3779,6 +3946,7 @@ __export(index_exports, {
|
|
|
3779
3946
|
launchWithCdp: () => launchWithCdp,
|
|
3780
3947
|
listHostedCliRuntimes: () => listHostedCliRuntimes,
|
|
3781
3948
|
listMeshes: () => listMeshes,
|
|
3949
|
+
listWorktrees: () => listWorktrees,
|
|
3782
3950
|
loadConfig: () => loadConfig,
|
|
3783
3951
|
loadState: () => loadState,
|
|
3784
3952
|
logCommand: () => logCommand,
|
|
@@ -3798,6 +3966,7 @@ __export(index_exports, {
|
|
|
3798
3966
|
normalizeSessionModalFields: () => normalizeSessionModalFields,
|
|
3799
3967
|
parsePorcelainV2Status: () => parsePorcelainV2Status,
|
|
3800
3968
|
parseProviderSourceConfigUpdate: () => parseProviderSourceConfigUpdate,
|
|
3969
|
+
parseWorktreeListOutput: () => parseWorktreeListOutput,
|
|
3801
3970
|
partitionSessionHostDiagnosticsSessions: () => partitionSessionHostDiagnosticsSessions,
|
|
3802
3971
|
partitionSessionHostRecords: () => partitionSessionHostRecords,
|
|
3803
3972
|
prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
|
|
@@ -3807,6 +3976,7 @@ __export(index_exports, {
|
|
|
3807
3976
|
recordDebugTrace: () => recordDebugTrace,
|
|
3808
3977
|
registerExtensionProviders: () => registerExtensionProviders,
|
|
3809
3978
|
removeNode: () => removeNode,
|
|
3979
|
+
removeWorktree: () => removeWorktree,
|
|
3810
3980
|
resetConfig: () => resetConfig,
|
|
3811
3981
|
resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
|
|
3812
3982
|
resetState: () => resetState,
|
|
@@ -3816,6 +3986,7 @@ __export(index_exports, {
|
|
|
3816
3986
|
resolveGitRepository: () => resolveGitRepository,
|
|
3817
3987
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
3818
3988
|
resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
|
|
3989
|
+
resolveWorktreePath: () => resolveWorktreePath,
|
|
3819
3990
|
runAsyncBatch: () => runAsyncBatch,
|
|
3820
3991
|
runGit: () => runGit,
|
|
3821
3992
|
saveConfig: () => saveConfig,
|
|
@@ -4739,6 +4910,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
|
4739
4910
|
"dirty_index_required",
|
|
4740
4911
|
"conflict",
|
|
4741
4912
|
"invalid_args",
|
|
4913
|
+
"nothing_to_commit",
|
|
4742
4914
|
"git_command_failed"
|
|
4743
4915
|
]);
|
|
4744
4916
|
function failure(reason, error) {
|
|
@@ -4983,7 +5155,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
|
4983
5155
|
} catch (err) {
|
|
4984
5156
|
const output = (err?.stdout || "") + (err?.stderr || "");
|
|
4985
5157
|
if (/nothing to commit/i.test(output)) {
|
|
4986
|
-
throw new GitCommandError("
|
|
5158
|
+
throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
|
|
5159
|
+
stdout: err?.stdout,
|
|
5160
|
+
stderr: err?.stderr
|
|
5161
|
+
});
|
|
4987
5162
|
}
|
|
4988
5163
|
throw err;
|
|
4989
5164
|
}
|
|
@@ -5175,20 +5350,23 @@ var TurnSnapshotTracker = class {
|
|
|
5175
5350
|
}
|
|
5176
5351
|
};
|
|
5177
5352
|
|
|
5353
|
+
// src/git/index.ts
|
|
5354
|
+
init_git_worktree();
|
|
5355
|
+
|
|
5178
5356
|
// src/index.ts
|
|
5179
5357
|
init_config();
|
|
5180
5358
|
|
|
5181
5359
|
// src/config/workspaces.ts
|
|
5182
5360
|
var fs = __toESM(require("fs"));
|
|
5183
5361
|
var os = __toESM(require("os"));
|
|
5184
|
-
var
|
|
5362
|
+
var path5 = __toESM(require("path"));
|
|
5185
5363
|
var import_crypto2 = require("crypto");
|
|
5186
5364
|
var MAX_WORKSPACES = 50;
|
|
5187
5365
|
function expandPath(p) {
|
|
5188
5366
|
const t = (p || "").trim();
|
|
5189
5367
|
if (!t) return "";
|
|
5190
|
-
if (t.startsWith("~")) return
|
|
5191
|
-
return
|
|
5368
|
+
if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5369
|
+
return path5.resolve(t);
|
|
5192
5370
|
}
|
|
5193
5371
|
function validateWorkspacePath(absPath) {
|
|
5194
5372
|
try {
|
|
@@ -5202,7 +5380,7 @@ function validateWorkspacePath(absPath) {
|
|
|
5202
5380
|
}
|
|
5203
5381
|
}
|
|
5204
5382
|
function defaultWorkspaceLabel(absPath) {
|
|
5205
|
-
const base =
|
|
5383
|
+
const base = path5.basename(absPath) || absPath;
|
|
5206
5384
|
return base;
|
|
5207
5385
|
}
|
|
5208
5386
|
function getDefaultWorkspacePath(config) {
|
|
@@ -5293,9 +5471,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
5293
5471
|
return getDefaultWorkspacePath(config) || void 0;
|
|
5294
5472
|
}
|
|
5295
5473
|
function findWorkspaceByPath(config, rawPath) {
|
|
5296
|
-
const abs =
|
|
5474
|
+
const abs = path5.resolve(expandPath(rawPath));
|
|
5297
5475
|
if (!abs) return void 0;
|
|
5298
|
-
return (config.workspaces || []).find((w) =>
|
|
5476
|
+
return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
|
|
5299
5477
|
}
|
|
5300
5478
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
5301
5479
|
const abs = expandPath(rawPath);
|
|
@@ -5311,7 +5489,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
5311
5489
|
const v = validateWorkspacePath(abs);
|
|
5312
5490
|
if (!v.ok) return { error: v.error };
|
|
5313
5491
|
const list = [...config.workspaces || []];
|
|
5314
|
-
if (list.some((w) =>
|
|
5492
|
+
if (list.some((w) => path5.resolve(w.path) === abs)) {
|
|
5315
5493
|
return { error: "Workspace already in list" };
|
|
5316
5494
|
}
|
|
5317
5495
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -5345,7 +5523,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
5345
5523
|
}
|
|
5346
5524
|
|
|
5347
5525
|
// src/config/recent-activity.ts
|
|
5348
|
-
var
|
|
5526
|
+
var path6 = __toESM(require("path"));
|
|
5349
5527
|
|
|
5350
5528
|
// src/providers/summary-metadata.ts
|
|
5351
5529
|
function normalizeSummaryItem(item) {
|
|
@@ -5414,9 +5592,9 @@ var MAX_ACTIVITY = 30;
|
|
|
5414
5592
|
function normalizeWorkspace(workspace) {
|
|
5415
5593
|
if (!workspace) return "";
|
|
5416
5594
|
try {
|
|
5417
|
-
return
|
|
5595
|
+
return path6.resolve(expandPath(workspace));
|
|
5418
5596
|
} catch {
|
|
5419
|
-
return
|
|
5597
|
+
return path6.resolve(workspace);
|
|
5420
5598
|
}
|
|
5421
5599
|
}
|
|
5422
5600
|
function buildRecentActivityKey(entry) {
|
|
@@ -5584,14 +5762,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5584
5762
|
}
|
|
5585
5763
|
|
|
5586
5764
|
// src/config/saved-sessions.ts
|
|
5587
|
-
var
|
|
5765
|
+
var path7 = __toESM(require("path"));
|
|
5588
5766
|
var MAX_SAVED_SESSIONS = 500;
|
|
5589
5767
|
function normalizeWorkspace2(workspace) {
|
|
5590
5768
|
if (!workspace) return "";
|
|
5591
5769
|
try {
|
|
5592
|
-
return
|
|
5770
|
+
return path7.resolve(expandPath(workspace));
|
|
5593
5771
|
} catch {
|
|
5594
|
-
return
|
|
5772
|
+
return path7.resolve(workspace);
|
|
5595
5773
|
}
|
|
5596
5774
|
}
|
|
5597
5775
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5770,7 +5948,7 @@ function resetState() {
|
|
|
5770
5948
|
var import_child_process = require("child_process");
|
|
5771
5949
|
var import_fs4 = require("fs");
|
|
5772
5950
|
var import_os2 = require("os");
|
|
5773
|
-
var
|
|
5951
|
+
var path8 = __toESM(require("path"));
|
|
5774
5952
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5775
5953
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5776
5954
|
function registerIDEDefinition(def) {
|
|
@@ -5789,9 +5967,9 @@ function getMergedDefinitions() {
|
|
|
5789
5967
|
function findCliCommand(command) {
|
|
5790
5968
|
const trimmed = String(command || "").trim();
|
|
5791
5969
|
if (!trimmed) return null;
|
|
5792
|
-
if (
|
|
5793
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5794
|
-
const resolved =
|
|
5970
|
+
if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
5971
|
+
const candidate = trimmed.startsWith("~") ? path8.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
|
|
5972
|
+
const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
|
|
5795
5973
|
return (0, import_fs4.existsSync)(resolved) ? resolved : null;
|
|
5796
5974
|
}
|
|
5797
5975
|
try {
|
|
@@ -5819,7 +5997,7 @@ function getIdeVersion(cliCommand) {
|
|
|
5819
5997
|
function checkPathExists(paths) {
|
|
5820
5998
|
const home = (0, import_os2.homedir)();
|
|
5821
5999
|
for (const p of paths) {
|
|
5822
|
-
const normalized = p.startsWith("~") ?
|
|
6000
|
+
const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
|
|
5823
6001
|
if (normalized.includes("*")) {
|
|
5824
6002
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5825
6003
|
const resolved = normalized.replace("*", username);
|
|
@@ -5831,19 +6009,19 @@ function checkPathExists(paths) {
|
|
|
5831
6009
|
return null;
|
|
5832
6010
|
}
|
|
5833
6011
|
async function detectIDEs(providerLoader) {
|
|
5834
|
-
const
|
|
6012
|
+
const os22 = (0, import_os2.platform)();
|
|
5835
6013
|
const results = [];
|
|
5836
6014
|
for (const def of getMergedDefinitions()) {
|
|
5837
6015
|
const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
|
|
5838
|
-
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[
|
|
6016
|
+
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
|
|
5839
6017
|
let resolvedCli = cliPath;
|
|
5840
|
-
if (!resolvedCli && appPath &&
|
|
6018
|
+
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
5841
6019
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
5842
6020
|
if ((0, import_fs4.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
5843
6021
|
}
|
|
5844
|
-
if (!resolvedCli && appPath &&
|
|
5845
|
-
const { dirname:
|
|
5846
|
-
const appDir =
|
|
6022
|
+
if (!resolvedCli && appPath && os22 === "win32") {
|
|
6023
|
+
const { dirname: dirname9 } = await import("path");
|
|
6024
|
+
const appDir = dirname9(appPath);
|
|
5847
6025
|
const candidates = [
|
|
5848
6026
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
5849
6027
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -5858,7 +6036,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5858
6036
|
}
|
|
5859
6037
|
}
|
|
5860
6038
|
}
|
|
5861
|
-
const installed =
|
|
6039
|
+
const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
|
|
5862
6040
|
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
5863
6041
|
results.push({
|
|
5864
6042
|
id: def.id,
|
|
@@ -5877,7 +6055,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5877
6055
|
// src/detection/cli-detector.ts
|
|
5878
6056
|
var import_child_process2 = require("child_process");
|
|
5879
6057
|
var os2 = __toESM(require("os"));
|
|
5880
|
-
var
|
|
6058
|
+
var path9 = __toESM(require("path"));
|
|
5881
6059
|
var import_fs5 = require("fs");
|
|
5882
6060
|
function parseVersion(raw) {
|
|
5883
6061
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
@@ -5890,18 +6068,18 @@ function shellQuote(value) {
|
|
|
5890
6068
|
function expandHome(value) {
|
|
5891
6069
|
const trimmed = value.trim();
|
|
5892
6070
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5893
|
-
return
|
|
6071
|
+
return path9.join(os2.homedir(), trimmed.slice(1));
|
|
5894
6072
|
}
|
|
5895
6073
|
function isExplicitCommandPath(command) {
|
|
5896
6074
|
const trimmed = command.trim();
|
|
5897
|
-
return
|
|
6075
|
+
return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5898
6076
|
}
|
|
5899
6077
|
function resolveCommandPath(command) {
|
|
5900
6078
|
const trimmed = command.trim();
|
|
5901
6079
|
if (!trimmed) return null;
|
|
5902
6080
|
if (isExplicitCommandPath(trimmed)) {
|
|
5903
6081
|
const expanded = expandHome(trimmed);
|
|
5904
|
-
const candidate =
|
|
6082
|
+
const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
|
|
5905
6083
|
return (0, import_fs5.existsSync)(candidate) ? candidate : null;
|
|
5906
6084
|
}
|
|
5907
6085
|
return null;
|
|
@@ -8170,9 +8348,9 @@ ${cleanBody}`;
|
|
|
8170
8348
|
|
|
8171
8349
|
// src/config/chat-history.ts
|
|
8172
8350
|
var fs3 = __toESM(require("fs"));
|
|
8173
|
-
var
|
|
8351
|
+
var path11 = __toESM(require("path"));
|
|
8174
8352
|
var os5 = __toESM(require("os"));
|
|
8175
|
-
var HISTORY_DIR =
|
|
8353
|
+
var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
|
|
8176
8354
|
var RETAIN_DAYS = 30;
|
|
8177
8355
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
8178
8356
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -8335,7 +8513,7 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
8335
8513
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
8336
8514
|
return new Map(files.map((file) => {
|
|
8337
8515
|
try {
|
|
8338
|
-
const stat2 = fs3.statSync(
|
|
8516
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8339
8517
|
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
8340
8518
|
} catch {
|
|
8341
8519
|
return [file, `${file}:missing`];
|
|
@@ -8346,7 +8524,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
8346
8524
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
8347
8525
|
}
|
|
8348
8526
|
function getSavedHistoryIndexFilePath(dir) {
|
|
8349
|
-
return
|
|
8527
|
+
return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
8350
8528
|
}
|
|
8351
8529
|
function getSavedHistoryIndexLockPath(dir) {
|
|
8352
8530
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -8448,7 +8626,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
8448
8626
|
}
|
|
8449
8627
|
for (const file of Array.from(currentEntries.keys())) {
|
|
8450
8628
|
if (incomingFiles.has(file)) continue;
|
|
8451
|
-
if (!fs3.existsSync(
|
|
8629
|
+
if (!fs3.existsSync(path11.join(dir, file))) {
|
|
8452
8630
|
currentEntries.delete(file);
|
|
8453
8631
|
}
|
|
8454
8632
|
}
|
|
@@ -8474,7 +8652,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8474
8652
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8475
8653
|
const files = listHistoryFiles(dir);
|
|
8476
8654
|
for (const file of files) {
|
|
8477
|
-
const stat2 = fs3.statSync(
|
|
8655
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8478
8656
|
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
8479
8657
|
}
|
|
8480
8658
|
return false;
|
|
@@ -8484,14 +8662,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8484
8662
|
}
|
|
8485
8663
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
8486
8664
|
try {
|
|
8487
|
-
const stat2 = fs3.statSync(
|
|
8665
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8488
8666
|
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
8489
8667
|
} catch {
|
|
8490
8668
|
return `${file}:missing`;
|
|
8491
8669
|
}
|
|
8492
8670
|
}
|
|
8493
8671
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
8494
|
-
const filePath =
|
|
8672
|
+
const filePath = path11.join(dir, file);
|
|
8495
8673
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
8496
8674
|
const currentEntry = entries.get(file) || null;
|
|
8497
8675
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -8564,7 +8742,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
8564
8742
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
8565
8743
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
8566
8744
|
if (!historySessionId) return null;
|
|
8567
|
-
const filePath =
|
|
8745
|
+
const filePath = path11.join(dir, file);
|
|
8568
8746
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8569
8747
|
const lines = content.split("\n").filter(Boolean);
|
|
8570
8748
|
let messageCount = 0;
|
|
@@ -8651,7 +8829,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
8651
8829
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
8652
8830
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
8653
8831
|
for (const file of files.slice().sort()) {
|
|
8654
|
-
const filePath =
|
|
8832
|
+
const filePath = path11.join(dir, file);
|
|
8655
8833
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
8656
8834
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
8657
8835
|
const persisted = persistedEntries.get(file);
|
|
@@ -8771,12 +8949,12 @@ var ChatHistoryWriter = class {
|
|
|
8771
8949
|
});
|
|
8772
8950
|
}
|
|
8773
8951
|
if (newMessages.length === 0) return;
|
|
8774
|
-
const dir =
|
|
8952
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8775
8953
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8776
8954
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8777
8955
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
8778
8956
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
8779
|
-
const filePath =
|
|
8957
|
+
const filePath = path11.join(dir, fileName);
|
|
8780
8958
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
8781
8959
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
8782
8960
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -8867,11 +9045,11 @@ var ChatHistoryWriter = class {
|
|
|
8867
9045
|
const ws = String(workspace || "").trim();
|
|
8868
9046
|
if (!id || !ws) return;
|
|
8869
9047
|
try {
|
|
8870
|
-
const dir =
|
|
9048
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8871
9049
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8872
9050
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8873
9051
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
8874
|
-
const filePath =
|
|
9052
|
+
const filePath = path11.join(dir, fileName);
|
|
8875
9053
|
const record = {
|
|
8876
9054
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8877
9055
|
receivedAt: Date.now(),
|
|
@@ -8917,14 +9095,14 @@ var ChatHistoryWriter = class {
|
|
|
8917
9095
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8918
9096
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8919
9097
|
}
|
|
8920
|
-
const dir =
|
|
9098
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8921
9099
|
if (!fs3.existsSync(dir)) return;
|
|
8922
9100
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8923
9101
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8924
9102
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8925
9103
|
for (const file of files) {
|
|
8926
|
-
const sourcePath =
|
|
8927
|
-
const targetPath =
|
|
9104
|
+
const sourcePath = path11.join(dir, file);
|
|
9105
|
+
const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8928
9106
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8929
9107
|
const rewritten = sourceLines.map((line) => {
|
|
8930
9108
|
try {
|
|
@@ -8958,13 +9136,13 @@ var ChatHistoryWriter = class {
|
|
|
8958
9136
|
const sessionId = String(historySessionId || "").trim();
|
|
8959
9137
|
if (!sessionId) return;
|
|
8960
9138
|
try {
|
|
8961
|
-
const dir =
|
|
9139
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8962
9140
|
if (!fs3.existsSync(dir)) return;
|
|
8963
9141
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8964
9142
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8965
9143
|
const seen = /* @__PURE__ */ new Set();
|
|
8966
9144
|
for (const file of files) {
|
|
8967
|
-
const filePath =
|
|
9145
|
+
const filePath = path11.join(dir, file);
|
|
8968
9146
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8969
9147
|
const next = [];
|
|
8970
9148
|
for (const line of lines) {
|
|
@@ -9018,11 +9196,11 @@ var ChatHistoryWriter = class {
|
|
|
9018
9196
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
9019
9197
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
9020
9198
|
for (const dir of agentDirs) {
|
|
9021
|
-
const dirPath =
|
|
9199
|
+
const dirPath = path11.join(HISTORY_DIR, dir.name);
|
|
9022
9200
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
9023
9201
|
let removedAny = false;
|
|
9024
9202
|
for (const file of files) {
|
|
9025
|
-
const filePath =
|
|
9203
|
+
const filePath = path11.join(dirPath, file);
|
|
9026
9204
|
const stat2 = fs3.statSync(filePath);
|
|
9027
9205
|
if (stat2.mtimeMs < cutoff) {
|
|
9028
9206
|
fs3.unlinkSync(filePath);
|
|
@@ -9072,13 +9250,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
9072
9250
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
9073
9251
|
try {
|
|
9074
9252
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9075
|
-
const dir =
|
|
9253
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
9076
9254
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
9077
9255
|
const files = listHistoryFiles(dir, historySessionId);
|
|
9078
9256
|
const allMessages = [];
|
|
9079
9257
|
const seen = /* @__PURE__ */ new Set();
|
|
9080
9258
|
for (const file of files) {
|
|
9081
|
-
const filePath =
|
|
9259
|
+
const filePath = path11.join(dir, file);
|
|
9082
9260
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
9083
9261
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
9084
9262
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -9102,7 +9280,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
9102
9280
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
9103
9281
|
try {
|
|
9104
9282
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9105
|
-
const dir =
|
|
9283
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
9106
9284
|
if (!fs3.existsSync(dir)) {
|
|
9107
9285
|
savedHistorySessionCache.delete(sanitized);
|
|
9108
9286
|
return { sessions: [], hasMore: false };
|
|
@@ -9163,11 +9341,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
9163
9341
|
}
|
|
9164
9342
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
9165
9343
|
try {
|
|
9166
|
-
const dir =
|
|
9344
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
9167
9345
|
if (!fs3.existsSync(dir)) return null;
|
|
9168
9346
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
9169
9347
|
for (const file of files) {
|
|
9170
|
-
const lines = fs3.readFileSync(
|
|
9348
|
+
const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
9171
9349
|
for (const line of lines) {
|
|
9172
9350
|
try {
|
|
9173
9351
|
const parsed = JSON.parse(line);
|
|
@@ -9187,16 +9365,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
9187
9365
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
9188
9366
|
if (records.length === 0) return false;
|
|
9189
9367
|
try {
|
|
9190
|
-
const dir =
|
|
9368
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
9191
9369
|
fs3.mkdirSync(dir, { recursive: true });
|
|
9192
9370
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
9193
9371
|
for (const file of fs3.readdirSync(dir)) {
|
|
9194
9372
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
9195
|
-
fs3.unlinkSync(
|
|
9373
|
+
fs3.unlinkSync(path11.join(dir, file));
|
|
9196
9374
|
}
|
|
9197
9375
|
}
|
|
9198
9376
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
9199
|
-
const filePath =
|
|
9377
|
+
const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
9200
9378
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
9201
9379
|
`, "utf-8");
|
|
9202
9380
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -11191,6 +11369,14 @@ function getActiveChatOptions(profile) {
|
|
|
11191
11369
|
if (profile === "full") return {};
|
|
11192
11370
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
11193
11371
|
}
|
|
11372
|
+
function resolveSessionStatus(activeChat, providerStatus) {
|
|
11373
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
11374
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
11375
|
+
if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
|
|
11376
|
+
if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
|
|
11377
|
+
if (topLevelStatus !== "idle") return topLevelStatus;
|
|
11378
|
+
return chatStatus;
|
|
11379
|
+
}
|
|
11194
11380
|
function shouldIncludeSessionControls(profile) {
|
|
11195
11381
|
return profile !== "live";
|
|
11196
11382
|
}
|
|
@@ -11269,9 +11455,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11269
11455
|
providerName: state.name,
|
|
11270
11456
|
kind: "workspace",
|
|
11271
11457
|
transport: "cdp-page",
|
|
11272
|
-
status:
|
|
11273
|
-
activeModal: activeChat?.activeModal || null
|
|
11274
|
-
}),
|
|
11458
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11275
11459
|
title,
|
|
11276
11460
|
workspace,
|
|
11277
11461
|
...git && { git },
|
|
@@ -11306,9 +11490,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11306
11490
|
providerSessionId: ext.providerSessionId,
|
|
11307
11491
|
kind: "agent",
|
|
11308
11492
|
transport: "cdp-webview",
|
|
11309
|
-
status:
|
|
11310
|
-
activeModal: activeChat?.activeModal || null
|
|
11311
|
-
}),
|
|
11493
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
11312
11494
|
title: activeChat?.title || ext.name,
|
|
11313
11495
|
workspace,
|
|
11314
11496
|
...git && { git },
|
|
@@ -11358,9 +11540,7 @@ function buildCliSession(state, options) {
|
|
|
11358
11540
|
providerSessionId: state.providerSessionId,
|
|
11359
11541
|
kind: "agent",
|
|
11360
11542
|
transport: "pty",
|
|
11361
|
-
status:
|
|
11362
|
-
activeModal: activeChat?.activeModal || null
|
|
11363
|
-
}),
|
|
11543
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11364
11544
|
title: activeChat?.title || state.name,
|
|
11365
11545
|
workspace,
|
|
11366
11546
|
...git && { git },
|
|
@@ -11408,9 +11588,7 @@ function buildAcpSession(state, options) {
|
|
|
11408
11588
|
providerName: state.name,
|
|
11409
11589
|
kind: "agent",
|
|
11410
11590
|
transport: "acp",
|
|
11411
|
-
status:
|
|
11412
|
-
activeModal: activeChat?.activeModal || null
|
|
11413
|
-
}),
|
|
11591
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11414
11592
|
title: activeChat?.title || state.name,
|
|
11415
11593
|
workspace,
|
|
11416
11594
|
...git && { git },
|
|
@@ -11533,7 +11711,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
11533
11711
|
// src/commands/chat-commands.ts
|
|
11534
11712
|
var fs4 = __toESM(require("fs"));
|
|
11535
11713
|
var os6 = __toESM(require("os"));
|
|
11536
|
-
var
|
|
11714
|
+
var path12 = __toESM(require("path"));
|
|
11537
11715
|
var import_node_crypto = require("crypto");
|
|
11538
11716
|
|
|
11539
11717
|
// src/providers/provider-input-support.ts
|
|
@@ -11736,6 +11914,7 @@ function buildSessionModalDeliverySignature(payload) {
|
|
|
11736
11914
|
// src/commands/chat-commands.ts
|
|
11737
11915
|
var RECENT_SEND_WINDOW_MS = 1200;
|
|
11738
11916
|
var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
|
|
11917
|
+
var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
|
|
11739
11918
|
var recentSendByTarget = /* @__PURE__ */ new Map();
|
|
11740
11919
|
function getCurrentProviderType(h, fallback = "") {
|
|
11741
11920
|
return h.currentSession?.providerType || h.currentProviderType || fallback;
|
|
@@ -11788,6 +11967,16 @@ function buildSendInputSignature(input) {
|
|
|
11788
11967
|
function getSendChatInputEnvelope(args) {
|
|
11789
11968
|
return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
|
|
11790
11969
|
}
|
|
11970
|
+
function sleep(ms) {
|
|
11971
|
+
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
11972
|
+
}
|
|
11973
|
+
async function waitOnceForFreshHermesCliStart(adapter, log) {
|
|
11974
|
+
if (adapter.cliType !== "hermes-cli") return;
|
|
11975
|
+
const status = typeof adapter.getStatus === "function" ? adapter.getStatus()?.status : void 0;
|
|
11976
|
+
if (status !== "starting") return;
|
|
11977
|
+
log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
|
|
11978
|
+
await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
|
|
11979
|
+
}
|
|
11791
11980
|
function getHistorySessionId(h, args) {
|
|
11792
11981
|
const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
|
|
11793
11982
|
if (explicit) return explicit;
|
|
@@ -11896,6 +12085,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
11896
12085
|
return raw;
|
|
11897
12086
|
}
|
|
11898
12087
|
}
|
|
12088
|
+
function isGeneratingLikeStatus(status) {
|
|
12089
|
+
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
12090
|
+
}
|
|
12091
|
+
function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
12092
|
+
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
12093
|
+
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
12094
|
+
const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
|
|
12095
|
+
if (adapterRawStatus !== "idle") return false;
|
|
12096
|
+
if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
|
|
12097
|
+
return true;
|
|
12098
|
+
}
|
|
12099
|
+
function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
12100
|
+
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
12101
|
+
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
12102
|
+
}
|
|
12103
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
12104
|
+
if (status !== "idle") return messages;
|
|
12105
|
+
return messages.map((message) => {
|
|
12106
|
+
const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
12107
|
+
const hasStreamingMeta = meta?.streaming === true;
|
|
12108
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
12109
|
+
return {
|
|
12110
|
+
...message,
|
|
12111
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
12112
|
+
...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
|
|
12113
|
+
};
|
|
12114
|
+
});
|
|
12115
|
+
}
|
|
11899
12116
|
function buildReadChatCommandResult(payload, args) {
|
|
11900
12117
|
let validatedPayload;
|
|
11901
12118
|
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
@@ -12044,7 +12261,7 @@ function buildDebugBundleText(bundle) {
|
|
|
12044
12261
|
}
|
|
12045
12262
|
function getChatDebugBundleDir() {
|
|
12046
12263
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
12047
|
-
return override ||
|
|
12264
|
+
return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
12048
12265
|
}
|
|
12049
12266
|
function safeBundleIdSegment(value, fallback) {
|
|
12050
12267
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -12060,6 +12277,14 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
12060
12277
|
const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
|
|
12061
12278
|
const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
|
|
12062
12279
|
const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
|
|
12280
|
+
const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
|
|
12281
|
+
const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
|
|
12282
|
+
const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
|
|
12283
|
+
const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
|
|
12284
|
+
const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
|
|
12285
|
+
const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
|
|
12286
|
+
const cliStatus = typeof cli?.status === "string" ? cli.status : "";
|
|
12287
|
+
const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
|
|
12063
12288
|
return {
|
|
12064
12289
|
createdAt: bundle.createdAt,
|
|
12065
12290
|
targetSessionId: target.targetSessionId,
|
|
@@ -12068,8 +12293,22 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
12068
12293
|
readChatSuccess: readChat.success,
|
|
12069
12294
|
readChatStatus: readChat.status,
|
|
12070
12295
|
readChatTotalMessages: readChat.totalMessages,
|
|
12296
|
+
readChatReturnedMessages,
|
|
12071
12297
|
cliStatus: cli?.status,
|
|
12298
|
+
cliParsedStatus: cliParsedStatus || void 0,
|
|
12072
12299
|
cliMessageCount: cli?.messageCount,
|
|
12300
|
+
cliParsedMessageCount,
|
|
12301
|
+
cliPartialResponseChars: cliPartialResponse.length,
|
|
12302
|
+
parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
|
|
12303
|
+
parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
|
|
12304
|
+
readChatDebug: Object.keys(debugReadChat).length ? {
|
|
12305
|
+
adapterStatus: debugReadChat.adapterStatus,
|
|
12306
|
+
parsedStatus: debugReadChat.parsedStatus,
|
|
12307
|
+
returnedStatus: debugReadChat.returnedStatus,
|
|
12308
|
+
parsedMsgCount: debugReadChat.parsedMsgCount,
|
|
12309
|
+
returnedMsgCount: debugReadChat.returnedMsgCount,
|
|
12310
|
+
shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
|
|
12311
|
+
} : void 0,
|
|
12073
12312
|
hasFrontendSnapshot: !!frontend
|
|
12074
12313
|
};
|
|
12075
12314
|
}
|
|
@@ -12077,7 +12316,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
12077
12316
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
12078
12317
|
const dir = getChatDebugBundleDir();
|
|
12079
12318
|
fs4.mkdirSync(dir, { recursive: true });
|
|
12080
|
-
const savedPath =
|
|
12319
|
+
const savedPath = path12.join(dir, `${bundleId}.json`);
|
|
12081
12320
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
12082
12321
|
`;
|
|
12083
12322
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -12307,7 +12546,7 @@ async function handleChatHistory(h, args) {
|
|
|
12307
12546
|
}
|
|
12308
12547
|
}
|
|
12309
12548
|
async function handleReadChat(h, args) {
|
|
12310
|
-
const provider = h.getProvider(args?.agentType);
|
|
12549
|
+
const provider = h.getProvider(args?.agentType || args?.providerType);
|
|
12311
12550
|
const transport = getTargetTransport(h, provider);
|
|
12312
12551
|
const historySessionId = getHistorySessionId(h, args);
|
|
12313
12552
|
const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
|
|
@@ -12334,10 +12573,13 @@ async function handleReadChat(h, args) {
|
|
|
12334
12573
|
const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
12335
12574
|
const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
12336
12575
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
12337
|
-
const returnedStatus = parsedRecord.status
|
|
12338
|
-
|
|
12576
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
12577
|
+
const runtimeMessageMerger = getTargetInstance(h, args);
|
|
12578
|
+
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
|
|
12579
|
+
const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
|
|
12580
|
+
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}`);
|
|
12339
12581
|
return buildReadChatCommandResult({
|
|
12340
|
-
messages:
|
|
12582
|
+
messages: returnedMessages,
|
|
12341
12583
|
status: returnedStatus,
|
|
12342
12584
|
activeModal,
|
|
12343
12585
|
debugReadChat: {
|
|
@@ -12348,7 +12590,7 @@ async function handleReadChat(h, args) {
|
|
|
12348
12590
|
returnedStatus: String(returnedStatus || ""),
|
|
12349
12591
|
shouldPreferAdapterMessages: false,
|
|
12350
12592
|
parsedMsgCount: parsedRecord.messages.length,
|
|
12351
|
-
returnedMsgCount:
|
|
12593
|
+
returnedMsgCount: returnedMessages.length
|
|
12352
12594
|
},
|
|
12353
12595
|
...title ? { title } : {},
|
|
12354
12596
|
...providerSessionId ? { providerSessionId } : {},
|
|
@@ -12594,6 +12836,7 @@ async function handleSendChat(h, args) {
|
|
|
12594
12836
|
try {
|
|
12595
12837
|
assertTextOnlyInput(provider, input);
|
|
12596
12838
|
if (!text) return { success: false, error: "text required for PTY send" };
|
|
12839
|
+
await waitOnceForFreshHermesCliStart(adapter, _log);
|
|
12597
12840
|
await adapter.sendMessage(text);
|
|
12598
12841
|
return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
|
|
12599
12842
|
} catch (e) {
|
|
@@ -13093,9 +13336,17 @@ async function handleResolveAction(h, args) {
|
|
|
13093
13336
|
const targetState = targetInstance?.getState?.();
|
|
13094
13337
|
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;
|
|
13095
13338
|
const statusModal = status?.activeModal && Array.isArray(status.activeModal.buttons) && status.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? status.activeModal : null;
|
|
13096
|
-
const
|
|
13097
|
-
|
|
13098
|
-
|
|
13339
|
+
const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
|
|
13340
|
+
try {
|
|
13341
|
+
return parseMaybeJson(adapter.getScriptParsedStatus());
|
|
13342
|
+
} catch {
|
|
13343
|
+
return null;
|
|
13344
|
+
}
|
|
13345
|
+
})() : null;
|
|
13346
|
+
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;
|
|
13347
|
+
const effectiveModal = statusModal || surfacedModal || parsedModal;
|
|
13348
|
+
const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
|
|
13349
|
+
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"}`);
|
|
13099
13350
|
if (!effectiveModal) {
|
|
13100
13351
|
return { success: false, error: "Not in approval state" };
|
|
13101
13352
|
}
|
|
@@ -13221,7 +13472,7 @@ async function handleResolveAction(h, args) {
|
|
|
13221
13472
|
|
|
13222
13473
|
// src/commands/cdp-commands.ts
|
|
13223
13474
|
var fs5 = __toESM(require("fs"));
|
|
13224
|
-
var
|
|
13475
|
+
var path13 = __toESM(require("path"));
|
|
13225
13476
|
var os7 = __toESM(require("os"));
|
|
13226
13477
|
var KEY_TO_VK = {
|
|
13227
13478
|
Backspace: 8,
|
|
@@ -13478,25 +13729,25 @@ function resolveSafePath(requestedPath) {
|
|
|
13478
13729
|
const inputPath = rawPath || ".";
|
|
13479
13730
|
const home = os7.homedir();
|
|
13480
13731
|
if (inputPath.startsWith("~")) {
|
|
13481
|
-
return
|
|
13732
|
+
return path13.resolve(path13.join(home, inputPath.slice(1)));
|
|
13482
13733
|
}
|
|
13483
13734
|
if (process.platform === "win32") {
|
|
13484
13735
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
13485
|
-
if (
|
|
13486
|
-
return
|
|
13736
|
+
if (path13.win32.isAbsolute(normalized)) {
|
|
13737
|
+
return path13.win32.normalize(normalized);
|
|
13487
13738
|
}
|
|
13488
|
-
return
|
|
13739
|
+
return path13.win32.resolve(normalized);
|
|
13489
13740
|
}
|
|
13490
|
-
if (
|
|
13491
|
-
return
|
|
13741
|
+
if (path13.isAbsolute(inputPath)) {
|
|
13742
|
+
return path13.normalize(inputPath);
|
|
13492
13743
|
}
|
|
13493
|
-
return
|
|
13744
|
+
return path13.resolve(inputPath);
|
|
13494
13745
|
}
|
|
13495
13746
|
function listDirectoryEntriesSafe(dirPath) {
|
|
13496
13747
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
13497
13748
|
const files = [];
|
|
13498
13749
|
for (const entry of entries) {
|
|
13499
|
-
const entryPath =
|
|
13750
|
+
const entryPath = path13.join(dirPath, entry.name);
|
|
13500
13751
|
try {
|
|
13501
13752
|
if (entry.isDirectory()) {
|
|
13502
13753
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -13550,7 +13801,7 @@ async function handleFileRead(h, args) {
|
|
|
13550
13801
|
async function handleFileWrite(h, args) {
|
|
13551
13802
|
try {
|
|
13552
13803
|
const filePath = resolveSafePath(args?.path);
|
|
13553
|
-
fs5.mkdirSync(
|
|
13804
|
+
fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
13554
13805
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
13555
13806
|
return { success: true, path: filePath };
|
|
13556
13807
|
} catch (e) {
|
|
@@ -14334,9 +14585,11 @@ var DaemonCommandHandler = class {
|
|
|
14334
14585
|
}
|
|
14335
14586
|
const sessionLookupFailed = !!targetSessionId && !session;
|
|
14336
14587
|
const managerKey = this.extractIdeType(args, sessionLookupFailed);
|
|
14337
|
-
let providerType;
|
|
14588
|
+
let providerType = args?.agentType || args?.providerType;
|
|
14338
14589
|
if (!sessionLookupFailed) {
|
|
14339
|
-
providerType = session?.providerType ||
|
|
14590
|
+
providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
|
|
14591
|
+
} else if (!providerType) {
|
|
14592
|
+
providerType = this.inferProviderType(managerKey);
|
|
14340
14593
|
}
|
|
14341
14594
|
return { session, managerKey, providerType, sessionLookupFailed };
|
|
14342
14595
|
}
|
|
@@ -14416,7 +14669,8 @@ var DaemonCommandHandler = class {
|
|
|
14416
14669
|
"pty_resize",
|
|
14417
14670
|
"invoke_provider_script"
|
|
14418
14671
|
]);
|
|
14419
|
-
|
|
14672
|
+
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);
|
|
14673
|
+
if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
|
|
14420
14674
|
const result2 = {
|
|
14421
14675
|
success: false,
|
|
14422
14676
|
error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
|
|
@@ -14669,7 +14923,7 @@ var DaemonCommandHandler = class {
|
|
|
14669
14923
|
|
|
14670
14924
|
// src/commands/cli-manager.ts
|
|
14671
14925
|
var os13 = __toESM(require("os"));
|
|
14672
|
-
var
|
|
14926
|
+
var path17 = __toESM(require("path"));
|
|
14673
14927
|
var crypto4 = __toESM(require("crypto"));
|
|
14674
14928
|
var import_fs6 = require("fs");
|
|
14675
14929
|
var import_child_process6 = require("child_process");
|
|
@@ -14679,7 +14933,7 @@ init_config();
|
|
|
14679
14933
|
|
|
14680
14934
|
// src/providers/cli-provider-instance.ts
|
|
14681
14935
|
var os12 = __toESM(require("os"));
|
|
14682
|
-
var
|
|
14936
|
+
var path16 = __toESM(require("path"));
|
|
14683
14937
|
var crypto3 = __toESM(require("crypto"));
|
|
14684
14938
|
var fs6 = __toESM(require("fs"));
|
|
14685
14939
|
var import_node_module = require("module");
|
|
@@ -14738,7 +14992,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
14738
14992
|
var CachedDatabaseSync = null;
|
|
14739
14993
|
function getDatabaseSync() {
|
|
14740
14994
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
14741
|
-
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(
|
|
14995
|
+
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
14742
14996
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
14743
14997
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
14744
14998
|
if (!CachedDatabaseSync) {
|
|
@@ -14791,7 +15045,7 @@ var CliProviderInstance = class {
|
|
|
14791
15045
|
this.providerSessionId = options?.providerSessionId;
|
|
14792
15046
|
this.launchMode = options?.launchMode || "new";
|
|
14793
15047
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
14794
|
-
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
|
|
15048
|
+
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
14795
15049
|
this.monitor = new StatusMonitor();
|
|
14796
15050
|
this.historyWriter = new ChatHistoryWriter();
|
|
14797
15051
|
}
|
|
@@ -15268,7 +15522,19 @@ var CliProviderInstance = class {
|
|
|
15268
15522
|
}
|
|
15269
15523
|
}
|
|
15270
15524
|
pushEvent(event) {
|
|
15271
|
-
|
|
15525
|
+
const enrichedEvent = {
|
|
15526
|
+
...event,
|
|
15527
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
|
|
15528
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
|
|
15529
|
+
providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
|
|
15530
|
+
workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
|
|
15531
|
+
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
15532
|
+
};
|
|
15533
|
+
if (this.context?.emitProviderEvent) {
|
|
15534
|
+
this.context.emitProviderEvent(enrichedEvent);
|
|
15535
|
+
return;
|
|
15536
|
+
}
|
|
15537
|
+
this.events.push(enrichedEvent);
|
|
15272
15538
|
}
|
|
15273
15539
|
flushEvents() {
|
|
15274
15540
|
const events = [...this.events];
|
|
@@ -15475,12 +15741,29 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15475
15741
|
);
|
|
15476
15742
|
}
|
|
15477
15743
|
}
|
|
15744
|
+
mergeRuntimeChatMessages(parsedMessages) {
|
|
15745
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
15746
|
+
}
|
|
15478
15747
|
mergeConversationMessages(parsedMessages) {
|
|
15479
15748
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15483
|
-
|
|
15749
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
15750
|
+
message,
|
|
15751
|
+
index,
|
|
15752
|
+
source: "parsed"
|
|
15753
|
+
}));
|
|
15754
|
+
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
15755
|
+
message: entry.message,
|
|
15756
|
+
index: parsedMessages.length + index,
|
|
15757
|
+
source: "runtime"
|
|
15758
|
+
}));
|
|
15759
|
+
const getTime = (message) => {
|
|
15760
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
15761
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
15762
|
+
};
|
|
15763
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
15764
|
+
const aTime = getTime(a.message);
|
|
15765
|
+
const bTime = getTime(b.message);
|
|
15766
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
15484
15767
|
return a.index - b.index;
|
|
15485
15768
|
}).map((entry) => entry.message));
|
|
15486
15769
|
}
|
|
@@ -16804,11 +17087,11 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
16804
17087
|
// src/commands/cli-manager.ts
|
|
16805
17088
|
function isExplicitCommand(command) {
|
|
16806
17089
|
const trimmed = command.trim();
|
|
16807
|
-
return
|
|
17090
|
+
return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
16808
17091
|
}
|
|
16809
17092
|
function expandExecutable(command) {
|
|
16810
17093
|
const trimmed = command.trim();
|
|
16811
|
-
return trimmed.startsWith("~") ?
|
|
17094
|
+
return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
16812
17095
|
}
|
|
16813
17096
|
function commandExists(command) {
|
|
16814
17097
|
const trimmed = command.trim();
|
|
@@ -16832,6 +17115,35 @@ function colorize(color, text) {
|
|
|
16832
17115
|
const fn = chalkApi?.[color];
|
|
16833
17116
|
return typeof fn === "function" ? fn(text) : text;
|
|
16834
17117
|
}
|
|
17118
|
+
var COORDINATOR_DELEGATED_ENV_UNSETS = {
|
|
17119
|
+
ADHDEV_INLINE_MESH: "",
|
|
17120
|
+
ADHDEV_MCP_TRANSPORT: "",
|
|
17121
|
+
ADHDEV_MESH_ID: "",
|
|
17122
|
+
HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
|
|
17123
|
+
};
|
|
17124
|
+
function hasCliArg(args, flag) {
|
|
17125
|
+
return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
17126
|
+
}
|
|
17127
|
+
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
17128
|
+
const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
17129
|
+
(0, import_fs6.mkdirSync)(baseDir, { recursive: true });
|
|
17130
|
+
const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
17131
|
+
const filePath = path17.join(baseDir, `${workspaceHash}.json`);
|
|
17132
|
+
(0, import_fs6.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
17133
|
+
return filePath;
|
|
17134
|
+
}
|
|
17135
|
+
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
17136
|
+
const cliType = String(input.cliType || "").trim();
|
|
17137
|
+
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
17138
|
+
const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
|
|
17139
|
+
if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
|
|
17140
|
+
cliArgs.unshift("--ignore-user-config");
|
|
17141
|
+
}
|
|
17142
|
+
if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
|
|
17143
|
+
cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
17144
|
+
}
|
|
17145
|
+
return { cliArgs, env };
|
|
17146
|
+
}
|
|
16835
17147
|
function isUuid(value) {
|
|
16836
17148
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
16837
17149
|
}
|
|
@@ -17002,7 +17314,7 @@ var DaemonCliManager = class {
|
|
|
17002
17314
|
attachExisting
|
|
17003
17315
|
}) || void 0;
|
|
17004
17316
|
}
|
|
17005
|
-
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
|
|
17317
|
+
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
|
|
17006
17318
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
17007
17319
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
17008
17320
|
if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
|
|
@@ -17016,7 +17328,7 @@ var DaemonCliManager = class {
|
|
|
17016
17328
|
providerSessionId,
|
|
17017
17329
|
attachExisting
|
|
17018
17330
|
);
|
|
17019
|
-
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
|
|
17331
|
+
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
17020
17332
|
}
|
|
17021
17333
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
17022
17334
|
}
|
|
@@ -17089,7 +17401,7 @@ var DaemonCliManager = class {
|
|
|
17089
17401
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
17090
17402
|
const trimmed = (workingDir || "").trim();
|
|
17091
17403
|
if (!trimmed) throw new Error("working directory required");
|
|
17092
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17404
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
|
|
17093
17405
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
17094
17406
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
17095
17407
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -17219,6 +17531,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17219
17531
|
{
|
|
17220
17532
|
providerSessionId: sessionBinding.providerSessionId,
|
|
17221
17533
|
launchMode: sessionBinding.launchMode,
|
|
17534
|
+
extraEnv: options?.extraEnv,
|
|
17222
17535
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
17223
17536
|
this.persistRecentActivity({
|
|
17224
17537
|
kind: "cli",
|
|
@@ -17239,7 +17552,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17239
17552
|
resolvedCliArgs,
|
|
17240
17553
|
key,
|
|
17241
17554
|
sessionBinding.providerSessionId,
|
|
17242
|
-
false
|
|
17555
|
+
false,
|
|
17556
|
+
options?.extraEnv
|
|
17243
17557
|
);
|
|
17244
17558
|
try {
|
|
17245
17559
|
await adapter.spawn();
|
|
@@ -17463,12 +17777,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17463
17777
|
const dir = resolved.path;
|
|
17464
17778
|
const launchSource = resolved.source;
|
|
17465
17779
|
if (!cliType) throw new Error("cliType required");
|
|
17780
|
+
const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
|
|
17781
|
+
const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
|
|
17782
|
+
cliType,
|
|
17783
|
+
workspace: dir,
|
|
17784
|
+
cliArgs: args?.cliArgs,
|
|
17785
|
+
env: args?.env
|
|
17786
|
+
}) : null;
|
|
17466
17787
|
const started = await this.startSession(
|
|
17467
17788
|
cliType,
|
|
17468
17789
|
dir,
|
|
17469
|
-
args?.cliArgs,
|
|
17790
|
+
delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
|
|
17470
17791
|
args?.initialModel,
|
|
17471
|
-
{
|
|
17792
|
+
{
|
|
17793
|
+
resumeSessionId: args?.resumeSessionId,
|
|
17794
|
+
settingsOverride,
|
|
17795
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
17796
|
+
}
|
|
17472
17797
|
);
|
|
17473
17798
|
return {
|
|
17474
17799
|
success: true,
|
|
@@ -17590,11 +17915,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17590
17915
|
var import_child_process7 = require("child_process");
|
|
17591
17916
|
var net = __toESM(require("net"));
|
|
17592
17917
|
var os15 = __toESM(require("os"));
|
|
17593
|
-
var
|
|
17918
|
+
var path19 = __toESM(require("path"));
|
|
17594
17919
|
|
|
17595
17920
|
// src/providers/provider-loader.ts
|
|
17596
17921
|
var fs7 = __toESM(require("fs"));
|
|
17597
|
-
var
|
|
17922
|
+
var path18 = __toESM(require("path"));
|
|
17598
17923
|
var os14 = __toESM(require("os"));
|
|
17599
17924
|
var chokidar = __toESM(require("chokidar"));
|
|
17600
17925
|
init_logger();
|
|
@@ -17918,7 +18243,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17918
18243
|
try {
|
|
17919
18244
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
17920
18245
|
return ["ide", "extension", "cli", "acp"].some(
|
|
17921
|
-
(category) => fs7.existsSync(
|
|
18246
|
+
(category) => fs7.existsSync(path18.join(candidate, category))
|
|
17922
18247
|
);
|
|
17923
18248
|
} catch {
|
|
17924
18249
|
return false;
|
|
@@ -17926,20 +18251,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17926
18251
|
}
|
|
17927
18252
|
static hasProviderRootMarker(candidate) {
|
|
17928
18253
|
try {
|
|
17929
|
-
return fs7.existsSync(
|
|
18254
|
+
return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
17930
18255
|
} catch {
|
|
17931
18256
|
return false;
|
|
17932
18257
|
}
|
|
17933
18258
|
}
|
|
17934
18259
|
detectDefaultUserDir() {
|
|
17935
|
-
const fallback =
|
|
18260
|
+
const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17936
18261
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17937
18262
|
const visited = /* @__PURE__ */ new Set();
|
|
17938
18263
|
for (const start of this.probeStarts) {
|
|
17939
|
-
let current =
|
|
18264
|
+
let current = path18.resolve(start);
|
|
17940
18265
|
while (!visited.has(current)) {
|
|
17941
18266
|
visited.add(current);
|
|
17942
|
-
const siblingCandidate =
|
|
18267
|
+
const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17943
18268
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17944
18269
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17945
18270
|
if (envOptIn || hasMarker) {
|
|
@@ -17961,7 +18286,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17961
18286
|
return { path: siblingCandidate, source };
|
|
17962
18287
|
}
|
|
17963
18288
|
}
|
|
17964
|
-
const parent =
|
|
18289
|
+
const parent = path18.dirname(current);
|
|
17965
18290
|
if (parent === current) break;
|
|
17966
18291
|
current = parent;
|
|
17967
18292
|
}
|
|
@@ -17971,11 +18296,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17971
18296
|
constructor(options) {
|
|
17972
18297
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17973
18298
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17974
|
-
this.defaultProvidersDir =
|
|
18299
|
+
this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17975
18300
|
const detected = this.detectDefaultUserDir();
|
|
17976
18301
|
this.userDir = detected.path;
|
|
17977
18302
|
this.userDirSource = detected.source;
|
|
17978
|
-
this.upstreamDir =
|
|
18303
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17979
18304
|
this.disableUpstream = false;
|
|
17980
18305
|
this.applySourceConfig({
|
|
17981
18306
|
userDir: options?.userDir,
|
|
@@ -18034,7 +18359,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18034
18359
|
this.userDir = detected.path;
|
|
18035
18360
|
this.userDirSource = detected.source;
|
|
18036
18361
|
}
|
|
18037
|
-
this.upstreamDir =
|
|
18362
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
18038
18363
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
18039
18364
|
if (this.explicitProviderDir) {
|
|
18040
18365
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -18048,7 +18373,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18048
18373
|
* Canonical provider directory shape for a given root.
|
|
18049
18374
|
*/
|
|
18050
18375
|
getProviderDir(root, category, type) {
|
|
18051
|
-
return
|
|
18376
|
+
return path18.join(root, category, type);
|
|
18052
18377
|
}
|
|
18053
18378
|
/**
|
|
18054
18379
|
* Canonical user override directory for a provider.
|
|
@@ -18075,7 +18400,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18075
18400
|
resolveProviderFile(type, ...segments) {
|
|
18076
18401
|
const dir = this.findProviderDirInternal(type);
|
|
18077
18402
|
if (!dir) return null;
|
|
18078
|
-
return
|
|
18403
|
+
return path18.join(dir, ...segments);
|
|
18079
18404
|
}
|
|
18080
18405
|
/**
|
|
18081
18406
|
* Load all providers (3-tier priority)
|
|
@@ -18114,7 +18439,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18114
18439
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
18115
18440
|
try {
|
|
18116
18441
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
18117
|
-
(d) => fs7.statSync(
|
|
18442
|
+
(d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
|
|
18118
18443
|
);
|
|
18119
18444
|
} catch {
|
|
18120
18445
|
return false;
|
|
@@ -18611,8 +18936,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18611
18936
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
18612
18937
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
18613
18938
|
if (providerDir) {
|
|
18614
|
-
const fullDir =
|
|
18615
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18939
|
+
const fullDir = path18.join(providerDir, entry.scriptDir);
|
|
18940
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18616
18941
|
}
|
|
18617
18942
|
matched = true;
|
|
18618
18943
|
}
|
|
@@ -18627,8 +18952,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18627
18952
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18628
18953
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
18629
18954
|
if (providerDir) {
|
|
18630
|
-
const fullDir =
|
|
18631
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18955
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18956
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18632
18957
|
}
|
|
18633
18958
|
}
|
|
18634
18959
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -18645,8 +18970,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18645
18970
|
resolved._resolvedScriptDir = dirOverride;
|
|
18646
18971
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
18647
18972
|
if (providerDir) {
|
|
18648
|
-
const fullDir =
|
|
18649
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18973
|
+
const fullDir = path18.join(providerDir, dirOverride);
|
|
18974
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18650
18975
|
}
|
|
18651
18976
|
}
|
|
18652
18977
|
} else if (override.scripts) {
|
|
@@ -18662,8 +18987,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18662
18987
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18663
18988
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
18664
18989
|
if (providerDir) {
|
|
18665
|
-
const fullDir =
|
|
18666
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18990
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18991
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18667
18992
|
}
|
|
18668
18993
|
}
|
|
18669
18994
|
}
|
|
@@ -18695,14 +19020,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18695
19020
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
18696
19021
|
return null;
|
|
18697
19022
|
}
|
|
18698
|
-
const dir =
|
|
19023
|
+
const dir = path18.join(providerDir, scriptDir);
|
|
18699
19024
|
if (!fs7.existsSync(dir)) {
|
|
18700
19025
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
18701
19026
|
return null;
|
|
18702
19027
|
}
|
|
18703
19028
|
const cached = this.scriptsCache.get(dir);
|
|
18704
19029
|
if (cached) return cached;
|
|
18705
|
-
const scriptsJs =
|
|
19030
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
18706
19031
|
if (fs7.existsSync(scriptsJs)) {
|
|
18707
19032
|
try {
|
|
18708
19033
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -18744,7 +19069,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18744
19069
|
return;
|
|
18745
19070
|
}
|
|
18746
19071
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
18747
|
-
this.log(`File changed: ${
|
|
19072
|
+
this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
|
|
18748
19073
|
this.reload();
|
|
18749
19074
|
}
|
|
18750
19075
|
};
|
|
@@ -18799,7 +19124,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18799
19124
|
}
|
|
18800
19125
|
const https = require("https");
|
|
18801
19126
|
const { execSync: execSync7 } = require("child_process");
|
|
18802
|
-
const metaPath =
|
|
19127
|
+
const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
18803
19128
|
let prevEtag = "";
|
|
18804
19129
|
let prevTimestamp = 0;
|
|
18805
19130
|
try {
|
|
@@ -18859,17 +19184,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18859
19184
|
return { updated: false };
|
|
18860
19185
|
}
|
|
18861
19186
|
this.log("Downloading latest providers from GitHub...");
|
|
18862
|
-
const tmpTar =
|
|
18863
|
-
const tmpExtract =
|
|
19187
|
+
const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
19188
|
+
const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
18864
19189
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
18865
19190
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
18866
19191
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
18867
19192
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
18868
19193
|
const rootDir = extracted.find(
|
|
18869
|
-
(d) => fs7.statSync(
|
|
19194
|
+
(d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
18870
19195
|
);
|
|
18871
19196
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
18872
|
-
const sourceDir =
|
|
19197
|
+
const sourceDir = path18.join(tmpExtract, rootDir);
|
|
18873
19198
|
const backupDir = this.upstreamDir + ".bak";
|
|
18874
19199
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
18875
19200
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -18944,8 +19269,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18944
19269
|
copyDirRecursive(src, dest) {
|
|
18945
19270
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18946
19271
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18947
|
-
const srcPath =
|
|
18948
|
-
const destPath =
|
|
19272
|
+
const srcPath = path18.join(src, entry.name);
|
|
19273
|
+
const destPath = path18.join(dest, entry.name);
|
|
18949
19274
|
if (entry.isDirectory()) {
|
|
18950
19275
|
this.copyDirRecursive(srcPath, destPath);
|
|
18951
19276
|
} else {
|
|
@@ -18956,7 +19281,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18956
19281
|
/** .meta.json save */
|
|
18957
19282
|
writeMeta(metaPath, etag, timestamp) {
|
|
18958
19283
|
try {
|
|
18959
|
-
fs7.mkdirSync(
|
|
19284
|
+
fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
|
|
18960
19285
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18961
19286
|
etag,
|
|
18962
19287
|
timestamp,
|
|
@@ -18973,7 +19298,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18973
19298
|
const scan = (d) => {
|
|
18974
19299
|
try {
|
|
18975
19300
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18976
|
-
if (entry.isDirectory()) scan(
|
|
19301
|
+
if (entry.isDirectory()) scan(path18.join(d, entry.name));
|
|
18977
19302
|
else if (entry.name === "provider.json") count++;
|
|
18978
19303
|
}
|
|
18979
19304
|
} catch {
|
|
@@ -19201,17 +19526,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19201
19526
|
for (const root of searchRoots) {
|
|
19202
19527
|
if (!fs7.existsSync(root)) continue;
|
|
19203
19528
|
const candidate = this.getProviderDir(root, cat, type);
|
|
19204
|
-
if (fs7.existsSync(
|
|
19205
|
-
const catDir =
|
|
19529
|
+
if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
|
|
19530
|
+
const catDir = path18.join(root, cat);
|
|
19206
19531
|
if (fs7.existsSync(catDir)) {
|
|
19207
19532
|
try {
|
|
19208
19533
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
19209
19534
|
if (!entry.isDirectory()) continue;
|
|
19210
|
-
const jsonPath =
|
|
19535
|
+
const jsonPath = path18.join(catDir, entry.name, "provider.json");
|
|
19211
19536
|
if (fs7.existsSync(jsonPath)) {
|
|
19212
19537
|
try {
|
|
19213
19538
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
19214
|
-
if (data.type === type) return
|
|
19539
|
+
if (data.type === type) return path18.join(catDir, entry.name);
|
|
19215
19540
|
} catch {
|
|
19216
19541
|
}
|
|
19217
19542
|
}
|
|
@@ -19228,7 +19553,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19228
19553
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
19229
19554
|
*/
|
|
19230
19555
|
buildScriptWrappersFromDir(dir) {
|
|
19231
|
-
const scriptsJs =
|
|
19556
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
19232
19557
|
if (fs7.existsSync(scriptsJs)) {
|
|
19233
19558
|
try {
|
|
19234
19559
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -19242,7 +19567,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19242
19567
|
for (const file of fs7.readdirSync(dir)) {
|
|
19243
19568
|
if (!file.endsWith(".js")) continue;
|
|
19244
19569
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
19245
|
-
const filePath =
|
|
19570
|
+
const filePath = path18.join(dir, file);
|
|
19246
19571
|
result[scriptName] = (...args) => {
|
|
19247
19572
|
try {
|
|
19248
19573
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -19302,7 +19627,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19302
19627
|
}
|
|
19303
19628
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
19304
19629
|
if (hasJson) {
|
|
19305
|
-
const jsonPath =
|
|
19630
|
+
const jsonPath = path18.join(d, "provider.json");
|
|
19306
19631
|
try {
|
|
19307
19632
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
19308
19633
|
const mod = JSON.parse(raw);
|
|
@@ -19323,7 +19648,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19323
19648
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
19324
19649
|
} else {
|
|
19325
19650
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
19326
|
-
const scriptsPath =
|
|
19651
|
+
const scriptsPath = path18.join(d, "scripts.js");
|
|
19327
19652
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
19328
19653
|
try {
|
|
19329
19654
|
delete require.cache[require.resolve(scriptsPath)];
|
|
@@ -19349,7 +19674,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19349
19674
|
if (!entry.isDirectory()) continue;
|
|
19350
19675
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
19351
19676
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
19352
|
-
scan(
|
|
19677
|
+
scan(path18.join(d, entry.name));
|
|
19353
19678
|
}
|
|
19354
19679
|
}
|
|
19355
19680
|
};
|
|
@@ -19674,8 +19999,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
19674
19999
|
const appNameMap = getMacAppIdentifiers();
|
|
19675
20000
|
const appName = appNameMap[ideId];
|
|
19676
20001
|
if (appName) {
|
|
19677
|
-
const storagePath =
|
|
19678
|
-
process.env.APPDATA ||
|
|
20002
|
+
const storagePath = path19.join(
|
|
20003
|
+
process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
|
|
19679
20004
|
appName,
|
|
19680
20005
|
"storage.json"
|
|
19681
20006
|
);
|
|
@@ -19864,9 +20189,9 @@ init_logger();
|
|
|
19864
20189
|
|
|
19865
20190
|
// src/logging/command-log.ts
|
|
19866
20191
|
var fs8 = __toESM(require("fs"));
|
|
19867
|
-
var
|
|
20192
|
+
var path20 = __toESM(require("path"));
|
|
19868
20193
|
var os16 = __toESM(require("os"));
|
|
19869
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
20194
|
+
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");
|
|
19870
20195
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
19871
20196
|
var MAX_DAYS = 7;
|
|
19872
20197
|
try {
|
|
@@ -19904,13 +20229,13 @@ function getDateStr2() {
|
|
|
19904
20229
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19905
20230
|
}
|
|
19906
20231
|
var currentDate2 = getDateStr2();
|
|
19907
|
-
var currentFile =
|
|
20232
|
+
var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19908
20233
|
var writeCount2 = 0;
|
|
19909
20234
|
function checkRotation() {
|
|
19910
20235
|
const today = getDateStr2();
|
|
19911
20236
|
if (today !== currentDate2) {
|
|
19912
20237
|
currentDate2 = today;
|
|
19913
|
-
currentFile =
|
|
20238
|
+
currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19914
20239
|
cleanOldFiles();
|
|
19915
20240
|
}
|
|
19916
20241
|
}
|
|
@@ -19924,7 +20249,7 @@ function cleanOldFiles() {
|
|
|
19924
20249
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
19925
20250
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
19926
20251
|
try {
|
|
19927
|
-
fs8.unlinkSync(
|
|
20252
|
+
fs8.unlinkSync(path20.join(LOG_DIR2, file));
|
|
19928
20253
|
} catch {
|
|
19929
20254
|
}
|
|
19930
20255
|
}
|
|
@@ -20007,14 +20332,66 @@ function getRecentCommands(count = 50) {
|
|
|
20007
20332
|
cleanOldFiles();
|
|
20008
20333
|
|
|
20009
20334
|
// src/commands/router.ts
|
|
20335
|
+
var yaml = __toESM(require("js-yaml"));
|
|
20010
20336
|
init_logger();
|
|
20011
20337
|
|
|
20012
20338
|
// src/commands/mesh-coordinator.ts
|
|
20013
|
-
var
|
|
20339
|
+
var import_node_child_process3 = require("child_process");
|
|
20340
|
+
var import_node_fs3 = require("fs");
|
|
20014
20341
|
var import_node_module2 = require("module");
|
|
20342
|
+
var os17 = __toESM(require("os"));
|
|
20015
20343
|
var import_node_path = require("path");
|
|
20016
20344
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
20017
20345
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20346
|
+
var HERMES_CLI_TYPE = "hermes-cli";
|
|
20347
|
+
var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
|
|
20348
|
+
function isHermesProvider(provider, cliType) {
|
|
20349
|
+
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
20350
|
+
return type === HERMES_CLI_TYPE;
|
|
20351
|
+
}
|
|
20352
|
+
function resolveHermesMeshCoordinatorSetup(options) {
|
|
20353
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
20354
|
+
meshId: options.meshId,
|
|
20355
|
+
nodeExecutable: options.nodeExecutable,
|
|
20356
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath
|
|
20357
|
+
});
|
|
20358
|
+
if (!mcpServer) {
|
|
20359
|
+
return {
|
|
20360
|
+
kind: "unsupported",
|
|
20361
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20362
|
+
};
|
|
20363
|
+
}
|
|
20364
|
+
const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
|
|
20365
|
+
if (!configPath.trim()) {
|
|
20366
|
+
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20367
|
+
}
|
|
20368
|
+
return {
|
|
20369
|
+
kind: "auto_import",
|
|
20370
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20371
|
+
configPath,
|
|
20372
|
+
configFormat: "hermes_config_yaml",
|
|
20373
|
+
mcpServer
|
|
20374
|
+
};
|
|
20375
|
+
}
|
|
20376
|
+
function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
|
|
20377
|
+
return {
|
|
20378
|
+
kind: "manual",
|
|
20379
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20380
|
+
configFormat: "hermes_config_yaml",
|
|
20381
|
+
configPathCommand: HERMES_MCP_CONFIG_PATH,
|
|
20382
|
+
requiresRestart: true,
|
|
20383
|
+
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.",
|
|
20384
|
+
template: renderMeshCoordinatorTemplate(
|
|
20385
|
+
"mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
|
|
20386
|
+
{
|
|
20387
|
+
meshId,
|
|
20388
|
+
workspace,
|
|
20389
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20390
|
+
adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
|
|
20391
|
+
}
|
|
20392
|
+
)
|
|
20393
|
+
};
|
|
20394
|
+
}
|
|
20018
20395
|
function resolveMeshCoordinatorSetup(options) {
|
|
20019
20396
|
const { provider, meshId, workspace } = options;
|
|
20020
20397
|
const config = provider?.meshCoordinator;
|
|
@@ -20024,6 +20401,9 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20024
20401
|
reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
|
|
20025
20402
|
};
|
|
20026
20403
|
}
|
|
20404
|
+
if (isHermesProvider(provider, options.cliType)) {
|
|
20405
|
+
return resolveHermesMeshCoordinatorSetup(options);
|
|
20406
|
+
}
|
|
20027
20407
|
const mcpConfig = config.mcpConfig;
|
|
20028
20408
|
if (!mcpConfig || mcpConfig.mode === "none") {
|
|
20029
20409
|
return {
|
|
@@ -20033,8 +20413,8 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20033
20413
|
}
|
|
20034
20414
|
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
|
|
20035
20415
|
if (mcpConfig.mode === "auto_import") {
|
|
20036
|
-
const
|
|
20037
|
-
if (!
|
|
20416
|
+
const path27 = mcpConfig.path?.trim();
|
|
20417
|
+
if (!path27) {
|
|
20038
20418
|
return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
|
|
20039
20419
|
}
|
|
20040
20420
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
@@ -20045,13 +20425,13 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20045
20425
|
if (!mcpServer) {
|
|
20046
20426
|
return {
|
|
20047
20427
|
kind: "unsupported",
|
|
20048
|
-
reason: "Could not resolve the ADHDev MCP server entrypoint
|
|
20428
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20049
20429
|
};
|
|
20050
20430
|
}
|
|
20051
20431
|
return {
|
|
20052
20432
|
kind: "auto_import",
|
|
20053
20433
|
serverName,
|
|
20054
|
-
configPath: (
|
|
20434
|
+
configPath: resolveMcpConfigPath(path27, workspace),
|
|
20055
20435
|
configFormat: mcpConfig.format,
|
|
20056
20436
|
mcpServer
|
|
20057
20437
|
};
|
|
@@ -20085,14 +20465,85 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20085
20465
|
function renderMeshCoordinatorTemplate(template, values) {
|
|
20086
20466
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
|
|
20087
20467
|
}
|
|
20468
|
+
function resolveMcpConfigPath(configPath, workspace) {
|
|
20469
|
+
const trimmed = configPath.trim();
|
|
20470
|
+
if (trimmed === "~") return os17.homedir();
|
|
20471
|
+
if (trimmed.startsWith("~/")) return (0, import_node_path.join)(os17.homedir(), trimmed.slice(2));
|
|
20472
|
+
if ((0, import_node_path.isAbsolute)(trimmed)) return trimmed;
|
|
20473
|
+
return (0, import_node_path.join)(workspace, trimmed);
|
|
20474
|
+
}
|
|
20088
20475
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
20089
20476
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
20090
20477
|
if (!entryPath) return null;
|
|
20478
|
+
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
|
|
20479
|
+
if (!nodeExecutable) return null;
|
|
20091
20480
|
return {
|
|
20092
|
-
command:
|
|
20093
|
-
args: [entryPath, "--repo-mesh", options.meshId]
|
|
20481
|
+
command: nodeExecutable,
|
|
20482
|
+
args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
|
|
20094
20483
|
};
|
|
20095
20484
|
}
|
|
20485
|
+
function resolveMcpNodeExecutable(explicitExecutable) {
|
|
20486
|
+
const explicit = explicitExecutable?.trim();
|
|
20487
|
+
if (explicit) return explicit;
|
|
20488
|
+
const candidates = [];
|
|
20489
|
+
const addCandidate = (candidate) => {
|
|
20490
|
+
const trimmed = candidate?.trim();
|
|
20491
|
+
if (!trimmed) return;
|
|
20492
|
+
const normalized = normalizeExistingPath(trimmed) || trimmed;
|
|
20493
|
+
if (!candidates.includes(normalized)) candidates.push(normalized);
|
|
20494
|
+
};
|
|
20495
|
+
addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
|
|
20496
|
+
addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
|
|
20497
|
+
addCandidate(process.env.npm_node_execpath);
|
|
20498
|
+
addNodeCandidatesFromPath(process.env.PATH, addCandidate);
|
|
20499
|
+
addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
|
|
20500
|
+
addCandidate("/opt/homebrew/bin/node");
|
|
20501
|
+
addCandidate("/usr/local/bin/node");
|
|
20502
|
+
addCandidate("/usr/bin/node");
|
|
20503
|
+
addCandidate(process.execPath);
|
|
20504
|
+
for (const candidate of candidates) {
|
|
20505
|
+
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
|
|
20506
|
+
}
|
|
20507
|
+
return null;
|
|
20508
|
+
}
|
|
20509
|
+
function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
20510
|
+
for (const entry of (pathValue || "").split(":")) {
|
|
20511
|
+
const dir = entry.trim();
|
|
20512
|
+
if (!dir) continue;
|
|
20513
|
+
addCandidate((0, import_node_path.join)(dir, "node"));
|
|
20514
|
+
}
|
|
20515
|
+
}
|
|
20516
|
+
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
20517
|
+
const versionsDir = (0, import_node_path.join)(homeDir, ".nvm", "versions", "node");
|
|
20518
|
+
try {
|
|
20519
|
+
const versionDirs = (0, import_node_fs3.readdirSync)(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
20520
|
+
for (const versionDir of versionDirs) {
|
|
20521
|
+
addCandidate((0, import_node_path.join)(versionsDir, versionDir, "bin", "node"));
|
|
20522
|
+
}
|
|
20523
|
+
} catch {
|
|
20524
|
+
}
|
|
20525
|
+
}
|
|
20526
|
+
function compareNodeVersionNamesDescending(a, b) {
|
|
20527
|
+
const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
20528
|
+
const left = parse(a);
|
|
20529
|
+
const right = parse(b);
|
|
20530
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
20531
|
+
const diff = (right[i] || 0) - (left[i] || 0);
|
|
20532
|
+
if (diff !== 0) return diff;
|
|
20533
|
+
}
|
|
20534
|
+
return b.localeCompare(a);
|
|
20535
|
+
}
|
|
20536
|
+
function nodeRuntimeSupportsWebSocket(nodeExecutable) {
|
|
20537
|
+
try {
|
|
20538
|
+
(0, import_node_child_process3.execFileSync)(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
|
|
20539
|
+
stdio: "ignore",
|
|
20540
|
+
timeout: 3e3
|
|
20541
|
+
});
|
|
20542
|
+
return true;
|
|
20543
|
+
} catch {
|
|
20544
|
+
return false;
|
|
20545
|
+
}
|
|
20546
|
+
}
|
|
20096
20547
|
function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
20097
20548
|
const explicit = explicitPath?.trim();
|
|
20098
20549
|
if (explicit) return normalizeExistingPath(explicit) || explicit;
|
|
@@ -20128,15 +20579,109 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
20128
20579
|
}
|
|
20129
20580
|
function normalizeExistingPath(filePath) {
|
|
20130
20581
|
try {
|
|
20131
|
-
if (!(0,
|
|
20132
|
-
return
|
|
20582
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return null;
|
|
20583
|
+
return import_node_fs3.realpathSync.native(filePath);
|
|
20133
20584
|
} catch {
|
|
20134
20585
|
return null;
|
|
20135
20586
|
}
|
|
20136
20587
|
}
|
|
20137
20588
|
|
|
20589
|
+
// src/mesh/mesh-events.ts
|
|
20590
|
+
init_mesh_config();
|
|
20591
|
+
init_logger();
|
|
20592
|
+
function readNonEmptyString(value) {
|
|
20593
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
20594
|
+
}
|
|
20595
|
+
function formatCompletionMetadata(event) {
|
|
20596
|
+
const parts = [
|
|
20597
|
+
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
20598
|
+
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
20599
|
+
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
20600
|
+
].filter(Boolean);
|
|
20601
|
+
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
20602
|
+
}
|
|
20603
|
+
function buildMeshSystemMessage(args) {
|
|
20604
|
+
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
20605
|
+
if (args.event === "agent:generating_completed") {
|
|
20606
|
+
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.`;
|
|
20607
|
+
}
|
|
20608
|
+
if (args.event === "agent:waiting_approval") {
|
|
20609
|
+
return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
20610
|
+
}
|
|
20611
|
+
return "";
|
|
20612
|
+
}
|
|
20613
|
+
function injectMeshSystemMessage(components, args) {
|
|
20614
|
+
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
20615
|
+
const instState = inst.getState();
|
|
20616
|
+
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
20617
|
+
if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
|
|
20618
|
+
return true;
|
|
20619
|
+
});
|
|
20620
|
+
if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
|
|
20621
|
+
const messageText = buildMeshSystemMessage({
|
|
20622
|
+
event: args.event,
|
|
20623
|
+
nodeLabel: args.nodeLabel,
|
|
20624
|
+
metadataEvent: args.metadataEvent
|
|
20625
|
+
});
|
|
20626
|
+
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
20627
|
+
for (const coord of coordinatorInstances) {
|
|
20628
|
+
const coordState = coord.getState();
|
|
20629
|
+
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
20630
|
+
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
20631
|
+
}
|
|
20632
|
+
return { success: true, forwarded: coordinatorInstances.length };
|
|
20633
|
+
}
|
|
20634
|
+
function handleMeshForwardEvent(components, payload) {
|
|
20635
|
+
const eventName = readNonEmptyString(payload.event);
|
|
20636
|
+
if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
|
|
20637
|
+
return { success: false, error: "unsupported mesh event" };
|
|
20638
|
+
}
|
|
20639
|
+
const meshId = readNonEmptyString(payload.meshId);
|
|
20640
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
20641
|
+
const nodeId = readNonEmptyString(payload.nodeId);
|
|
20642
|
+
const workspace = readNonEmptyString(payload.workspace);
|
|
20643
|
+
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
20644
|
+
return injectMeshSystemMessage(components, {
|
|
20645
|
+
meshId,
|
|
20646
|
+
nodeLabel,
|
|
20647
|
+
event: eventName,
|
|
20648
|
+
metadataEvent: {
|
|
20649
|
+
targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
|
|
20650
|
+
providerType: readNonEmptyString(payload.providerType),
|
|
20651
|
+
providerSessionId: readNonEmptyString(payload.providerSessionId)
|
|
20652
|
+
}
|
|
20653
|
+
});
|
|
20654
|
+
}
|
|
20655
|
+
function setupMeshEventForwarding(components) {
|
|
20656
|
+
components.instanceManager.onEvent((event) => {
|
|
20657
|
+
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
20658
|
+
const instanceId = readNonEmptyString(event.instanceId);
|
|
20659
|
+
if (!instanceId) return;
|
|
20660
|
+
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
20661
|
+
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
20662
|
+
const state = sourceInstance.getState();
|
|
20663
|
+
const workspace = readNonEmptyString(state.workspace);
|
|
20664
|
+
if (!workspace) return;
|
|
20665
|
+
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
20666
|
+
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
20667
|
+
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
20668
|
+
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
20669
|
+
if (!meshId) return;
|
|
20670
|
+
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
20671
|
+
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
20672
|
+
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
20673
|
+
injectMeshSystemMessage(components, {
|
|
20674
|
+
meshId,
|
|
20675
|
+
sourceInstanceId: instanceId,
|
|
20676
|
+
nodeLabel,
|
|
20677
|
+
event: event.event,
|
|
20678
|
+
metadataEvent: event
|
|
20679
|
+
});
|
|
20680
|
+
});
|
|
20681
|
+
}
|
|
20682
|
+
|
|
20138
20683
|
// src/status/snapshot.ts
|
|
20139
|
-
var
|
|
20684
|
+
var os18 = __toESM(require("os"));
|
|
20140
20685
|
init_config();
|
|
20141
20686
|
init_terminal_screen();
|
|
20142
20687
|
init_logger();
|
|
@@ -20192,8 +20737,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20192
20737
|
}
|
|
20193
20738
|
function buildMachineInfo(profile = "full") {
|
|
20194
20739
|
const base = {
|
|
20195
|
-
hostname:
|
|
20196
|
-
platform:
|
|
20740
|
+
hostname: os18.hostname(),
|
|
20741
|
+
platform: os18.platform()
|
|
20197
20742
|
};
|
|
20198
20743
|
if (profile === "live") {
|
|
20199
20744
|
return base;
|
|
@@ -20202,23 +20747,23 @@ function buildMachineInfo(profile = "full") {
|
|
|
20202
20747
|
const memSnap2 = getHostMemorySnapshot();
|
|
20203
20748
|
return {
|
|
20204
20749
|
...base,
|
|
20205
|
-
arch:
|
|
20206
|
-
cpus:
|
|
20750
|
+
arch: os18.arch(),
|
|
20751
|
+
cpus: os18.cpus().length,
|
|
20207
20752
|
totalMem: memSnap2.totalMem,
|
|
20208
|
-
release:
|
|
20753
|
+
release: os18.release()
|
|
20209
20754
|
};
|
|
20210
20755
|
}
|
|
20211
20756
|
const memSnap = getHostMemorySnapshot();
|
|
20212
20757
|
return {
|
|
20213
20758
|
...base,
|
|
20214
|
-
arch:
|
|
20215
|
-
cpus:
|
|
20759
|
+
arch: os18.arch(),
|
|
20760
|
+
cpus: os18.cpus().length,
|
|
20216
20761
|
totalMem: memSnap.totalMem,
|
|
20217
20762
|
freeMem: memSnap.freeMem,
|
|
20218
20763
|
availableMem: memSnap.availableMem,
|
|
20219
|
-
loadavg:
|
|
20220
|
-
uptime:
|
|
20221
|
-
release:
|
|
20764
|
+
loadavg: os18.loadavg(),
|
|
20765
|
+
uptime: os18.uptime(),
|
|
20766
|
+
release: os18.release()
|
|
20222
20767
|
};
|
|
20223
20768
|
}
|
|
20224
20769
|
function parseMessageTime(value) {
|
|
@@ -20452,14 +20997,14 @@ function buildStatusSnapshot(options) {
|
|
|
20452
20997
|
var import_child_process8 = require("child_process");
|
|
20453
20998
|
var import_child_process9 = require("child_process");
|
|
20454
20999
|
var fs9 = __toESM(require("fs"));
|
|
20455
|
-
var
|
|
20456
|
-
var
|
|
21000
|
+
var os19 = __toESM(require("os"));
|
|
21001
|
+
var path21 = __toESM(require("path"));
|
|
20457
21002
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
20458
21003
|
function getUpgradeLogPath() {
|
|
20459
|
-
const home =
|
|
20460
|
-
const dir =
|
|
21004
|
+
const home = os19.homedir();
|
|
21005
|
+
const dir = path21.join(home, ".adhdev");
|
|
20461
21006
|
fs9.mkdirSync(dir, { recursive: true });
|
|
20462
|
-
return
|
|
21007
|
+
return path21.join(dir, "daemon-upgrade.log");
|
|
20463
21008
|
}
|
|
20464
21009
|
function appendUpgradeLog(message) {
|
|
20465
21010
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -20470,14 +21015,14 @@ function appendUpgradeLog(message) {
|
|
|
20470
21015
|
}
|
|
20471
21016
|
}
|
|
20472
21017
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
20473
|
-
const binDir =
|
|
21018
|
+
const binDir = path21.dirname(nodeExecutable);
|
|
20474
21019
|
if (platform10 === "win32") {
|
|
20475
|
-
const npmCliPath =
|
|
21020
|
+
const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
20476
21021
|
if (fs9.existsSync(npmCliPath)) {
|
|
20477
21022
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20478
21023
|
}
|
|
20479
21024
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
20480
|
-
const candidatePath =
|
|
21025
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20481
21026
|
if (fs9.existsSync(candidatePath)) {
|
|
20482
21027
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20483
21028
|
}
|
|
@@ -20485,7 +21030,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
20485
21030
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20486
21031
|
}
|
|
20487
21032
|
for (const candidate of ["npm"]) {
|
|
20488
|
-
const candidatePath =
|
|
21033
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20489
21034
|
if (fs9.existsSync(candidatePath)) {
|
|
20490
21035
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20491
21036
|
}
|
|
@@ -20502,13 +21047,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20502
21047
|
let currentDir = resolvedPath;
|
|
20503
21048
|
try {
|
|
20504
21049
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
20505
|
-
currentDir =
|
|
21050
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20506
21051
|
}
|
|
20507
21052
|
} catch {
|
|
20508
|
-
currentDir =
|
|
21053
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20509
21054
|
}
|
|
20510
21055
|
while (true) {
|
|
20511
|
-
const packageJsonPath =
|
|
21056
|
+
const packageJsonPath = path21.join(currentDir, "package.json");
|
|
20512
21057
|
try {
|
|
20513
21058
|
if (fs9.existsSync(packageJsonPath)) {
|
|
20514
21059
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -20519,7 +21064,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20519
21064
|
}
|
|
20520
21065
|
} catch {
|
|
20521
21066
|
}
|
|
20522
|
-
const parentDir =
|
|
21067
|
+
const parentDir = path21.dirname(currentDir);
|
|
20523
21068
|
if (parentDir === currentDir) {
|
|
20524
21069
|
return null;
|
|
20525
21070
|
}
|
|
@@ -20527,13 +21072,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20527
21072
|
}
|
|
20528
21073
|
}
|
|
20529
21074
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
20530
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
20531
|
-
if (
|
|
21075
|
+
const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
|
|
21076
|
+
if (path21.basename(nodeModulesDir) !== "node_modules") {
|
|
20532
21077
|
return null;
|
|
20533
21078
|
}
|
|
20534
|
-
const maybeLibDir =
|
|
20535
|
-
if (
|
|
20536
|
-
return
|
|
21079
|
+
const maybeLibDir = path21.dirname(nodeModulesDir);
|
|
21080
|
+
if (path21.basename(maybeLibDir) === "lib") {
|
|
21081
|
+
return path21.dirname(maybeLibDir);
|
|
20537
21082
|
}
|
|
20538
21083
|
return maybeLibDir;
|
|
20539
21084
|
}
|
|
@@ -20648,7 +21193,7 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
20648
21193
|
}
|
|
20649
21194
|
}
|
|
20650
21195
|
function stopSessionHostProcesses(appName) {
|
|
20651
|
-
const pidFile =
|
|
21196
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
20652
21197
|
try {
|
|
20653
21198
|
if (fs9.existsSync(pidFile)) {
|
|
20654
21199
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -20665,7 +21210,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
20665
21210
|
}
|
|
20666
21211
|
}
|
|
20667
21212
|
function removeDaemonPidFile() {
|
|
20668
|
-
const pidFile =
|
|
21213
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
20669
21214
|
try {
|
|
20670
21215
|
fs9.unlinkSync(pidFile);
|
|
20671
21216
|
} catch {
|
|
@@ -20676,7 +21221,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20676
21221
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20677
21222
|
if (!npmRoot) return;
|
|
20678
21223
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20679
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
21224
|
+
const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
|
|
20680
21225
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
20681
21226
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
20682
21227
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -20684,25 +21229,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20684
21229
|
}
|
|
20685
21230
|
if (pkgName.startsWith("@")) {
|
|
20686
21231
|
const [scope, name] = pkgName.split("/");
|
|
20687
|
-
const scopeDir =
|
|
21232
|
+
const scopeDir = path21.join(npmRoot, scope);
|
|
20688
21233
|
if (!fs9.existsSync(scopeDir)) return;
|
|
20689
21234
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
20690
21235
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
20691
|
-
fs9.rmSync(
|
|
20692
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
21236
|
+
fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
|
|
21237
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
|
|
20693
21238
|
}
|
|
20694
21239
|
} else {
|
|
20695
21240
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
20696
21241
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
20697
|
-
fs9.rmSync(
|
|
20698
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
21242
|
+
fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
|
|
21243
|
+
appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
|
|
20699
21244
|
}
|
|
20700
21245
|
}
|
|
20701
21246
|
if (fs9.existsSync(binDir)) {
|
|
20702
21247
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
20703
21248
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
20704
|
-
fs9.rmSync(
|
|
20705
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
21249
|
+
fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
|
|
21250
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
|
|
20706
21251
|
}
|
|
20707
21252
|
}
|
|
20708
21253
|
}
|
|
@@ -20803,6 +21348,56 @@ function normalizeReleaseChannel(value) {
|
|
|
20803
21348
|
function resolveUpgradeChannel(args) {
|
|
20804
21349
|
return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
|
|
20805
21350
|
}
|
|
21351
|
+
function readProviderPriorityFromPolicy(policy) {
|
|
21352
|
+
const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
|
|
21353
|
+
const raw = record.providerPriority;
|
|
21354
|
+
if (!Array.isArray(raw)) return [];
|
|
21355
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21356
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
21357
|
+
if (seen.has(type)) return false;
|
|
21358
|
+
seen.add(type);
|
|
21359
|
+
return true;
|
|
21360
|
+
});
|
|
21361
|
+
}
|
|
21362
|
+
async function resolveProviderTypeFromPriority(args) {
|
|
21363
|
+
if (!args.providerPriority.length) {
|
|
21364
|
+
return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
|
|
21365
|
+
}
|
|
21366
|
+
const failed = [];
|
|
21367
|
+
for (const requestedType of args.providerPriority) {
|
|
21368
|
+
const normalizedType = args.providerLoader.resolveAlias(requestedType);
|
|
21369
|
+
if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
21370
|
+
failed.push(`${requestedType}: disabled`);
|
|
21371
|
+
continue;
|
|
21372
|
+
}
|
|
21373
|
+
const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
|
|
21374
|
+
args.providerLoader.setCliDetectionResults([{
|
|
21375
|
+
id: normalizedType,
|
|
21376
|
+
installed: !!detected,
|
|
21377
|
+
path: detected?.path
|
|
21378
|
+
}], false);
|
|
21379
|
+
args.onStatusChange?.();
|
|
21380
|
+
if (detected) return { providerType: normalizedType };
|
|
21381
|
+
failed.push(`${requestedType}: not detected`);
|
|
21382
|
+
}
|
|
21383
|
+
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
21384
|
+
}
|
|
21385
|
+
function loadYamlModule() {
|
|
21386
|
+
return yaml;
|
|
21387
|
+
}
|
|
21388
|
+
function getMcpServersKey(format) {
|
|
21389
|
+
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
21390
|
+
}
|
|
21391
|
+
function parseMeshCoordinatorMcpConfig(text, format) {
|
|
21392
|
+
if (!text.trim()) return {};
|
|
21393
|
+
if (format === "claude_mcp_json") return JSON.parse(text);
|
|
21394
|
+
const parsed = loadYamlModule().load(text);
|
|
21395
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
21396
|
+
}
|
|
21397
|
+
function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
21398
|
+
if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
|
|
21399
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
21400
|
+
}
|
|
20806
21401
|
var CHAT_COMMANDS = [
|
|
20807
21402
|
"send_chat",
|
|
20808
21403
|
"new_chat",
|
|
@@ -20901,6 +21496,154 @@ var DaemonCommandRouter = class {
|
|
|
20901
21496
|
constructor(deps) {
|
|
20902
21497
|
this.deps = deps;
|
|
20903
21498
|
}
|
|
21499
|
+
getCachedInlineMesh(meshId, inlineMesh) {
|
|
21500
|
+
if (inlineMesh && typeof inlineMesh === "object") {
|
|
21501
|
+
this.inlineMeshCache.set(meshId, inlineMesh);
|
|
21502
|
+
return inlineMesh;
|
|
21503
|
+
}
|
|
21504
|
+
return this.inlineMeshCache.get(meshId);
|
|
21505
|
+
}
|
|
21506
|
+
async getMeshForCommand(meshId, inlineMesh) {
|
|
21507
|
+
try {
|
|
21508
|
+
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21509
|
+
const mesh = getMesh3(meshId);
|
|
21510
|
+
if (mesh) return { mesh, inline: false };
|
|
21511
|
+
} catch {
|
|
21512
|
+
}
|
|
21513
|
+
const cached = this.getCachedInlineMesh(meshId, inlineMesh);
|
|
21514
|
+
return cached ? { mesh: cached, inline: true } : null;
|
|
21515
|
+
}
|
|
21516
|
+
updateInlineMeshNode(meshId, mesh, node) {
|
|
21517
|
+
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
21518
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
21519
|
+
if (idx >= 0) mesh.nodes[idx] = node;
|
|
21520
|
+
else mesh.nodes.push(node);
|
|
21521
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21522
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21523
|
+
}
|
|
21524
|
+
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
21525
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
21526
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
|
|
21527
|
+
if (idx === -1) return false;
|
|
21528
|
+
mesh.nodes.splice(idx, 1);
|
|
21529
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21530
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21531
|
+
return true;
|
|
21532
|
+
}
|
|
21533
|
+
normalizeMeshSessionCleanupMode(value) {
|
|
21534
|
+
return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
|
|
21535
|
+
}
|
|
21536
|
+
sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
|
|
21537
|
+
const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
|
|
21538
|
+
if (!sessionId) return false;
|
|
21539
|
+
if (sessionIds?.size) return sessionIds.has(sessionId);
|
|
21540
|
+
const workspace = typeof node?.workspace === "string" ? node.workspace : "";
|
|
21541
|
+
if (workspace && record?.workspace === workspace) return true;
|
|
21542
|
+
if (record?.meta?.meshNodeId === nodeId) return true;
|
|
21543
|
+
return false;
|
|
21544
|
+
}
|
|
21545
|
+
isCompletedHostedSession(record) {
|
|
21546
|
+
return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
|
|
21547
|
+
}
|
|
21548
|
+
async cleanupMeshSessions(args) {
|
|
21549
|
+
if (args.mode === "preserve") {
|
|
21550
|
+
return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
|
|
21551
|
+
}
|
|
21552
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
21553
|
+
const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
|
|
21554
|
+
const sessions = await this.deps.sessionHostControl.listSessions();
|
|
21555
|
+
const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
|
|
21556
|
+
const hasExplicitSessionIds = !!requestedSessionIds?.size;
|
|
21557
|
+
const stoppedSessionIds = [];
|
|
21558
|
+
const deletedSessionIds = [];
|
|
21559
|
+
const skippedSessionIds = [];
|
|
21560
|
+
const skippedLiveSessionIds = [];
|
|
21561
|
+
const deleteUnsupportedSessionIds = [];
|
|
21562
|
+
const recordsRemainSessionIds = [];
|
|
21563
|
+
const errors = [];
|
|
21564
|
+
const matchedBySurfaceKind = {
|
|
21565
|
+
live_runtime: 0,
|
|
21566
|
+
recovery_snapshot: 0,
|
|
21567
|
+
inactive_record: 0
|
|
21568
|
+
};
|
|
21569
|
+
for (const record of matched) {
|
|
21570
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21571
|
+
matchedBySurfaceKind[surfaceKind] += 1;
|
|
21572
|
+
}
|
|
21573
|
+
for (const record of matched) {
|
|
21574
|
+
const sessionId = String(record.sessionId);
|
|
21575
|
+
const completed = this.isCompletedHostedSession(record);
|
|
21576
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21577
|
+
const liveRuntime = surfaceKind === "live_runtime";
|
|
21578
|
+
if (!hasExplicitSessionIds && liveRuntime) {
|
|
21579
|
+
skippedSessionIds.push(sessionId);
|
|
21580
|
+
skippedLiveSessionIds.push(sessionId);
|
|
21581
|
+
continue;
|
|
21582
|
+
}
|
|
21583
|
+
try {
|
|
21584
|
+
if (args.mode === "stop") {
|
|
21585
|
+
if (!completed) {
|
|
21586
|
+
if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21587
|
+
stoppedSessionIds.push(sessionId);
|
|
21588
|
+
} else {
|
|
21589
|
+
skippedSessionIds.push(sessionId);
|
|
21590
|
+
}
|
|
21591
|
+
continue;
|
|
21592
|
+
}
|
|
21593
|
+
if (args.mode === "delete_stopped") {
|
|
21594
|
+
if (completed) {
|
|
21595
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
|
|
21596
|
+
deletedSessionIds.push(sessionId);
|
|
21597
|
+
} else {
|
|
21598
|
+
skippedSessionIds.push(sessionId);
|
|
21599
|
+
}
|
|
21600
|
+
continue;
|
|
21601
|
+
}
|
|
21602
|
+
if (args.mode === "stop_and_delete") {
|
|
21603
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
|
|
21604
|
+
deletedSessionIds.push(sessionId);
|
|
21605
|
+
continue;
|
|
21606
|
+
}
|
|
21607
|
+
} catch (e) {
|
|
21608
|
+
const message = e?.message || String(e);
|
|
21609
|
+
if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
|
|
21610
|
+
deleteUnsupportedSessionIds.push(sessionId);
|
|
21611
|
+
recordsRemainSessionIds.push(sessionId);
|
|
21612
|
+
if (args.mode === "stop_and_delete" && !completed) {
|
|
21613
|
+
try {
|
|
21614
|
+
await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21615
|
+
stoppedSessionIds.push(sessionId);
|
|
21616
|
+
} catch (stopError) {
|
|
21617
|
+
errors.push({ sessionId, error: stopError?.message || String(stopError) });
|
|
21618
|
+
continue;
|
|
21619
|
+
}
|
|
21620
|
+
}
|
|
21621
|
+
skippedSessionIds.push(sessionId);
|
|
21622
|
+
continue;
|
|
21623
|
+
}
|
|
21624
|
+
errors.push({ sessionId, error: message });
|
|
21625
|
+
}
|
|
21626
|
+
}
|
|
21627
|
+
const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
|
|
21628
|
+
return {
|
|
21629
|
+
success: errors.length === 0,
|
|
21630
|
+
mode: args.mode,
|
|
21631
|
+
dryRun: args.dryRun === true,
|
|
21632
|
+
matchedCount: matched.length,
|
|
21633
|
+
matchedBySurfaceKind,
|
|
21634
|
+
stoppedSessionIds,
|
|
21635
|
+
deletedSessionIds,
|
|
21636
|
+
skippedSessionIds,
|
|
21637
|
+
skippedLiveSessionIds,
|
|
21638
|
+
...deleteUnsupported ? {
|
|
21639
|
+
deleteUnsupported: true,
|
|
21640
|
+
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
21641
|
+
deleteUnsupportedSessionIds,
|
|
21642
|
+
recordsRemainSessionIds
|
|
21643
|
+
} : {},
|
|
21644
|
+
...errors.length ? { errors } : {}
|
|
21645
|
+
};
|
|
21646
|
+
}
|
|
20904
21647
|
async traceSessionHostAction(action, args, run, summarizeResult) {
|
|
20905
21648
|
const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
|
|
20906
21649
|
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -21020,6 +21763,9 @@ var DaemonCommandRouter = class {
|
|
|
21020
21763
|
async executeDaemonCommand(cmd, args) {
|
|
21021
21764
|
switch (cmd) {
|
|
21022
21765
|
// ─── CLI / ACP commands ───
|
|
21766
|
+
case "mesh_forward_event": {
|
|
21767
|
+
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
21768
|
+
}
|
|
21023
21769
|
case "launch_cli":
|
|
21024
21770
|
case "stop_cli":
|
|
21025
21771
|
case "set_cli_view_mode":
|
|
@@ -21564,7 +22310,26 @@ var DaemonCommandRouter = class {
|
|
|
21564
22310
|
if (!name) return { success: false, error: "name required" };
|
|
21565
22311
|
try {
|
|
21566
22312
|
const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21567
|
-
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
|
|
22313
|
+
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
|
|
22314
|
+
return { success: true, mesh };
|
|
22315
|
+
} catch (e) {
|
|
22316
|
+
return { success: false, error: e.message };
|
|
22317
|
+
}
|
|
22318
|
+
}
|
|
22319
|
+
case "update_mesh": {
|
|
22320
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22321
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22322
|
+
try {
|
|
22323
|
+
const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22324
|
+
const patch = {};
|
|
22325
|
+
if (typeof args?.name === "string") patch.name = args.name;
|
|
22326
|
+
if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
|
|
22327
|
+
if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
|
|
22328
|
+
if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
|
|
22329
|
+
if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
|
|
22330
|
+
const mesh = updateMesh2(meshId, patch);
|
|
22331
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22332
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21568
22333
|
return { success: true, mesh };
|
|
21569
22334
|
} catch (e) {
|
|
21570
22335
|
return { success: false, error: e.message };
|
|
@@ -21588,21 +22353,164 @@ var DaemonCommandRouter = class {
|
|
|
21588
22353
|
if (!workspace) return { success: false, error: "workspace required" };
|
|
21589
22354
|
try {
|
|
21590
22355
|
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21591
|
-
const
|
|
22356
|
+
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
22357
|
+
const readOnly = args?.readOnly === true;
|
|
22358
|
+
const policy = {
|
|
22359
|
+
...readOnly ? { readOnly: true } : {},
|
|
22360
|
+
...providerPriority.length ? { providerPriority } : {}
|
|
22361
|
+
};
|
|
22362
|
+
const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
|
|
21592
22363
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
21593
22364
|
return { success: true, node };
|
|
21594
22365
|
} catch (e) {
|
|
21595
22366
|
return { success: false, error: e.message };
|
|
21596
22367
|
}
|
|
21597
22368
|
}
|
|
22369
|
+
case "update_mesh_node": {
|
|
22370
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22371
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22372
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22373
|
+
try {
|
|
22374
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22375
|
+
const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
|
|
22376
|
+
if (Array.isArray(args?.providerPriority)) {
|
|
22377
|
+
const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
|
|
22378
|
+
delete policy.provider_priority;
|
|
22379
|
+
if (providerPriority.length) {
|
|
22380
|
+
policy.providerPriority = providerPriority;
|
|
22381
|
+
} else {
|
|
22382
|
+
delete policy.providerPriority;
|
|
22383
|
+
}
|
|
22384
|
+
}
|
|
22385
|
+
const node = updateNode2(meshId, nodeId, { policy });
|
|
22386
|
+
if (!node) return { success: false, error: "Mesh node not found" };
|
|
22387
|
+
return { success: true, node };
|
|
22388
|
+
} catch (e) {
|
|
22389
|
+
return { success: false, error: e.message };
|
|
22390
|
+
}
|
|
22391
|
+
}
|
|
22392
|
+
case "cleanup_mesh_sessions": {
|
|
22393
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22394
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22395
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22396
|
+
try {
|
|
22397
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22398
|
+
const mesh = meshRecord?.mesh;
|
|
22399
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22400
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22401
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
22402
|
+
const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
|
|
22403
|
+
const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
|
|
22404
|
+
const result = await this.cleanupMeshSessions({
|
|
22405
|
+
meshId,
|
|
22406
|
+
nodeId,
|
|
22407
|
+
node,
|
|
22408
|
+
mode,
|
|
22409
|
+
sessionIds,
|
|
22410
|
+
dryRun: args?.dryRun === true
|
|
22411
|
+
});
|
|
22412
|
+
return result;
|
|
22413
|
+
} catch (e) {
|
|
22414
|
+
return { success: false, error: e.message };
|
|
22415
|
+
}
|
|
22416
|
+
}
|
|
21598
22417
|
case "remove_mesh_node": {
|
|
21599
22418
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21600
22419
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
21601
22420
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
21602
22421
|
try {
|
|
21603
|
-
const
|
|
21604
|
-
const
|
|
21605
|
-
|
|
22422
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22423
|
+
const mesh = meshRecord?.mesh;
|
|
22424
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22425
|
+
const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
|
|
22426
|
+
args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
|
|
22427
|
+
);
|
|
22428
|
+
let sessionCleanup;
|
|
22429
|
+
if (node && sessionCleanupMode !== "preserve") {
|
|
22430
|
+
sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
|
|
22431
|
+
if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
|
|
22432
|
+
}
|
|
22433
|
+
if (node?.isLocalWorktree && node.workspace) {
|
|
22434
|
+
try {
|
|
22435
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
22436
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
22437
|
+
if (repoRoot) {
|
|
22438
|
+
const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22439
|
+
await removeWorktree2(repoRoot, node.workspace);
|
|
22440
|
+
}
|
|
22441
|
+
} catch (e) {
|
|
22442
|
+
LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
|
|
22443
|
+
}
|
|
22444
|
+
}
|
|
22445
|
+
let removed = false;
|
|
22446
|
+
if (meshRecord?.inline) {
|
|
22447
|
+
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
22448
|
+
} else {
|
|
22449
|
+
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22450
|
+
removed = removeNode3(meshId, nodeId);
|
|
22451
|
+
}
|
|
22452
|
+
return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
|
|
22453
|
+
} catch (e) {
|
|
22454
|
+
return { success: false, error: e.message };
|
|
22455
|
+
}
|
|
22456
|
+
}
|
|
22457
|
+
case "clone_mesh_node": {
|
|
22458
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22459
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
22460
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
22461
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
22462
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22463
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
22464
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
22465
|
+
try {
|
|
22466
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22467
|
+
const mesh = meshRecord?.mesh;
|
|
22468
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22469
|
+
const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
|
|
22470
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
22471
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
22472
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22473
|
+
const result = await createWorktree2({
|
|
22474
|
+
repoRoot,
|
|
22475
|
+
branch,
|
|
22476
|
+
baseBranch,
|
|
22477
|
+
meshName: mesh.name
|
|
22478
|
+
});
|
|
22479
|
+
let node;
|
|
22480
|
+
if (meshRecord.inline) {
|
|
22481
|
+
const { randomUUID: randomUUID8 } = await import("crypto");
|
|
22482
|
+
node = {
|
|
22483
|
+
id: `node_${randomUUID8().replace(/-/g, "")}`,
|
|
22484
|
+
workspace: result.worktreePath,
|
|
22485
|
+
repoRoot: result.worktreePath,
|
|
22486
|
+
daemonId: sourceNode.daemonId,
|
|
22487
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22488
|
+
policy: { ...sourceNode.policy || {} },
|
|
22489
|
+
isLocalWorktree: true,
|
|
22490
|
+
worktreeBranch: result.branch,
|
|
22491
|
+
clonedFromNodeId: sourceNodeId
|
|
22492
|
+
};
|
|
22493
|
+
this.updateInlineMeshNode(meshId, mesh, node);
|
|
22494
|
+
} else {
|
|
22495
|
+
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22496
|
+
node = addNode3(meshId, {
|
|
22497
|
+
workspace: result.worktreePath,
|
|
22498
|
+
repoRoot: result.worktreePath,
|
|
22499
|
+
daemonId: sourceNode.daemonId,
|
|
22500
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22501
|
+
isLocalWorktree: true,
|
|
22502
|
+
worktreeBranch: result.branch,
|
|
22503
|
+
clonedFromNodeId: sourceNodeId,
|
|
22504
|
+
policy: { ...sourceNode.policy || {} }
|
|
22505
|
+
});
|
|
22506
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
22507
|
+
}
|
|
22508
|
+
return {
|
|
22509
|
+
success: true,
|
|
22510
|
+
node,
|
|
22511
|
+
worktreePath: result.worktreePath,
|
|
22512
|
+
branch: result.branch
|
|
22513
|
+
};
|
|
21606
22514
|
} catch (e) {
|
|
21607
22515
|
return { success: false, error: e.message };
|
|
21608
22516
|
}
|
|
@@ -21610,7 +22518,7 @@ var DaemonCommandRouter = class {
|
|
|
21610
22518
|
// ─── Mesh Coordinator Launch ───
|
|
21611
22519
|
case "launch_mesh_coordinator": {
|
|
21612
22520
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21613
|
-
|
|
22521
|
+
let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
|
|
21614
22522
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
21615
22523
|
try {
|
|
21616
22524
|
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
@@ -21638,9 +22546,29 @@ var DaemonCommandRouter = class {
|
|
|
21638
22546
|
}
|
|
21639
22547
|
const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
|
|
21640
22548
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
22549
|
+
if (!cliType) {
|
|
22550
|
+
const resolved = await resolveProviderTypeFromPriority({
|
|
22551
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
|
|
22552
|
+
providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
|
|
22553
|
+
providerLoader: this.deps.providerLoader,
|
|
22554
|
+
onStatusChange: this.deps.onStatusChange
|
|
22555
|
+
});
|
|
22556
|
+
if (!resolved.providerType) {
|
|
22557
|
+
return {
|
|
22558
|
+
success: false,
|
|
22559
|
+
code: "mesh_coordinator_provider_priority_unusable",
|
|
22560
|
+
error: resolved.error || "No usable provider found from node providerPriority",
|
|
22561
|
+
meshId,
|
|
22562
|
+
cliType,
|
|
22563
|
+
workspace
|
|
22564
|
+
};
|
|
22565
|
+
}
|
|
22566
|
+
cliType = resolved.providerType;
|
|
22567
|
+
}
|
|
21641
22568
|
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
21642
22569
|
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
21643
22570
|
provider: providerMeta,
|
|
22571
|
+
cliType,
|
|
21644
22572
|
meshId,
|
|
21645
22573
|
workspace
|
|
21646
22574
|
});
|
|
@@ -21665,7 +22593,8 @@ var DaemonCommandRouter = class {
|
|
|
21665
22593
|
meshCoordinatorSetup: coordinatorSetup
|
|
21666
22594
|
};
|
|
21667
22595
|
}
|
|
21668
|
-
|
|
22596
|
+
const configFormat = coordinatorSetup.configFormat;
|
|
22597
|
+
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
21669
22598
|
return {
|
|
21670
22599
|
success: false,
|
|
21671
22600
|
code: "mesh_coordinator_unsupported",
|
|
@@ -21675,44 +22604,93 @@ var DaemonCommandRouter = class {
|
|
|
21675
22604
|
workspace
|
|
21676
22605
|
};
|
|
21677
22606
|
}
|
|
21678
|
-
|
|
21679
|
-
|
|
21680
|
-
|
|
21681
|
-
|
|
21682
|
-
|
|
21683
|
-
|
|
21684
|
-
|
|
21685
|
-
|
|
21686
|
-
|
|
21687
|
-
|
|
22607
|
+
let systemPrompt = "";
|
|
22608
|
+
try {
|
|
22609
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
22610
|
+
} catch (error) {
|
|
22611
|
+
const message = error?.message || String(error);
|
|
22612
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
22613
|
+
return {
|
|
22614
|
+
success: false,
|
|
22615
|
+
code: "mesh_coordinator_prompt_failed",
|
|
22616
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
22617
|
+
meshId,
|
|
22618
|
+
cliType,
|
|
22619
|
+
workspace
|
|
22620
|
+
};
|
|
21688
22621
|
}
|
|
22622
|
+
const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
|
|
22623
|
+
const { dirname: dirname9 } = await import("path");
|
|
22624
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
22625
|
+
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
22626
|
+
const returnManualFallback = (message) => ({
|
|
22627
|
+
success: false,
|
|
22628
|
+
code: "mesh_coordinator_manual_mcp_setup_required",
|
|
22629
|
+
error: message,
|
|
22630
|
+
meshId,
|
|
22631
|
+
cliType,
|
|
22632
|
+
workspace,
|
|
22633
|
+
meshCoordinatorSetup: hermesManualFallback
|
|
22634
|
+
});
|
|
21689
22635
|
const mcpServerEntry = {
|
|
21690
22636
|
command: coordinatorSetup.mcpServer.command,
|
|
21691
22637
|
args: coordinatorSetup.mcpServer.args
|
|
21692
22638
|
};
|
|
21693
22639
|
if (args?.inlineMesh) {
|
|
21694
22640
|
mcpServerEntry.env = {
|
|
21695
|
-
ADHDEV_INLINE_MESH: JSON.stringify(mesh)
|
|
22641
|
+
ADHDEV_INLINE_MESH: JSON.stringify(mesh),
|
|
22642
|
+
ADHDEV_MCP_TRANSPORT: "ipc"
|
|
21696
22643
|
};
|
|
21697
22644
|
}
|
|
22645
|
+
try {
|
|
22646
|
+
mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
|
|
22647
|
+
} catch (error) {
|
|
22648
|
+
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
22649
|
+
LOG.error("MeshCoordinator", message);
|
|
22650
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22651
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
22652
|
+
}
|
|
22653
|
+
const hadExistingMcpConfig = existsSync23(mcpConfigPath);
|
|
22654
|
+
let existingMcpConfig = {};
|
|
22655
|
+
if (hadExistingMcpConfig) {
|
|
22656
|
+
try {
|
|
22657
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
|
|
22658
|
+
copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
|
|
22659
|
+
} catch (error) {
|
|
22660
|
+
LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
22661
|
+
return {
|
|
22662
|
+
success: false,
|
|
22663
|
+
code: "mesh_coordinator_config_parse_failed",
|
|
22664
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`
|
|
22665
|
+
};
|
|
22666
|
+
}
|
|
22667
|
+
}
|
|
22668
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
22669
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
21698
22670
|
const mcpConfig = {
|
|
21699
22671
|
...existingMcpConfig,
|
|
21700
|
-
|
|
21701
|
-
...
|
|
22672
|
+
[mcpServersKey]: {
|
|
22673
|
+
...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
|
|
21702
22674
|
[coordinatorSetup.serverName]: mcpServerEntry
|
|
21703
22675
|
}
|
|
21704
22676
|
};
|
|
21705
|
-
writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
21706
|
-
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21707
|
-
let systemPrompt = "";
|
|
21708
22677
|
try {
|
|
21709
|
-
|
|
21710
|
-
} catch {
|
|
21711
|
-
|
|
22678
|
+
writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
22679
|
+
} catch (error) {
|
|
22680
|
+
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
22681
|
+
LOG.error("MeshCoordinator", message);
|
|
22682
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22683
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21712
22684
|
}
|
|
22685
|
+
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21713
22686
|
const cliArgs = [];
|
|
22687
|
+
const launchEnv = {};
|
|
21714
22688
|
if (systemPrompt) {
|
|
21715
|
-
|
|
22689
|
+
if (configFormat === "hermes_config_yaml") {
|
|
22690
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
22691
|
+
} else {
|
|
22692
|
+
cliArgs.push("--append-system-prompt", systemPrompt);
|
|
22693
|
+
}
|
|
21716
22694
|
}
|
|
21717
22695
|
if (cliType === "claude-cli") {
|
|
21718
22696
|
cliArgs.push("--mcp-config", coordinatorSetup.configPath);
|
|
@@ -21721,6 +22699,7 @@ var DaemonCommandRouter = class {
|
|
|
21721
22699
|
cliType,
|
|
21722
22700
|
dir: workspace,
|
|
21723
22701
|
cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
|
|
22702
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
21724
22703
|
settings: {
|
|
21725
22704
|
meshCoordinatorFor: meshId
|
|
21726
22705
|
}
|
|
@@ -21900,6 +22879,12 @@ var DaemonStatusReporter = class {
|
|
|
21900
22879
|
if (providerType) {
|
|
21901
22880
|
payload.providerType = providerType;
|
|
21902
22881
|
}
|
|
22882
|
+
if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
|
|
22883
|
+
payload.providerSessionId = event.providerSessionId.trim();
|
|
22884
|
+
}
|
|
22885
|
+
if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
|
|
22886
|
+
payload.workspaceName = event.workspaceName.trim();
|
|
22887
|
+
}
|
|
21903
22888
|
if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
|
|
21904
22889
|
payload.duration = event.duration;
|
|
21905
22890
|
}
|
|
@@ -23147,7 +24132,10 @@ var ProviderInstanceManager = class {
|
|
|
23147
24132
|
this.instances.get(id).dispose();
|
|
23148
24133
|
}
|
|
23149
24134
|
this.instances.set(id, instance);
|
|
23150
|
-
await instance.init(
|
|
24135
|
+
await instance.init({
|
|
24136
|
+
...context,
|
|
24137
|
+
emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
|
|
24138
|
+
});
|
|
23151
24139
|
}
|
|
23152
24140
|
/**
|
|
23153
24141
|
* Instance remove
|
|
@@ -23309,6 +24297,17 @@ var ProviderInstanceManager = class {
|
|
|
23309
24297
|
onEvent(listener) {
|
|
23310
24298
|
this.eventListeners.push(listener);
|
|
23311
24299
|
}
|
|
24300
|
+
emitProviderEvent(providerType, instanceId, event) {
|
|
24301
|
+
const payload = {
|
|
24302
|
+
...event,
|
|
24303
|
+
providerType,
|
|
24304
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
|
|
24305
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
|
|
24306
|
+
};
|
|
24307
|
+
for (const listener of this.eventListeners) {
|
|
24308
|
+
listener(payload);
|
|
24309
|
+
}
|
|
24310
|
+
}
|
|
23312
24311
|
emitPendingEvents(providerType, state, extra = {}) {
|
|
23313
24312
|
for (const event of state.pendingEvents) {
|
|
23314
24313
|
for (const listener of this.eventListeners) {
|
|
@@ -23381,11 +24380,11 @@ var ProviderInstanceManager = class {
|
|
|
23381
24380
|
|
|
23382
24381
|
// src/providers/version-archive.ts
|
|
23383
24382
|
var fs11 = __toESM(require("fs"));
|
|
23384
|
-
var
|
|
23385
|
-
var
|
|
24383
|
+
var path22 = __toESM(require("path"));
|
|
24384
|
+
var os20 = __toESM(require("os"));
|
|
23386
24385
|
var import_child_process10 = require("child_process");
|
|
23387
24386
|
var import_os3 = require("os");
|
|
23388
|
-
var ARCHIVE_PATH =
|
|
24387
|
+
var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
|
|
23389
24388
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
23390
24389
|
var VersionArchive = class {
|
|
23391
24390
|
history = {};
|
|
@@ -23432,7 +24431,7 @@ var VersionArchive = class {
|
|
|
23432
24431
|
}
|
|
23433
24432
|
save() {
|
|
23434
24433
|
try {
|
|
23435
|
-
fs11.mkdirSync(
|
|
24434
|
+
fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
|
|
23436
24435
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
23437
24436
|
} catch {
|
|
23438
24437
|
}
|
|
@@ -23488,8 +24487,8 @@ function getVersion(binary, versionCommand) {
|
|
|
23488
24487
|
function checkPathExists2(paths) {
|
|
23489
24488
|
for (const p of paths) {
|
|
23490
24489
|
if (p.includes("*")) {
|
|
23491
|
-
const home =
|
|
23492
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
24490
|
+
const home = os20.homedir();
|
|
24491
|
+
const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
|
|
23493
24492
|
if (fs11.existsSync(resolved)) return resolved;
|
|
23494
24493
|
} else {
|
|
23495
24494
|
if (fs11.existsSync(p)) return p;
|
|
@@ -23499,7 +24498,7 @@ function checkPathExists2(paths) {
|
|
|
23499
24498
|
}
|
|
23500
24499
|
function getMacAppVersion(appPath) {
|
|
23501
24500
|
if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
23502
|
-
const plistPath =
|
|
24501
|
+
const plistPath = path22.join(appPath, "Contents", "Info.plist");
|
|
23503
24502
|
if (!fs11.existsSync(plistPath)) return null;
|
|
23504
24503
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
23505
24504
|
return raw || null;
|
|
@@ -23525,7 +24524,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23525
24524
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
23526
24525
|
let resolvedBin = cliBin;
|
|
23527
24526
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
23528
|
-
const bundled =
|
|
24527
|
+
const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
23529
24528
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
23530
24529
|
}
|
|
23531
24530
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -23566,7 +24565,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23566
24565
|
// src/daemon/dev-server.ts
|
|
23567
24566
|
var http2 = __toESM(require("http"));
|
|
23568
24567
|
var fs15 = __toESM(require("fs"));
|
|
23569
|
-
var
|
|
24568
|
+
var path26 = __toESM(require("path"));
|
|
23570
24569
|
init_config();
|
|
23571
24570
|
|
|
23572
24571
|
// src/daemon/scaffold-template.ts
|
|
@@ -23917,7 +24916,7 @@ init_logger();
|
|
|
23917
24916
|
|
|
23918
24917
|
// src/daemon/dev-cdp-handlers.ts
|
|
23919
24918
|
var fs12 = __toESM(require("fs"));
|
|
23920
|
-
var
|
|
24919
|
+
var path23 = __toESM(require("path"));
|
|
23921
24920
|
init_logger();
|
|
23922
24921
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
23923
24922
|
const body = await ctx.readBody(req);
|
|
@@ -24096,17 +25095,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
24096
25095
|
return;
|
|
24097
25096
|
}
|
|
24098
25097
|
let scriptsPath = "";
|
|
24099
|
-
const directScripts =
|
|
25098
|
+
const directScripts = path23.join(dir, "scripts.js");
|
|
24100
25099
|
if (fs12.existsSync(directScripts)) {
|
|
24101
25100
|
scriptsPath = directScripts;
|
|
24102
25101
|
} else {
|
|
24103
|
-
const scriptsDir =
|
|
25102
|
+
const scriptsDir = path23.join(dir, "scripts");
|
|
24104
25103
|
if (fs12.existsSync(scriptsDir)) {
|
|
24105
25104
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
24106
|
-
return fs12.statSync(
|
|
25105
|
+
return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
|
|
24107
25106
|
}).sort().reverse();
|
|
24108
25107
|
for (const ver of versions) {
|
|
24109
|
-
const p =
|
|
25108
|
+
const p = path23.join(scriptsDir, ver, "scripts.js");
|
|
24110
25109
|
if (fs12.existsSync(p)) {
|
|
24111
25110
|
scriptsPath = p;
|
|
24112
25111
|
break;
|
|
@@ -24935,7 +25934,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
24935
25934
|
|
|
24936
25935
|
// src/daemon/dev-cli-debug.ts
|
|
24937
25936
|
var fs13 = __toESM(require("fs"));
|
|
24938
|
-
var
|
|
25937
|
+
var path24 = __toESM(require("path"));
|
|
24939
25938
|
function slugifyFixtureName(value) {
|
|
24940
25939
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24941
25940
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -24945,11 +25944,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
24945
25944
|
if (!providerDir) {
|
|
24946
25945
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
24947
25946
|
}
|
|
24948
|
-
return
|
|
25947
|
+
return path24.join(providerDir, "fixtures");
|
|
24949
25948
|
}
|
|
24950
25949
|
function readCliFixture(ctx, type, name) {
|
|
24951
25950
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
24952
|
-
const filePath =
|
|
25951
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
24953
25952
|
if (!fs13.existsSync(filePath)) {
|
|
24954
25953
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
24955
25954
|
}
|
|
@@ -25117,7 +26116,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
|
|
|
25117
26116
|
if (!adapter) return null;
|
|
25118
26117
|
return { target, instance, adapter };
|
|
25119
26118
|
}
|
|
25120
|
-
function
|
|
26119
|
+
function sleep2(ms) {
|
|
25121
26120
|
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
25122
26121
|
}
|
|
25123
26122
|
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
@@ -25134,7 +26133,7 @@ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
|
25134
26133
|
return bundle;
|
|
25135
26134
|
}
|
|
25136
26135
|
}
|
|
25137
|
-
await
|
|
26136
|
+
await sleep2(100);
|
|
25138
26137
|
}
|
|
25139
26138
|
return getCliTargetBundle(ctx, type, instanceId);
|
|
25140
26139
|
}
|
|
@@ -25190,7 +26189,7 @@ async function runCliExerciseInternal(ctx, body) {
|
|
|
25190
26189
|
const message = String(lastLaunchError.message || "");
|
|
25191
26190
|
const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
|
|
25192
26191
|
if (!retryable || attempt === 2) break;
|
|
25193
|
-
await
|
|
26192
|
+
await sleep2(1e3);
|
|
25194
26193
|
}
|
|
25195
26194
|
}
|
|
25196
26195
|
if (!launched) {
|
|
@@ -25253,16 +26252,16 @@ async function runCliExerciseInternal(ctx, body) {
|
|
|
25253
26252
|
const modal = debug?.activeModal || trace?.activeModal || null;
|
|
25254
26253
|
noteStatus(status);
|
|
25255
26254
|
if (resolveActiveModalIfNeeded(status, modal)) {
|
|
25256
|
-
await
|
|
26255
|
+
await sleep2(150);
|
|
25257
26256
|
continue;
|
|
25258
26257
|
}
|
|
25259
26258
|
const startupParseGate = !!debug?.startupParseGate;
|
|
25260
26259
|
if (status === "idle" && !startupParseGate) break;
|
|
25261
|
-
await
|
|
26260
|
+
await sleep2(150);
|
|
25262
26261
|
}
|
|
25263
26262
|
ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
|
|
25264
26263
|
while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
|
|
25265
|
-
await
|
|
26264
|
+
await sleep2(150);
|
|
25266
26265
|
bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
|
|
25267
26266
|
if (!bundle) {
|
|
25268
26267
|
throw new Error("CLI instance disappeared during exercise");
|
|
@@ -25716,7 +26715,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
25716
26715
|
},
|
|
25717
26716
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
25718
26717
|
};
|
|
25719
|
-
const filePath =
|
|
26718
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
25720
26719
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
25721
26720
|
ctx.json(res, 200, {
|
|
25722
26721
|
saved: true,
|
|
@@ -25740,7 +26739,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
25740
26739
|
return;
|
|
25741
26740
|
}
|
|
25742
26741
|
const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
25743
|
-
const fullPath =
|
|
26742
|
+
const fullPath = path24.join(fixtureDir, file);
|
|
25744
26743
|
try {
|
|
25745
26744
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
25746
26745
|
return {
|
|
@@ -25876,8 +26875,8 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
25876
26875
|
|
|
25877
26876
|
// src/daemon/dev-auto-implement.ts
|
|
25878
26877
|
var fs14 = __toESM(require("fs"));
|
|
25879
|
-
var
|
|
25880
|
-
var
|
|
26878
|
+
var path25 = __toESM(require("path"));
|
|
26879
|
+
var os21 = __toESM(require("os"));
|
|
25881
26880
|
function getAutoImplPid(ctx) {
|
|
25882
26881
|
const pid = ctx.autoImplProcess?.pid;
|
|
25883
26882
|
return typeof pid === "number" && pid > 0 ? pid : null;
|
|
@@ -25926,22 +26925,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
25926
26925
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
25927
26926
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
25928
26927
|
try {
|
|
25929
|
-
return fs14.statSync(
|
|
26928
|
+
return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
25930
26929
|
} catch {
|
|
25931
26930
|
return false;
|
|
25932
26931
|
}
|
|
25933
26932
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
25934
26933
|
if (versions.length === 0) return null;
|
|
25935
|
-
return
|
|
26934
|
+
return path25.join(scriptsDir, versions[0]);
|
|
25936
26935
|
}
|
|
25937
26936
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
25938
|
-
const canonicalUserDir =
|
|
25939
|
-
const desiredDir = requestedDir ?
|
|
25940
|
-
const upstreamRoot =
|
|
25941
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
26937
|
+
const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
26938
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
26939
|
+
const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
|
|
26940
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
25942
26941
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
25943
26942
|
}
|
|
25944
|
-
if (
|
|
26943
|
+
if (path25.basename(desiredDir) !== type) {
|
|
25945
26944
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
25946
26945
|
}
|
|
25947
26946
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -25949,11 +26948,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
25949
26948
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
25950
26949
|
}
|
|
25951
26950
|
if (!fs14.existsSync(desiredDir)) {
|
|
25952
|
-
fs14.mkdirSync(
|
|
26951
|
+
fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
25953
26952
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
25954
26953
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
25955
26954
|
}
|
|
25956
|
-
const providerJson =
|
|
26955
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
25957
26956
|
if (!fs14.existsSync(providerJson)) {
|
|
25958
26957
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
25959
26958
|
}
|
|
@@ -25964,13 +26963,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
25964
26963
|
const refDir = ctx.findProviderDir(referenceType);
|
|
25965
26964
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
25966
26965
|
const referenceScripts = {};
|
|
25967
|
-
const scriptsDir =
|
|
26966
|
+
const scriptsDir = path25.join(refDir, "scripts");
|
|
25968
26967
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
25969
26968
|
if (!latestDir) return referenceScripts;
|
|
25970
26969
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
25971
26970
|
if (!file.endsWith(".js")) continue;
|
|
25972
26971
|
try {
|
|
25973
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
26972
|
+
referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
|
|
25974
26973
|
} catch {
|
|
25975
26974
|
}
|
|
25976
26975
|
}
|
|
@@ -26078,9 +27077,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26078
27077
|
});
|
|
26079
27078
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
26080
27079
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
26081
|
-
const tmpDir =
|
|
27080
|
+
const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
|
|
26082
27081
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
26083
|
-
const promptFile =
|
|
27082
|
+
const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
26084
27083
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
26085
27084
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
26086
27085
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -26233,7 +27232,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26233
27232
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
26234
27233
|
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
26235
27234
|
let shellCmd;
|
|
26236
|
-
const isWin =
|
|
27235
|
+
const isWin = os21.platform() === "win32";
|
|
26237
27236
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
26238
27237
|
const promptMode = autoImpl?.promptMode ?? "stdin";
|
|
26239
27238
|
const extraArgs = autoImpl?.extraArgs ?? [];
|
|
@@ -26272,7 +27271,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26272
27271
|
try {
|
|
26273
27272
|
const pty = require("node-pty");
|
|
26274
27273
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
26275
|
-
const isWin2 =
|
|
27274
|
+
const isWin2 = os21.platform() === "win32";
|
|
26276
27275
|
child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
26277
27276
|
name: "xterm-256color",
|
|
26278
27277
|
cols: 120,
|
|
@@ -26512,7 +27511,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26512
27511
|
setMode: "set_mode.js"
|
|
26513
27512
|
};
|
|
26514
27513
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26515
|
-
const scriptsDir =
|
|
27514
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26516
27515
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26517
27516
|
if (latestScriptsDir) {
|
|
26518
27517
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26523,7 +27522,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26523
27522
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
26524
27523
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26525
27524
|
try {
|
|
26526
|
-
const content = fs14.readFileSync(
|
|
27525
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26527
27526
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26528
27527
|
lines.push("```javascript");
|
|
26529
27528
|
lines.push(content);
|
|
@@ -26540,7 +27539,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26540
27539
|
lines.push("");
|
|
26541
27540
|
for (const file of refFiles) {
|
|
26542
27541
|
try {
|
|
26543
|
-
const content = fs14.readFileSync(
|
|
27542
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26544
27543
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26545
27544
|
lines.push("```javascript");
|
|
26546
27545
|
lines.push(content);
|
|
@@ -26581,10 +27580,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26581
27580
|
lines.push("");
|
|
26582
27581
|
}
|
|
26583
27582
|
}
|
|
26584
|
-
const docsDir =
|
|
27583
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26585
27584
|
const loadGuide = (name) => {
|
|
26586
27585
|
try {
|
|
26587
|
-
const p =
|
|
27586
|
+
const p = path25.join(docsDir, name);
|
|
26588
27587
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26589
27588
|
} catch {
|
|
26590
27589
|
}
|
|
@@ -26821,7 +27820,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26821
27820
|
parseApproval: "parse_approval.js"
|
|
26822
27821
|
};
|
|
26823
27822
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26824
|
-
const scriptsDir =
|
|
27823
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26825
27824
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26826
27825
|
if (latestScriptsDir) {
|
|
26827
27826
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26833,7 +27832,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26833
27832
|
if (!file.endsWith(".js")) continue;
|
|
26834
27833
|
if (!targetFileNames.has(file)) continue;
|
|
26835
27834
|
try {
|
|
26836
|
-
const content = fs14.readFileSync(
|
|
27835
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26837
27836
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26838
27837
|
lines.push("```javascript");
|
|
26839
27838
|
lines.push(content);
|
|
@@ -26849,7 +27848,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26849
27848
|
lines.push("");
|
|
26850
27849
|
for (const file of refFiles) {
|
|
26851
27850
|
try {
|
|
26852
|
-
const content = fs14.readFileSync(
|
|
27851
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26853
27852
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26854
27853
|
lines.push("```javascript");
|
|
26855
27854
|
lines.push(content);
|
|
@@ -26882,10 +27881,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26882
27881
|
lines.push("");
|
|
26883
27882
|
}
|
|
26884
27883
|
}
|
|
26885
|
-
const docsDir =
|
|
27884
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26886
27885
|
const loadGuide = (name) => {
|
|
26887
27886
|
try {
|
|
26888
|
-
const p =
|
|
27887
|
+
const p = path25.join(docsDir, name);
|
|
26889
27888
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26890
27889
|
} catch {
|
|
26891
27890
|
}
|
|
@@ -27332,8 +28331,8 @@ var DevServer = class _DevServer {
|
|
|
27332
28331
|
}
|
|
27333
28332
|
getEndpointList() {
|
|
27334
28333
|
return this.routes.map((r) => {
|
|
27335
|
-
const
|
|
27336
|
-
return `${r.method.padEnd(5)} ${
|
|
28334
|
+
const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
28335
|
+
return `${r.method.padEnd(5)} ${path27}`;
|
|
27337
28336
|
});
|
|
27338
28337
|
}
|
|
27339
28338
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -27621,12 +28620,12 @@ var DevServer = class _DevServer {
|
|
|
27621
28620
|
// ─── DevConsole SPA ───
|
|
27622
28621
|
getConsoleDistDir() {
|
|
27623
28622
|
const candidates = [
|
|
27624
|
-
|
|
27625
|
-
|
|
27626
|
-
|
|
28623
|
+
path26.resolve(__dirname, "../../web-devconsole/dist"),
|
|
28624
|
+
path26.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
28625
|
+
path26.join(process.cwd(), "packages/web-devconsole/dist")
|
|
27627
28626
|
];
|
|
27628
28627
|
for (const dir of candidates) {
|
|
27629
|
-
if (fs15.existsSync(
|
|
28628
|
+
if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
|
|
27630
28629
|
}
|
|
27631
28630
|
return null;
|
|
27632
28631
|
}
|
|
@@ -27636,7 +28635,7 @@ var DevServer = class _DevServer {
|
|
|
27636
28635
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
27637
28636
|
return;
|
|
27638
28637
|
}
|
|
27639
|
-
const htmlPath =
|
|
28638
|
+
const htmlPath = path26.join(distDir, "index.html");
|
|
27640
28639
|
try {
|
|
27641
28640
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
27642
28641
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -27661,15 +28660,15 @@ var DevServer = class _DevServer {
|
|
|
27661
28660
|
this.json(res, 404, { error: "Not found" });
|
|
27662
28661
|
return;
|
|
27663
28662
|
}
|
|
27664
|
-
const safePath =
|
|
27665
|
-
const filePath =
|
|
28663
|
+
const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
|
|
28664
|
+
const filePath = path26.join(distDir, safePath);
|
|
27666
28665
|
if (!filePath.startsWith(distDir)) {
|
|
27667
28666
|
this.json(res, 403, { error: "Forbidden" });
|
|
27668
28667
|
return;
|
|
27669
28668
|
}
|
|
27670
28669
|
try {
|
|
27671
28670
|
const content = fs15.readFileSync(filePath);
|
|
27672
|
-
const ext =
|
|
28671
|
+
const ext = path26.extname(filePath);
|
|
27673
28672
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
27674
28673
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
27675
28674
|
res.end(content);
|
|
@@ -27782,9 +28781,9 @@ var DevServer = class _DevServer {
|
|
|
27782
28781
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27783
28782
|
if (entry.isDirectory()) {
|
|
27784
28783
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
27785
|
-
scan(
|
|
28784
|
+
scan(path26.join(d, entry.name), rel);
|
|
27786
28785
|
} else {
|
|
27787
|
-
const stat2 = fs15.statSync(
|
|
28786
|
+
const stat2 = fs15.statSync(path26.join(d, entry.name));
|
|
27788
28787
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
27789
28788
|
}
|
|
27790
28789
|
}
|
|
@@ -27807,7 +28806,7 @@ var DevServer = class _DevServer {
|
|
|
27807
28806
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27808
28807
|
return;
|
|
27809
28808
|
}
|
|
27810
|
-
const fullPath =
|
|
28809
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27811
28810
|
if (!fullPath.startsWith(dir)) {
|
|
27812
28811
|
this.json(res, 403, { error: "Forbidden" });
|
|
27813
28812
|
return;
|
|
@@ -27832,14 +28831,14 @@ var DevServer = class _DevServer {
|
|
|
27832
28831
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27833
28832
|
return;
|
|
27834
28833
|
}
|
|
27835
|
-
const fullPath =
|
|
28834
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27836
28835
|
if (!fullPath.startsWith(dir)) {
|
|
27837
28836
|
this.json(res, 403, { error: "Forbidden" });
|
|
27838
28837
|
return;
|
|
27839
28838
|
}
|
|
27840
28839
|
try {
|
|
27841
28840
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
27842
|
-
fs15.mkdirSync(
|
|
28841
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27843
28842
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27844
28843
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
27845
28844
|
this.providerLoader.reload();
|
|
@@ -27856,7 +28855,7 @@ var DevServer = class _DevServer {
|
|
|
27856
28855
|
return;
|
|
27857
28856
|
}
|
|
27858
28857
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
27859
|
-
const p =
|
|
28858
|
+
const p = path26.join(dir, name);
|
|
27860
28859
|
if (fs15.existsSync(p)) {
|
|
27861
28860
|
const source = fs15.readFileSync(p, "utf-8");
|
|
27862
28861
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -27877,8 +28876,8 @@ var DevServer = class _DevServer {
|
|
|
27877
28876
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
27878
28877
|
return;
|
|
27879
28878
|
}
|
|
27880
|
-
const target = fs15.existsSync(
|
|
27881
|
-
const targetPath =
|
|
28879
|
+
const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
28880
|
+
const targetPath = path26.join(dir, target);
|
|
27882
28881
|
try {
|
|
27883
28882
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
27884
28883
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -28025,7 +29024,7 @@ var DevServer = class _DevServer {
|
|
|
28025
29024
|
}
|
|
28026
29025
|
let targetDir;
|
|
28027
29026
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
28028
|
-
const jsonPath =
|
|
29027
|
+
const jsonPath = path26.join(targetDir, "provider.json");
|
|
28029
29028
|
if (fs15.existsSync(jsonPath)) {
|
|
28030
29029
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
28031
29030
|
return;
|
|
@@ -28037,8 +29036,8 @@ var DevServer = class _DevServer {
|
|
|
28037
29036
|
const createdFiles = ["provider.json"];
|
|
28038
29037
|
if (result.files) {
|
|
28039
29038
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
28040
|
-
const fullPath =
|
|
28041
|
-
fs15.mkdirSync(
|
|
29039
|
+
const fullPath = path26.join(targetDir, relPath);
|
|
29040
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
28042
29041
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
28043
29042
|
createdFiles.push(relPath);
|
|
28044
29043
|
}
|
|
@@ -28091,22 +29090,22 @@ var DevServer = class _DevServer {
|
|
|
28091
29090
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
28092
29091
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
28093
29092
|
try {
|
|
28094
|
-
return fs15.statSync(
|
|
29093
|
+
return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
|
|
28095
29094
|
} catch {
|
|
28096
29095
|
return false;
|
|
28097
29096
|
}
|
|
28098
29097
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
28099
29098
|
if (versions.length === 0) return null;
|
|
28100
|
-
return
|
|
29099
|
+
return path26.join(scriptsDir, versions[0]);
|
|
28101
29100
|
}
|
|
28102
29101
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
28103
|
-
const canonicalUserDir =
|
|
28104
|
-
const desiredDir = requestedDir ?
|
|
28105
|
-
const upstreamRoot =
|
|
28106
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
29102
|
+
const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
29103
|
+
const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
|
|
29104
|
+
const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
|
|
29105
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
|
|
28107
29106
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
28108
29107
|
}
|
|
28109
|
-
if (
|
|
29108
|
+
if (path26.basename(desiredDir) !== type) {
|
|
28110
29109
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
28111
29110
|
}
|
|
28112
29111
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -28114,11 +29113,11 @@ var DevServer = class _DevServer {
|
|
|
28114
29113
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
28115
29114
|
}
|
|
28116
29115
|
if (!fs15.existsSync(desiredDir)) {
|
|
28117
|
-
fs15.mkdirSync(
|
|
29116
|
+
fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
|
|
28118
29117
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
28119
29118
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
28120
29119
|
}
|
|
28121
|
-
const providerJson =
|
|
29120
|
+
const providerJson = path26.join(desiredDir, "provider.json");
|
|
28122
29121
|
if (!fs15.existsSync(providerJson)) {
|
|
28123
29122
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
28124
29123
|
}
|
|
@@ -28154,7 +29153,7 @@ var DevServer = class _DevServer {
|
|
|
28154
29153
|
setMode: "set_mode.js"
|
|
28155
29154
|
};
|
|
28156
29155
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28157
|
-
const scriptsDir =
|
|
29156
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28158
29157
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28159
29158
|
if (latestScriptsDir) {
|
|
28160
29159
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28165,7 +29164,7 @@ var DevServer = class _DevServer {
|
|
|
28165
29164
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
28166
29165
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
28167
29166
|
try {
|
|
28168
|
-
const content = fs15.readFileSync(
|
|
29167
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28169
29168
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28170
29169
|
lines.push("```javascript");
|
|
28171
29170
|
lines.push(content);
|
|
@@ -28182,7 +29181,7 @@ var DevServer = class _DevServer {
|
|
|
28182
29181
|
lines.push("");
|
|
28183
29182
|
for (const file of refFiles) {
|
|
28184
29183
|
try {
|
|
28185
|
-
const content = fs15.readFileSync(
|
|
29184
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28186
29185
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28187
29186
|
lines.push("```javascript");
|
|
28188
29187
|
lines.push(content);
|
|
@@ -28223,10 +29222,10 @@ var DevServer = class _DevServer {
|
|
|
28223
29222
|
lines.push("");
|
|
28224
29223
|
}
|
|
28225
29224
|
}
|
|
28226
|
-
const docsDir =
|
|
29225
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28227
29226
|
const loadGuide = (name) => {
|
|
28228
29227
|
try {
|
|
28229
|
-
const p =
|
|
29228
|
+
const p = path26.join(docsDir, name);
|
|
28230
29229
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28231
29230
|
} catch {
|
|
28232
29231
|
}
|
|
@@ -28400,7 +29399,7 @@ var DevServer = class _DevServer {
|
|
|
28400
29399
|
parseApproval: "parse_approval.js"
|
|
28401
29400
|
};
|
|
28402
29401
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28403
|
-
const scriptsDir =
|
|
29402
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28404
29403
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28405
29404
|
if (latestScriptsDir) {
|
|
28406
29405
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28412,7 +29411,7 @@ var DevServer = class _DevServer {
|
|
|
28412
29411
|
if (!file.endsWith(".js")) continue;
|
|
28413
29412
|
if (!targetFileNames.has(file)) continue;
|
|
28414
29413
|
try {
|
|
28415
|
-
const content = fs15.readFileSync(
|
|
29414
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28416
29415
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28417
29416
|
lines.push("```javascript");
|
|
28418
29417
|
lines.push(content);
|
|
@@ -28428,7 +29427,7 @@ var DevServer = class _DevServer {
|
|
|
28428
29427
|
lines.push("");
|
|
28429
29428
|
for (const file of refFiles) {
|
|
28430
29429
|
try {
|
|
28431
|
-
const content = fs15.readFileSync(
|
|
29430
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28432
29431
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28433
29432
|
lines.push("```javascript");
|
|
28434
29433
|
lines.push(content);
|
|
@@ -28461,10 +29460,10 @@ var DevServer = class _DevServer {
|
|
|
28461
29460
|
lines.push("");
|
|
28462
29461
|
}
|
|
28463
29462
|
}
|
|
28464
|
-
const docsDir =
|
|
29463
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28465
29464
|
const loadGuide = (name) => {
|
|
28466
29465
|
try {
|
|
28467
|
-
const p =
|
|
29466
|
+
const p = path26.join(docsDir, name);
|
|
28468
29467
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28469
29468
|
} catch {
|
|
28470
29469
|
}
|
|
@@ -29464,48 +30463,6 @@ var SessionRegistry = class {
|
|
|
29464
30463
|
// src/boot/daemon-lifecycle.ts
|
|
29465
30464
|
init_logger();
|
|
29466
30465
|
init_config();
|
|
29467
|
-
|
|
29468
|
-
// src/mesh/mesh-events.ts
|
|
29469
|
-
init_mesh_config();
|
|
29470
|
-
init_logger();
|
|
29471
|
-
function setupMeshEventForwarding(components) {
|
|
29472
|
-
components.instanceManager.onEvent((event) => {
|
|
29473
|
-
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
29474
|
-
const instanceId = event.instanceId;
|
|
29475
|
-
if (!instanceId) return;
|
|
29476
|
-
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
29477
|
-
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
29478
|
-
const state = sourceInstance.getState();
|
|
29479
|
-
const workspace = state.workspace;
|
|
29480
|
-
if (!workspace) return;
|
|
29481
|
-
const mesh = getMeshByRepo(workspace);
|
|
29482
|
-
if (!mesh) return;
|
|
29483
|
-
const allInstances = components.instanceManager.getByCategory("cli");
|
|
29484
|
-
const coordinatorInstances = allInstances.filter((inst) => {
|
|
29485
|
-
const instState = inst.getState();
|
|
29486
|
-
if (instState.settings?.meshCoordinatorFor !== mesh.id) return false;
|
|
29487
|
-
if (instState.instanceId === instanceId) return false;
|
|
29488
|
-
return true;
|
|
29489
|
-
});
|
|
29490
|
-
if (coordinatorInstances.length === 0) return;
|
|
29491
|
-
const targetNode = mesh.nodes.find((n) => n.workspace === workspace);
|
|
29492
|
-
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : `Agent at ${workspace}`;
|
|
29493
|
-
let messageText = "";
|
|
29494
|
-
if (event.event === "agent:generating_completed") {
|
|
29495
|
-
messageText = `[System] ${nodeLabel} has completed its task and is now idle. You may use mesh_read_chat to review its progress.`;
|
|
29496
|
-
} else if (event.event === "agent:waiting_approval") {
|
|
29497
|
-
messageText = `[System] ${nodeLabel} is waiting for approval to proceed. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
29498
|
-
}
|
|
29499
|
-
if (!messageText) return;
|
|
29500
|
-
for (const coord of coordinatorInstances) {
|
|
29501
|
-
const coordState = coord.getState();
|
|
29502
|
-
LOG.info("MeshEvents", `Forwarding event from ${workspace} to coordinator ${coordState.instanceId}`);
|
|
29503
|
-
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
29504
|
-
}
|
|
29505
|
-
});
|
|
29506
|
-
}
|
|
29507
|
-
|
|
29508
|
-
// src/boot/daemon-lifecycle.ts
|
|
29509
30466
|
async function initDaemonComponents(config) {
|
|
29510
30467
|
installGlobalInterceptor();
|
|
29511
30468
|
const appConfig = loadConfig();
|
|
@@ -29812,6 +30769,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29812
30769
|
createGitWorkspaceMonitor,
|
|
29813
30770
|
createInteractionId,
|
|
29814
30771
|
createMesh,
|
|
30772
|
+
createWorktree,
|
|
29815
30773
|
deleteMesh,
|
|
29816
30774
|
detectAllVersions,
|
|
29817
30775
|
detectCLIs,
|
|
@@ -29864,6 +30822,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29864
30822
|
launchWithCdp,
|
|
29865
30823
|
listHostedCliRuntimes,
|
|
29866
30824
|
listMeshes,
|
|
30825
|
+
listWorktrees,
|
|
29867
30826
|
loadConfig,
|
|
29868
30827
|
loadState,
|
|
29869
30828
|
logCommand,
|
|
@@ -29883,6 +30842,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29883
30842
|
normalizeSessionModalFields,
|
|
29884
30843
|
parsePorcelainV2Status,
|
|
29885
30844
|
parseProviderSourceConfigUpdate,
|
|
30845
|
+
parseWorktreeListOutput,
|
|
29886
30846
|
partitionSessionHostDiagnosticsSessions,
|
|
29887
30847
|
partitionSessionHostRecords,
|
|
29888
30848
|
prepareSessionChatTailUpdate,
|
|
@@ -29892,6 +30852,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29892
30852
|
recordDebugTrace,
|
|
29893
30853
|
registerExtensionProviders,
|
|
29894
30854
|
removeNode,
|
|
30855
|
+
removeWorktree,
|
|
29895
30856
|
resetConfig,
|
|
29896
30857
|
resetDebugRuntimeConfig,
|
|
29897
30858
|
resetState,
|
|
@@ -29901,6 +30862,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29901
30862
|
resolveGitRepository,
|
|
29902
30863
|
resolveSessionHostAppName,
|
|
29903
30864
|
resolveSessionHostAppNameResolution,
|
|
30865
|
+
resolveWorktreePath,
|
|
29904
30866
|
runAsyncBatch,
|
|
29905
30867
|
runGit,
|
|
29906
30868
|
saveConfig,
|