@adhdev/daemon-core 0.9.76-rc.4 → 0.9.76-rc.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -1
- package/dist/cli-adapters/provider-cli-runtime.d.ts +1 -0
- package/dist/commands/cli-manager.d.ts +17 -4
- package/dist/commands/mesh-coordinator.d.ts +2 -0
- package/dist/commands/router.d.ts +11 -0
- package/dist/config/mesh-config.d.ts +3 -0
- package/dist/git/git-types.d.ts +1 -1
- package/dist/git/git-worktree.d.ts +64 -0
- package/dist/git/index.d.ts +2 -0
- package/dist/index.js +1318 -426
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1345 -457
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +1 -0
- package/dist/mesh/mesh-events.d.ts +9 -0
- package/dist/providers/chat-message-normalization.d.ts +11 -0
- package/dist/providers/cli-provider-instance.d.ts +3 -0
- package/dist/providers/provider-instance-manager.d.ts +1 -0
- package/dist/providers/provider-instance.d.ts +2 -0
- package/dist/repo-mesh-types.d.ts +13 -0
- package/dist/shared-types.d.ts +22 -1
- package/package.json +3 -4
- package/src/cli-adapters/provider-cli-adapter.ts +13 -6
- package/src/cli-adapters/provider-cli-runtime.ts +3 -2
- package/src/commands/chat-commands.ts +76 -5
- package/src/commands/cli-manager.ts +78 -5
- package/src/commands/handler.ts +13 -4
- package/src/commands/mesh-coordinator.ts +149 -6
- package/src/commands/router.d.ts +1 -0
- package/src/commands/router.ts +505 -34
- package/src/config/mesh-config.ts +23 -2
- package/src/git/git-commands.ts +5 -1
- package/src/git/git-types.ts +1 -0
- package/src/git/git-worktree.ts +214 -0
- package/src/git/index.ts +14 -0
- package/src/mesh/coordinator-prompt.ts +25 -10
- package/src/mesh/mesh-events.ts +109 -43
- package/src/providers/chat-message-normalization.ts +54 -0
- package/src/providers/cli-provider-instance.d.ts +2 -0
- package/src/providers/cli-provider-instance.ts +55 -7
- package/src/providers/provider-instance-manager.ts +20 -1
- package/src/providers/provider-instance.ts +2 -0
- package/src/repo-mesh-types.ts +15 -0
- package/src/shared-types.ts +24 -1
- package/src/status/builders.ts +17 -12
- package/src/status/reporter.ts +6 -0
package/dist/index.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}`);
|
|
@@ -3727,6 +3886,7 @@ __export(index_exports, {
|
|
|
3727
3886
|
createGitWorkspaceMonitor: () => createGitWorkspaceMonitor,
|
|
3728
3887
|
createInteractionId: () => createInteractionId,
|
|
3729
3888
|
createMesh: () => createMesh,
|
|
3889
|
+
createWorktree: () => createWorktree,
|
|
3730
3890
|
deleteMesh: () => deleteMesh,
|
|
3731
3891
|
detectAllVersions: () => detectAllVersions,
|
|
3732
3892
|
detectCLIs: () => detectCLIs,
|
|
@@ -3779,6 +3939,7 @@ __export(index_exports, {
|
|
|
3779
3939
|
launchWithCdp: () => launchWithCdp,
|
|
3780
3940
|
listHostedCliRuntimes: () => listHostedCliRuntimes,
|
|
3781
3941
|
listMeshes: () => listMeshes,
|
|
3942
|
+
listWorktrees: () => listWorktrees,
|
|
3782
3943
|
loadConfig: () => loadConfig,
|
|
3783
3944
|
loadState: () => loadState,
|
|
3784
3945
|
logCommand: () => logCommand,
|
|
@@ -3798,6 +3959,7 @@ __export(index_exports, {
|
|
|
3798
3959
|
normalizeSessionModalFields: () => normalizeSessionModalFields,
|
|
3799
3960
|
parsePorcelainV2Status: () => parsePorcelainV2Status,
|
|
3800
3961
|
parseProviderSourceConfigUpdate: () => parseProviderSourceConfigUpdate,
|
|
3962
|
+
parseWorktreeListOutput: () => parseWorktreeListOutput,
|
|
3801
3963
|
partitionSessionHostDiagnosticsSessions: () => partitionSessionHostDiagnosticsSessions,
|
|
3802
3964
|
partitionSessionHostRecords: () => partitionSessionHostRecords,
|
|
3803
3965
|
prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
|
|
@@ -3807,6 +3969,7 @@ __export(index_exports, {
|
|
|
3807
3969
|
recordDebugTrace: () => recordDebugTrace,
|
|
3808
3970
|
registerExtensionProviders: () => registerExtensionProviders,
|
|
3809
3971
|
removeNode: () => removeNode,
|
|
3972
|
+
removeWorktree: () => removeWorktree,
|
|
3810
3973
|
resetConfig: () => resetConfig,
|
|
3811
3974
|
resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
|
|
3812
3975
|
resetState: () => resetState,
|
|
@@ -3816,6 +3979,7 @@ __export(index_exports, {
|
|
|
3816
3979
|
resolveGitRepository: () => resolveGitRepository,
|
|
3817
3980
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
3818
3981
|
resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
|
|
3982
|
+
resolveWorktreePath: () => resolveWorktreePath,
|
|
3819
3983
|
runAsyncBatch: () => runAsyncBatch,
|
|
3820
3984
|
runGit: () => runGit,
|
|
3821
3985
|
saveConfig: () => saveConfig,
|
|
@@ -4739,6 +4903,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
|
4739
4903
|
"dirty_index_required",
|
|
4740
4904
|
"conflict",
|
|
4741
4905
|
"invalid_args",
|
|
4906
|
+
"nothing_to_commit",
|
|
4742
4907
|
"git_command_failed"
|
|
4743
4908
|
]);
|
|
4744
4909
|
function failure(reason, error) {
|
|
@@ -4983,7 +5148,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
|
4983
5148
|
} catch (err) {
|
|
4984
5149
|
const output = (err?.stdout || "") + (err?.stderr || "");
|
|
4985
5150
|
if (/nothing to commit/i.test(output)) {
|
|
4986
|
-
throw new GitCommandError("
|
|
5151
|
+
throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
|
|
5152
|
+
stdout: err?.stdout,
|
|
5153
|
+
stderr: err?.stderr
|
|
5154
|
+
});
|
|
4987
5155
|
}
|
|
4988
5156
|
throw err;
|
|
4989
5157
|
}
|
|
@@ -5175,20 +5343,23 @@ var TurnSnapshotTracker = class {
|
|
|
5175
5343
|
}
|
|
5176
5344
|
};
|
|
5177
5345
|
|
|
5346
|
+
// src/git/index.ts
|
|
5347
|
+
init_git_worktree();
|
|
5348
|
+
|
|
5178
5349
|
// src/index.ts
|
|
5179
5350
|
init_config();
|
|
5180
5351
|
|
|
5181
5352
|
// src/config/workspaces.ts
|
|
5182
5353
|
var fs = __toESM(require("fs"));
|
|
5183
5354
|
var os = __toESM(require("os"));
|
|
5184
|
-
var
|
|
5355
|
+
var path5 = __toESM(require("path"));
|
|
5185
5356
|
var import_crypto2 = require("crypto");
|
|
5186
5357
|
var MAX_WORKSPACES = 50;
|
|
5187
5358
|
function expandPath(p) {
|
|
5188
5359
|
const t = (p || "").trim();
|
|
5189
5360
|
if (!t) return "";
|
|
5190
|
-
if (t.startsWith("~")) return
|
|
5191
|
-
return
|
|
5361
|
+
if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5362
|
+
return path5.resolve(t);
|
|
5192
5363
|
}
|
|
5193
5364
|
function validateWorkspacePath(absPath) {
|
|
5194
5365
|
try {
|
|
@@ -5202,7 +5373,7 @@ function validateWorkspacePath(absPath) {
|
|
|
5202
5373
|
}
|
|
5203
5374
|
}
|
|
5204
5375
|
function defaultWorkspaceLabel(absPath) {
|
|
5205
|
-
const base =
|
|
5376
|
+
const base = path5.basename(absPath) || absPath;
|
|
5206
5377
|
return base;
|
|
5207
5378
|
}
|
|
5208
5379
|
function getDefaultWorkspacePath(config) {
|
|
@@ -5293,9 +5464,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
5293
5464
|
return getDefaultWorkspacePath(config) || void 0;
|
|
5294
5465
|
}
|
|
5295
5466
|
function findWorkspaceByPath(config, rawPath) {
|
|
5296
|
-
const abs =
|
|
5467
|
+
const abs = path5.resolve(expandPath(rawPath));
|
|
5297
5468
|
if (!abs) return void 0;
|
|
5298
|
-
return (config.workspaces || []).find((w) =>
|
|
5469
|
+
return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
|
|
5299
5470
|
}
|
|
5300
5471
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
5301
5472
|
const abs = expandPath(rawPath);
|
|
@@ -5311,7 +5482,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
5311
5482
|
const v = validateWorkspacePath(abs);
|
|
5312
5483
|
if (!v.ok) return { error: v.error };
|
|
5313
5484
|
const list = [...config.workspaces || []];
|
|
5314
|
-
if (list.some((w) =>
|
|
5485
|
+
if (list.some((w) => path5.resolve(w.path) === abs)) {
|
|
5315
5486
|
return { error: "Workspace already in list" };
|
|
5316
5487
|
}
|
|
5317
5488
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -5345,7 +5516,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
5345
5516
|
}
|
|
5346
5517
|
|
|
5347
5518
|
// src/config/recent-activity.ts
|
|
5348
|
-
var
|
|
5519
|
+
var path6 = __toESM(require("path"));
|
|
5349
5520
|
|
|
5350
5521
|
// src/providers/summary-metadata.ts
|
|
5351
5522
|
function normalizeSummaryItem(item) {
|
|
@@ -5414,9 +5585,9 @@ var MAX_ACTIVITY = 30;
|
|
|
5414
5585
|
function normalizeWorkspace(workspace) {
|
|
5415
5586
|
if (!workspace) return "";
|
|
5416
5587
|
try {
|
|
5417
|
-
return
|
|
5588
|
+
return path6.resolve(expandPath(workspace));
|
|
5418
5589
|
} catch {
|
|
5419
|
-
return
|
|
5590
|
+
return path6.resolve(workspace);
|
|
5420
5591
|
}
|
|
5421
5592
|
}
|
|
5422
5593
|
function buildRecentActivityKey(entry) {
|
|
@@ -5584,14 +5755,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5584
5755
|
}
|
|
5585
5756
|
|
|
5586
5757
|
// src/config/saved-sessions.ts
|
|
5587
|
-
var
|
|
5758
|
+
var path7 = __toESM(require("path"));
|
|
5588
5759
|
var MAX_SAVED_SESSIONS = 500;
|
|
5589
5760
|
function normalizeWorkspace2(workspace) {
|
|
5590
5761
|
if (!workspace) return "";
|
|
5591
5762
|
try {
|
|
5592
|
-
return
|
|
5763
|
+
return path7.resolve(expandPath(workspace));
|
|
5593
5764
|
} catch {
|
|
5594
|
-
return
|
|
5765
|
+
return path7.resolve(workspace);
|
|
5595
5766
|
}
|
|
5596
5767
|
}
|
|
5597
5768
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5770,7 +5941,7 @@ function resetState() {
|
|
|
5770
5941
|
var import_child_process = require("child_process");
|
|
5771
5942
|
var import_fs4 = require("fs");
|
|
5772
5943
|
var import_os2 = require("os");
|
|
5773
|
-
var
|
|
5944
|
+
var path8 = __toESM(require("path"));
|
|
5774
5945
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5775
5946
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5776
5947
|
function registerIDEDefinition(def) {
|
|
@@ -5789,9 +5960,9 @@ function getMergedDefinitions() {
|
|
|
5789
5960
|
function findCliCommand(command) {
|
|
5790
5961
|
const trimmed = String(command || "").trim();
|
|
5791
5962
|
if (!trimmed) return null;
|
|
5792
|
-
if (
|
|
5793
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5794
|
-
const resolved =
|
|
5963
|
+
if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
5964
|
+
const candidate = trimmed.startsWith("~") ? path8.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
|
|
5965
|
+
const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
|
|
5795
5966
|
return (0, import_fs4.existsSync)(resolved) ? resolved : null;
|
|
5796
5967
|
}
|
|
5797
5968
|
try {
|
|
@@ -5819,7 +5990,7 @@ function getIdeVersion(cliCommand) {
|
|
|
5819
5990
|
function checkPathExists(paths) {
|
|
5820
5991
|
const home = (0, import_os2.homedir)();
|
|
5821
5992
|
for (const p of paths) {
|
|
5822
|
-
const normalized = p.startsWith("~") ?
|
|
5993
|
+
const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
|
|
5823
5994
|
if (normalized.includes("*")) {
|
|
5824
5995
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5825
5996
|
const resolved = normalized.replace("*", username);
|
|
@@ -5831,19 +6002,19 @@ function checkPathExists(paths) {
|
|
|
5831
6002
|
return null;
|
|
5832
6003
|
}
|
|
5833
6004
|
async function detectIDEs(providerLoader) {
|
|
5834
|
-
const
|
|
6005
|
+
const os22 = (0, import_os2.platform)();
|
|
5835
6006
|
const results = [];
|
|
5836
6007
|
for (const def of getMergedDefinitions()) {
|
|
5837
6008
|
const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
|
|
5838
|
-
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[
|
|
6009
|
+
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
|
|
5839
6010
|
let resolvedCli = cliPath;
|
|
5840
|
-
if (!resolvedCli && appPath &&
|
|
6011
|
+
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
5841
6012
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
5842
6013
|
if ((0, import_fs4.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
5843
6014
|
}
|
|
5844
|
-
if (!resolvedCli && appPath &&
|
|
5845
|
-
const { dirname:
|
|
5846
|
-
const appDir =
|
|
6015
|
+
if (!resolvedCli && appPath && os22 === "win32") {
|
|
6016
|
+
const { dirname: dirname9 } = await import("path");
|
|
6017
|
+
const appDir = dirname9(appPath);
|
|
5847
6018
|
const candidates = [
|
|
5848
6019
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
5849
6020
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -5858,7 +6029,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5858
6029
|
}
|
|
5859
6030
|
}
|
|
5860
6031
|
}
|
|
5861
|
-
const installed =
|
|
6032
|
+
const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
|
|
5862
6033
|
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
5863
6034
|
results.push({
|
|
5864
6035
|
id: def.id,
|
|
@@ -5877,7 +6048,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5877
6048
|
// src/detection/cli-detector.ts
|
|
5878
6049
|
var import_child_process2 = require("child_process");
|
|
5879
6050
|
var os2 = __toESM(require("os"));
|
|
5880
|
-
var
|
|
6051
|
+
var path9 = __toESM(require("path"));
|
|
5881
6052
|
var import_fs5 = require("fs");
|
|
5882
6053
|
function parseVersion(raw) {
|
|
5883
6054
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
@@ -5890,18 +6061,18 @@ function shellQuote(value) {
|
|
|
5890
6061
|
function expandHome(value) {
|
|
5891
6062
|
const trimmed = value.trim();
|
|
5892
6063
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5893
|
-
return
|
|
6064
|
+
return path9.join(os2.homedir(), trimmed.slice(1));
|
|
5894
6065
|
}
|
|
5895
6066
|
function isExplicitCommandPath(command) {
|
|
5896
6067
|
const trimmed = command.trim();
|
|
5897
|
-
return
|
|
6068
|
+
return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5898
6069
|
}
|
|
5899
6070
|
function resolveCommandPath(command) {
|
|
5900
6071
|
const trimmed = command.trim();
|
|
5901
6072
|
if (!trimmed) return null;
|
|
5902
6073
|
if (isExplicitCommandPath(trimmed)) {
|
|
5903
6074
|
const expanded = expandHome(trimmed);
|
|
5904
|
-
const candidate =
|
|
6075
|
+
const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
|
|
5905
6076
|
return (0, import_fs5.existsSync)(candidate) ? candidate : null;
|
|
5906
6077
|
}
|
|
5907
6078
|
return null;
|
|
@@ -8170,9 +8341,9 @@ ${cleanBody}`;
|
|
|
8170
8341
|
|
|
8171
8342
|
// src/config/chat-history.ts
|
|
8172
8343
|
var fs3 = __toESM(require("fs"));
|
|
8173
|
-
var
|
|
8344
|
+
var path11 = __toESM(require("path"));
|
|
8174
8345
|
var os5 = __toESM(require("os"));
|
|
8175
|
-
var HISTORY_DIR =
|
|
8346
|
+
var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
|
|
8176
8347
|
var RETAIN_DAYS = 30;
|
|
8177
8348
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
8178
8349
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -8335,7 +8506,7 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
8335
8506
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
8336
8507
|
return new Map(files.map((file) => {
|
|
8337
8508
|
try {
|
|
8338
|
-
const stat2 = fs3.statSync(
|
|
8509
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8339
8510
|
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
8340
8511
|
} catch {
|
|
8341
8512
|
return [file, `${file}:missing`];
|
|
@@ -8346,7 +8517,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
8346
8517
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
8347
8518
|
}
|
|
8348
8519
|
function getSavedHistoryIndexFilePath(dir) {
|
|
8349
|
-
return
|
|
8520
|
+
return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
8350
8521
|
}
|
|
8351
8522
|
function getSavedHistoryIndexLockPath(dir) {
|
|
8352
8523
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -8448,7 +8619,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
8448
8619
|
}
|
|
8449
8620
|
for (const file of Array.from(currentEntries.keys())) {
|
|
8450
8621
|
if (incomingFiles.has(file)) continue;
|
|
8451
|
-
if (!fs3.existsSync(
|
|
8622
|
+
if (!fs3.existsSync(path11.join(dir, file))) {
|
|
8452
8623
|
currentEntries.delete(file);
|
|
8453
8624
|
}
|
|
8454
8625
|
}
|
|
@@ -8474,7 +8645,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8474
8645
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8475
8646
|
const files = listHistoryFiles(dir);
|
|
8476
8647
|
for (const file of files) {
|
|
8477
|
-
const stat2 = fs3.statSync(
|
|
8648
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8478
8649
|
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
8479
8650
|
}
|
|
8480
8651
|
return false;
|
|
@@ -8484,14 +8655,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8484
8655
|
}
|
|
8485
8656
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
8486
8657
|
try {
|
|
8487
|
-
const stat2 = fs3.statSync(
|
|
8658
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8488
8659
|
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
8489
8660
|
} catch {
|
|
8490
8661
|
return `${file}:missing`;
|
|
8491
8662
|
}
|
|
8492
8663
|
}
|
|
8493
8664
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
8494
|
-
const filePath =
|
|
8665
|
+
const filePath = path11.join(dir, file);
|
|
8495
8666
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
8496
8667
|
const currentEntry = entries.get(file) || null;
|
|
8497
8668
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -8564,7 +8735,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
8564
8735
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
8565
8736
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
8566
8737
|
if (!historySessionId) return null;
|
|
8567
|
-
const filePath =
|
|
8738
|
+
const filePath = path11.join(dir, file);
|
|
8568
8739
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8569
8740
|
const lines = content.split("\n").filter(Boolean);
|
|
8570
8741
|
let messageCount = 0;
|
|
@@ -8651,7 +8822,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
8651
8822
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
8652
8823
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
8653
8824
|
for (const file of files.slice().sort()) {
|
|
8654
|
-
const filePath =
|
|
8825
|
+
const filePath = path11.join(dir, file);
|
|
8655
8826
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
8656
8827
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
8657
8828
|
const persisted = persistedEntries.get(file);
|
|
@@ -8771,12 +8942,12 @@ var ChatHistoryWriter = class {
|
|
|
8771
8942
|
});
|
|
8772
8943
|
}
|
|
8773
8944
|
if (newMessages.length === 0) return;
|
|
8774
|
-
const dir =
|
|
8945
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8775
8946
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8776
8947
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8777
8948
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
8778
8949
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
8779
|
-
const filePath =
|
|
8950
|
+
const filePath = path11.join(dir, fileName);
|
|
8780
8951
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
8781
8952
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
8782
8953
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -8867,11 +9038,11 @@ var ChatHistoryWriter = class {
|
|
|
8867
9038
|
const ws = String(workspace || "").trim();
|
|
8868
9039
|
if (!id || !ws) return;
|
|
8869
9040
|
try {
|
|
8870
|
-
const dir =
|
|
9041
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8871
9042
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8872
9043
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8873
9044
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
8874
|
-
const filePath =
|
|
9045
|
+
const filePath = path11.join(dir, fileName);
|
|
8875
9046
|
const record = {
|
|
8876
9047
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8877
9048
|
receivedAt: Date.now(),
|
|
@@ -8917,14 +9088,14 @@ var ChatHistoryWriter = class {
|
|
|
8917
9088
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8918
9089
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8919
9090
|
}
|
|
8920
|
-
const dir =
|
|
9091
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8921
9092
|
if (!fs3.existsSync(dir)) return;
|
|
8922
9093
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8923
9094
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8924
9095
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8925
9096
|
for (const file of files) {
|
|
8926
|
-
const sourcePath =
|
|
8927
|
-
const targetPath =
|
|
9097
|
+
const sourcePath = path11.join(dir, file);
|
|
9098
|
+
const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8928
9099
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8929
9100
|
const rewritten = sourceLines.map((line) => {
|
|
8930
9101
|
try {
|
|
@@ -8958,13 +9129,13 @@ var ChatHistoryWriter = class {
|
|
|
8958
9129
|
const sessionId = String(historySessionId || "").trim();
|
|
8959
9130
|
if (!sessionId) return;
|
|
8960
9131
|
try {
|
|
8961
|
-
const dir =
|
|
9132
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8962
9133
|
if (!fs3.existsSync(dir)) return;
|
|
8963
9134
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8964
9135
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8965
9136
|
const seen = /* @__PURE__ */ new Set();
|
|
8966
9137
|
for (const file of files) {
|
|
8967
|
-
const filePath =
|
|
9138
|
+
const filePath = path11.join(dir, file);
|
|
8968
9139
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8969
9140
|
const next = [];
|
|
8970
9141
|
for (const line of lines) {
|
|
@@ -9018,11 +9189,11 @@ var ChatHistoryWriter = class {
|
|
|
9018
9189
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
9019
9190
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
9020
9191
|
for (const dir of agentDirs) {
|
|
9021
|
-
const dirPath =
|
|
9192
|
+
const dirPath = path11.join(HISTORY_DIR, dir.name);
|
|
9022
9193
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
9023
9194
|
let removedAny = false;
|
|
9024
9195
|
for (const file of files) {
|
|
9025
|
-
const filePath =
|
|
9196
|
+
const filePath = path11.join(dirPath, file);
|
|
9026
9197
|
const stat2 = fs3.statSync(filePath);
|
|
9027
9198
|
if (stat2.mtimeMs < cutoff) {
|
|
9028
9199
|
fs3.unlinkSync(filePath);
|
|
@@ -9072,13 +9243,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
9072
9243
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
9073
9244
|
try {
|
|
9074
9245
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9075
|
-
const dir =
|
|
9246
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
9076
9247
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
9077
9248
|
const files = listHistoryFiles(dir, historySessionId);
|
|
9078
9249
|
const allMessages = [];
|
|
9079
9250
|
const seen = /* @__PURE__ */ new Set();
|
|
9080
9251
|
for (const file of files) {
|
|
9081
|
-
const filePath =
|
|
9252
|
+
const filePath = path11.join(dir, file);
|
|
9082
9253
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
9083
9254
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
9084
9255
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -9102,7 +9273,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
9102
9273
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
9103
9274
|
try {
|
|
9104
9275
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9105
|
-
const dir =
|
|
9276
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
9106
9277
|
if (!fs3.existsSync(dir)) {
|
|
9107
9278
|
savedHistorySessionCache.delete(sanitized);
|
|
9108
9279
|
return { sessions: [], hasMore: false };
|
|
@@ -9163,11 +9334,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
9163
9334
|
}
|
|
9164
9335
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
9165
9336
|
try {
|
|
9166
|
-
const dir =
|
|
9337
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
9167
9338
|
if (!fs3.existsSync(dir)) return null;
|
|
9168
9339
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
9169
9340
|
for (const file of files) {
|
|
9170
|
-
const lines = fs3.readFileSync(
|
|
9341
|
+
const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
9171
9342
|
for (const line of lines) {
|
|
9172
9343
|
try {
|
|
9173
9344
|
const parsed = JSON.parse(line);
|
|
@@ -9187,16 +9358,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
9187
9358
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
9188
9359
|
if (records.length === 0) return false;
|
|
9189
9360
|
try {
|
|
9190
|
-
const dir =
|
|
9361
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
9191
9362
|
fs3.mkdirSync(dir, { recursive: true });
|
|
9192
9363
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
9193
9364
|
for (const file of fs3.readdirSync(dir)) {
|
|
9194
9365
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
9195
|
-
fs3.unlinkSync(
|
|
9366
|
+
fs3.unlinkSync(path11.join(dir, file));
|
|
9196
9367
|
}
|
|
9197
9368
|
}
|
|
9198
9369
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
9199
|
-
const filePath =
|
|
9370
|
+
const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
9200
9371
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
9201
9372
|
`, "utf-8");
|
|
9202
9373
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -11191,6 +11362,14 @@ function getActiveChatOptions(profile) {
|
|
|
11191
11362
|
if (profile === "full") return {};
|
|
11192
11363
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
11193
11364
|
}
|
|
11365
|
+
function resolveSessionStatus(activeChat, providerStatus) {
|
|
11366
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
11367
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
11368
|
+
if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
|
|
11369
|
+
if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
|
|
11370
|
+
if (topLevelStatus !== "idle") return topLevelStatus;
|
|
11371
|
+
return chatStatus;
|
|
11372
|
+
}
|
|
11194
11373
|
function shouldIncludeSessionControls(profile) {
|
|
11195
11374
|
return profile !== "live";
|
|
11196
11375
|
}
|
|
@@ -11269,9 +11448,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11269
11448
|
providerName: state.name,
|
|
11270
11449
|
kind: "workspace",
|
|
11271
11450
|
transport: "cdp-page",
|
|
11272
|
-
status:
|
|
11273
|
-
activeModal: activeChat?.activeModal || null
|
|
11274
|
-
}),
|
|
11451
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11275
11452
|
title,
|
|
11276
11453
|
workspace,
|
|
11277
11454
|
...git && { git },
|
|
@@ -11306,9 +11483,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11306
11483
|
providerSessionId: ext.providerSessionId,
|
|
11307
11484
|
kind: "agent",
|
|
11308
11485
|
transport: "cdp-webview",
|
|
11309
|
-
status:
|
|
11310
|
-
activeModal: activeChat?.activeModal || null
|
|
11311
|
-
}),
|
|
11486
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
11312
11487
|
title: activeChat?.title || ext.name,
|
|
11313
11488
|
workspace,
|
|
11314
11489
|
...git && { git },
|
|
@@ -11358,9 +11533,7 @@ function buildCliSession(state, options) {
|
|
|
11358
11533
|
providerSessionId: state.providerSessionId,
|
|
11359
11534
|
kind: "agent",
|
|
11360
11535
|
transport: "pty",
|
|
11361
|
-
status:
|
|
11362
|
-
activeModal: activeChat?.activeModal || null
|
|
11363
|
-
}),
|
|
11536
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11364
11537
|
title: activeChat?.title || state.name,
|
|
11365
11538
|
workspace,
|
|
11366
11539
|
...git && { git },
|
|
@@ -11408,9 +11581,7 @@ function buildAcpSession(state, options) {
|
|
|
11408
11581
|
providerName: state.name,
|
|
11409
11582
|
kind: "agent",
|
|
11410
11583
|
transport: "acp",
|
|
11411
|
-
status:
|
|
11412
|
-
activeModal: activeChat?.activeModal || null
|
|
11413
|
-
}),
|
|
11584
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11414
11585
|
title: activeChat?.title || state.name,
|
|
11415
11586
|
workspace,
|
|
11416
11587
|
...git && { git },
|
|
@@ -11533,7 +11704,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
11533
11704
|
// src/commands/chat-commands.ts
|
|
11534
11705
|
var fs4 = __toESM(require("fs"));
|
|
11535
11706
|
var os6 = __toESM(require("os"));
|
|
11536
|
-
var
|
|
11707
|
+
var path12 = __toESM(require("path"));
|
|
11537
11708
|
var import_node_crypto = require("crypto");
|
|
11538
11709
|
|
|
11539
11710
|
// src/providers/provider-input-support.ts
|
|
@@ -11896,6 +12067,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
11896
12067
|
return raw;
|
|
11897
12068
|
}
|
|
11898
12069
|
}
|
|
12070
|
+
function isGeneratingLikeStatus(status) {
|
|
12071
|
+
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
12072
|
+
}
|
|
12073
|
+
function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
12074
|
+
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
12075
|
+
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
12076
|
+
const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
|
|
12077
|
+
if (adapterRawStatus !== "idle") return false;
|
|
12078
|
+
if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
|
|
12079
|
+
return true;
|
|
12080
|
+
}
|
|
12081
|
+
function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
12082
|
+
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
12083
|
+
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
12084
|
+
}
|
|
12085
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
12086
|
+
if (status !== "idle") return messages;
|
|
12087
|
+
return messages.map((message) => {
|
|
12088
|
+
const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
12089
|
+
const hasStreamingMeta = meta?.streaming === true;
|
|
12090
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
12091
|
+
return {
|
|
12092
|
+
...message,
|
|
12093
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
12094
|
+
...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
|
|
12095
|
+
};
|
|
12096
|
+
});
|
|
12097
|
+
}
|
|
11899
12098
|
function buildReadChatCommandResult(payload, args) {
|
|
11900
12099
|
let validatedPayload;
|
|
11901
12100
|
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
@@ -12044,7 +12243,7 @@ function buildDebugBundleText(bundle) {
|
|
|
12044
12243
|
}
|
|
12045
12244
|
function getChatDebugBundleDir() {
|
|
12046
12245
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
12047
|
-
return override ||
|
|
12246
|
+
return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
12048
12247
|
}
|
|
12049
12248
|
function safeBundleIdSegment(value, fallback) {
|
|
12050
12249
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -12060,6 +12259,14 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
12060
12259
|
const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
|
|
12061
12260
|
const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
|
|
12062
12261
|
const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
|
|
12262
|
+
const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
|
|
12263
|
+
const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
|
|
12264
|
+
const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
|
|
12265
|
+
const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
|
|
12266
|
+
const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
|
|
12267
|
+
const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
|
|
12268
|
+
const cliStatus = typeof cli?.status === "string" ? cli.status : "";
|
|
12269
|
+
const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
|
|
12063
12270
|
return {
|
|
12064
12271
|
createdAt: bundle.createdAt,
|
|
12065
12272
|
targetSessionId: target.targetSessionId,
|
|
@@ -12068,8 +12275,22 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
12068
12275
|
readChatSuccess: readChat.success,
|
|
12069
12276
|
readChatStatus: readChat.status,
|
|
12070
12277
|
readChatTotalMessages: readChat.totalMessages,
|
|
12278
|
+
readChatReturnedMessages,
|
|
12071
12279
|
cliStatus: cli?.status,
|
|
12280
|
+
cliParsedStatus: cliParsedStatus || void 0,
|
|
12072
12281
|
cliMessageCount: cli?.messageCount,
|
|
12282
|
+
cliParsedMessageCount,
|
|
12283
|
+
cliPartialResponseChars: cliPartialResponse.length,
|
|
12284
|
+
parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
|
|
12285
|
+
parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
|
|
12286
|
+
readChatDebug: Object.keys(debugReadChat).length ? {
|
|
12287
|
+
adapterStatus: debugReadChat.adapterStatus,
|
|
12288
|
+
parsedStatus: debugReadChat.parsedStatus,
|
|
12289
|
+
returnedStatus: debugReadChat.returnedStatus,
|
|
12290
|
+
parsedMsgCount: debugReadChat.parsedMsgCount,
|
|
12291
|
+
returnedMsgCount: debugReadChat.returnedMsgCount,
|
|
12292
|
+
shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
|
|
12293
|
+
} : void 0,
|
|
12073
12294
|
hasFrontendSnapshot: !!frontend
|
|
12074
12295
|
};
|
|
12075
12296
|
}
|
|
@@ -12077,7 +12298,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
12077
12298
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
12078
12299
|
const dir = getChatDebugBundleDir();
|
|
12079
12300
|
fs4.mkdirSync(dir, { recursive: true });
|
|
12080
|
-
const savedPath =
|
|
12301
|
+
const savedPath = path12.join(dir, `${bundleId}.json`);
|
|
12081
12302
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
12082
12303
|
`;
|
|
12083
12304
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -12307,7 +12528,7 @@ async function handleChatHistory(h, args) {
|
|
|
12307
12528
|
}
|
|
12308
12529
|
}
|
|
12309
12530
|
async function handleReadChat(h, args) {
|
|
12310
|
-
const provider = h.getProvider(args?.agentType);
|
|
12531
|
+
const provider = h.getProvider(args?.agentType || args?.providerType);
|
|
12311
12532
|
const transport = getTargetTransport(h, provider);
|
|
12312
12533
|
const historySessionId = getHistorySessionId(h, args);
|
|
12313
12534
|
const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
|
|
@@ -12334,10 +12555,13 @@ async function handleReadChat(h, args) {
|
|
|
12334
12555
|
const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
12335
12556
|
const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
12336
12557
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
12337
|
-
const returnedStatus = parsedRecord.status
|
|
12338
|
-
|
|
12558
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
12559
|
+
const runtimeMessageMerger = getTargetInstance(h, args);
|
|
12560
|
+
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
|
|
12561
|
+
const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
|
|
12562
|
+
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
12563
|
return buildReadChatCommandResult({
|
|
12340
|
-
messages:
|
|
12564
|
+
messages: returnedMessages,
|
|
12341
12565
|
status: returnedStatus,
|
|
12342
12566
|
activeModal,
|
|
12343
12567
|
debugReadChat: {
|
|
@@ -12348,7 +12572,7 @@ async function handleReadChat(h, args) {
|
|
|
12348
12572
|
returnedStatus: String(returnedStatus || ""),
|
|
12349
12573
|
shouldPreferAdapterMessages: false,
|
|
12350
12574
|
parsedMsgCount: parsedRecord.messages.length,
|
|
12351
|
-
returnedMsgCount:
|
|
12575
|
+
returnedMsgCount: returnedMessages.length
|
|
12352
12576
|
},
|
|
12353
12577
|
...title ? { title } : {},
|
|
12354
12578
|
...providerSessionId ? { providerSessionId } : {},
|
|
@@ -13221,7 +13445,7 @@ async function handleResolveAction(h, args) {
|
|
|
13221
13445
|
|
|
13222
13446
|
// src/commands/cdp-commands.ts
|
|
13223
13447
|
var fs5 = __toESM(require("fs"));
|
|
13224
|
-
var
|
|
13448
|
+
var path13 = __toESM(require("path"));
|
|
13225
13449
|
var os7 = __toESM(require("os"));
|
|
13226
13450
|
var KEY_TO_VK = {
|
|
13227
13451
|
Backspace: 8,
|
|
@@ -13478,25 +13702,25 @@ function resolveSafePath(requestedPath) {
|
|
|
13478
13702
|
const inputPath = rawPath || ".";
|
|
13479
13703
|
const home = os7.homedir();
|
|
13480
13704
|
if (inputPath.startsWith("~")) {
|
|
13481
|
-
return
|
|
13705
|
+
return path13.resolve(path13.join(home, inputPath.slice(1)));
|
|
13482
13706
|
}
|
|
13483
13707
|
if (process.platform === "win32") {
|
|
13484
13708
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
13485
|
-
if (
|
|
13486
|
-
return
|
|
13709
|
+
if (path13.win32.isAbsolute(normalized)) {
|
|
13710
|
+
return path13.win32.normalize(normalized);
|
|
13487
13711
|
}
|
|
13488
|
-
return
|
|
13712
|
+
return path13.win32.resolve(normalized);
|
|
13489
13713
|
}
|
|
13490
|
-
if (
|
|
13491
|
-
return
|
|
13714
|
+
if (path13.isAbsolute(inputPath)) {
|
|
13715
|
+
return path13.normalize(inputPath);
|
|
13492
13716
|
}
|
|
13493
|
-
return
|
|
13717
|
+
return path13.resolve(inputPath);
|
|
13494
13718
|
}
|
|
13495
13719
|
function listDirectoryEntriesSafe(dirPath) {
|
|
13496
13720
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
13497
13721
|
const files = [];
|
|
13498
13722
|
for (const entry of entries) {
|
|
13499
|
-
const entryPath =
|
|
13723
|
+
const entryPath = path13.join(dirPath, entry.name);
|
|
13500
13724
|
try {
|
|
13501
13725
|
if (entry.isDirectory()) {
|
|
13502
13726
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -13550,7 +13774,7 @@ async function handleFileRead(h, args) {
|
|
|
13550
13774
|
async function handleFileWrite(h, args) {
|
|
13551
13775
|
try {
|
|
13552
13776
|
const filePath = resolveSafePath(args?.path);
|
|
13553
|
-
fs5.mkdirSync(
|
|
13777
|
+
fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
13554
13778
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
13555
13779
|
return { success: true, path: filePath };
|
|
13556
13780
|
} catch (e) {
|
|
@@ -14334,9 +14558,11 @@ var DaemonCommandHandler = class {
|
|
|
14334
14558
|
}
|
|
14335
14559
|
const sessionLookupFailed = !!targetSessionId && !session;
|
|
14336
14560
|
const managerKey = this.extractIdeType(args, sessionLookupFailed);
|
|
14337
|
-
let providerType;
|
|
14561
|
+
let providerType = args?.agentType || args?.providerType;
|
|
14338
14562
|
if (!sessionLookupFailed) {
|
|
14339
|
-
providerType = session?.providerType ||
|
|
14563
|
+
providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
|
|
14564
|
+
} else if (!providerType) {
|
|
14565
|
+
providerType = this.inferProviderType(managerKey);
|
|
14340
14566
|
}
|
|
14341
14567
|
return { session, managerKey, providerType, sessionLookupFailed };
|
|
14342
14568
|
}
|
|
@@ -14416,7 +14642,8 @@ var DaemonCommandHandler = class {
|
|
|
14416
14642
|
"pty_resize",
|
|
14417
14643
|
"invoke_provider_script"
|
|
14418
14644
|
]);
|
|
14419
|
-
|
|
14645
|
+
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);
|
|
14646
|
+
if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
|
|
14420
14647
|
const result2 = {
|
|
14421
14648
|
success: false,
|
|
14422
14649
|
error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
|
|
@@ -14669,7 +14896,7 @@ var DaemonCommandHandler = class {
|
|
|
14669
14896
|
|
|
14670
14897
|
// src/commands/cli-manager.ts
|
|
14671
14898
|
var os13 = __toESM(require("os"));
|
|
14672
|
-
var
|
|
14899
|
+
var path17 = __toESM(require("path"));
|
|
14673
14900
|
var crypto4 = __toESM(require("crypto"));
|
|
14674
14901
|
var import_fs6 = require("fs");
|
|
14675
14902
|
var import_child_process6 = require("child_process");
|
|
@@ -14679,7 +14906,7 @@ init_config();
|
|
|
14679
14906
|
|
|
14680
14907
|
// src/providers/cli-provider-instance.ts
|
|
14681
14908
|
var os12 = __toESM(require("os"));
|
|
14682
|
-
var
|
|
14909
|
+
var path16 = __toESM(require("path"));
|
|
14683
14910
|
var crypto3 = __toESM(require("crypto"));
|
|
14684
14911
|
var fs6 = __toESM(require("fs"));
|
|
14685
14912
|
var import_node_module = require("module");
|
|
@@ -14738,7 +14965,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
14738
14965
|
var CachedDatabaseSync = null;
|
|
14739
14966
|
function getDatabaseSync() {
|
|
14740
14967
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
14741
|
-
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(
|
|
14968
|
+
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
14742
14969
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
14743
14970
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
14744
14971
|
if (!CachedDatabaseSync) {
|
|
@@ -14791,7 +15018,7 @@ var CliProviderInstance = class {
|
|
|
14791
15018
|
this.providerSessionId = options?.providerSessionId;
|
|
14792
15019
|
this.launchMode = options?.launchMode || "new";
|
|
14793
15020
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
14794
|
-
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
|
|
15021
|
+
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
14795
15022
|
this.monitor = new StatusMonitor();
|
|
14796
15023
|
this.historyWriter = new ChatHistoryWriter();
|
|
14797
15024
|
}
|
|
@@ -15268,7 +15495,19 @@ var CliProviderInstance = class {
|
|
|
15268
15495
|
}
|
|
15269
15496
|
}
|
|
15270
15497
|
pushEvent(event) {
|
|
15271
|
-
|
|
15498
|
+
const enrichedEvent = {
|
|
15499
|
+
...event,
|
|
15500
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
|
|
15501
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
|
|
15502
|
+
providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
|
|
15503
|
+
workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
|
|
15504
|
+
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
15505
|
+
};
|
|
15506
|
+
if (this.context?.emitProviderEvent) {
|
|
15507
|
+
this.context.emitProviderEvent(enrichedEvent);
|
|
15508
|
+
return;
|
|
15509
|
+
}
|
|
15510
|
+
this.events.push(enrichedEvent);
|
|
15272
15511
|
}
|
|
15273
15512
|
flushEvents() {
|
|
15274
15513
|
const events = [...this.events];
|
|
@@ -15475,12 +15714,31 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15475
15714
|
);
|
|
15476
15715
|
}
|
|
15477
15716
|
}
|
|
15717
|
+
mergeRuntimeChatMessages(parsedMessages) {
|
|
15718
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
15719
|
+
}
|
|
15478
15720
|
mergeConversationMessages(parsedMessages) {
|
|
15479
15721
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15483
|
-
|
|
15722
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
15723
|
+
message,
|
|
15724
|
+
index,
|
|
15725
|
+
source: "parsed"
|
|
15726
|
+
}));
|
|
15727
|
+
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
15728
|
+
message: entry.message,
|
|
15729
|
+
index: parsedMessages.length + index,
|
|
15730
|
+
source: "runtime"
|
|
15731
|
+
}));
|
|
15732
|
+
const getTime = (message) => {
|
|
15733
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
15734
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
15735
|
+
};
|
|
15736
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
15737
|
+
const aTime = getTime(a.message);
|
|
15738
|
+
const bTime = getTime(b.message);
|
|
15739
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
15740
|
+
if (aTime && !bTime && a.source === "runtime" && b.source === "parsed") return -1;
|
|
15741
|
+
if (!aTime && bTime && a.source === "parsed" && b.source === "runtime") return 1;
|
|
15484
15742
|
return a.index - b.index;
|
|
15485
15743
|
}).map((entry) => entry.message));
|
|
15486
15744
|
}
|
|
@@ -16804,11 +17062,11 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
16804
17062
|
// src/commands/cli-manager.ts
|
|
16805
17063
|
function isExplicitCommand(command) {
|
|
16806
17064
|
const trimmed = command.trim();
|
|
16807
|
-
return
|
|
17065
|
+
return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
16808
17066
|
}
|
|
16809
17067
|
function expandExecutable(command) {
|
|
16810
17068
|
const trimmed = command.trim();
|
|
16811
|
-
return trimmed.startsWith("~") ?
|
|
17069
|
+
return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
16812
17070
|
}
|
|
16813
17071
|
function commandExists(command) {
|
|
16814
17072
|
const trimmed = command.trim();
|
|
@@ -16832,6 +17090,35 @@ function colorize(color, text) {
|
|
|
16832
17090
|
const fn = chalkApi?.[color];
|
|
16833
17091
|
return typeof fn === "function" ? fn(text) : text;
|
|
16834
17092
|
}
|
|
17093
|
+
var COORDINATOR_DELEGATED_ENV_UNSETS = {
|
|
17094
|
+
ADHDEV_INLINE_MESH: "",
|
|
17095
|
+
ADHDEV_MCP_TRANSPORT: "",
|
|
17096
|
+
ADHDEV_MESH_ID: "",
|
|
17097
|
+
HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
|
|
17098
|
+
};
|
|
17099
|
+
function hasCliArg(args, flag) {
|
|
17100
|
+
return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
17101
|
+
}
|
|
17102
|
+
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
17103
|
+
const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
17104
|
+
(0, import_fs6.mkdirSync)(baseDir, { recursive: true });
|
|
17105
|
+
const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
17106
|
+
const filePath = path17.join(baseDir, `${workspaceHash}.json`);
|
|
17107
|
+
(0, import_fs6.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
17108
|
+
return filePath;
|
|
17109
|
+
}
|
|
17110
|
+
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
17111
|
+
const cliType = String(input.cliType || "").trim();
|
|
17112
|
+
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
17113
|
+
const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
|
|
17114
|
+
if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
|
|
17115
|
+
cliArgs.unshift("--ignore-user-config");
|
|
17116
|
+
}
|
|
17117
|
+
if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
|
|
17118
|
+
cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
17119
|
+
}
|
|
17120
|
+
return { cliArgs, env };
|
|
17121
|
+
}
|
|
16835
17122
|
function isUuid(value) {
|
|
16836
17123
|
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
17124
|
}
|
|
@@ -17002,7 +17289,7 @@ var DaemonCliManager = class {
|
|
|
17002
17289
|
attachExisting
|
|
17003
17290
|
}) || void 0;
|
|
17004
17291
|
}
|
|
17005
|
-
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
|
|
17292
|
+
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
|
|
17006
17293
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
17007
17294
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
17008
17295
|
if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
|
|
@@ -17016,7 +17303,7 @@ var DaemonCliManager = class {
|
|
|
17016
17303
|
providerSessionId,
|
|
17017
17304
|
attachExisting
|
|
17018
17305
|
);
|
|
17019
|
-
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
|
|
17306
|
+
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
17020
17307
|
}
|
|
17021
17308
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
17022
17309
|
}
|
|
@@ -17089,7 +17376,7 @@ var DaemonCliManager = class {
|
|
|
17089
17376
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
17090
17377
|
const trimmed = (workingDir || "").trim();
|
|
17091
17378
|
if (!trimmed) throw new Error("working directory required");
|
|
17092
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17379
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
|
|
17093
17380
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
17094
17381
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
17095
17382
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -17219,6 +17506,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17219
17506
|
{
|
|
17220
17507
|
providerSessionId: sessionBinding.providerSessionId,
|
|
17221
17508
|
launchMode: sessionBinding.launchMode,
|
|
17509
|
+
extraEnv: options?.extraEnv,
|
|
17222
17510
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
17223
17511
|
this.persistRecentActivity({
|
|
17224
17512
|
kind: "cli",
|
|
@@ -17239,7 +17527,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17239
17527
|
resolvedCliArgs,
|
|
17240
17528
|
key,
|
|
17241
17529
|
sessionBinding.providerSessionId,
|
|
17242
|
-
false
|
|
17530
|
+
false,
|
|
17531
|
+
options?.extraEnv
|
|
17243
17532
|
);
|
|
17244
17533
|
try {
|
|
17245
17534
|
await adapter.spawn();
|
|
@@ -17463,12 +17752,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17463
17752
|
const dir = resolved.path;
|
|
17464
17753
|
const launchSource = resolved.source;
|
|
17465
17754
|
if (!cliType) throw new Error("cliType required");
|
|
17755
|
+
const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
|
|
17756
|
+
const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
|
|
17757
|
+
cliType,
|
|
17758
|
+
workspace: dir,
|
|
17759
|
+
cliArgs: args?.cliArgs,
|
|
17760
|
+
env: args?.env
|
|
17761
|
+
}) : null;
|
|
17466
17762
|
const started = await this.startSession(
|
|
17467
17763
|
cliType,
|
|
17468
17764
|
dir,
|
|
17469
|
-
args?.cliArgs,
|
|
17765
|
+
delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
|
|
17470
17766
|
args?.initialModel,
|
|
17471
|
-
{
|
|
17767
|
+
{
|
|
17768
|
+
resumeSessionId: args?.resumeSessionId,
|
|
17769
|
+
settingsOverride,
|
|
17770
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
17771
|
+
}
|
|
17472
17772
|
);
|
|
17473
17773
|
return {
|
|
17474
17774
|
success: true,
|
|
@@ -17590,11 +17890,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17590
17890
|
var import_child_process7 = require("child_process");
|
|
17591
17891
|
var net = __toESM(require("net"));
|
|
17592
17892
|
var os15 = __toESM(require("os"));
|
|
17593
|
-
var
|
|
17893
|
+
var path19 = __toESM(require("path"));
|
|
17594
17894
|
|
|
17595
17895
|
// src/providers/provider-loader.ts
|
|
17596
17896
|
var fs7 = __toESM(require("fs"));
|
|
17597
|
-
var
|
|
17897
|
+
var path18 = __toESM(require("path"));
|
|
17598
17898
|
var os14 = __toESM(require("os"));
|
|
17599
17899
|
var chokidar = __toESM(require("chokidar"));
|
|
17600
17900
|
init_logger();
|
|
@@ -17918,7 +18218,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17918
18218
|
try {
|
|
17919
18219
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
17920
18220
|
return ["ide", "extension", "cli", "acp"].some(
|
|
17921
|
-
(category) => fs7.existsSync(
|
|
18221
|
+
(category) => fs7.existsSync(path18.join(candidate, category))
|
|
17922
18222
|
);
|
|
17923
18223
|
} catch {
|
|
17924
18224
|
return false;
|
|
@@ -17926,20 +18226,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17926
18226
|
}
|
|
17927
18227
|
static hasProviderRootMarker(candidate) {
|
|
17928
18228
|
try {
|
|
17929
|
-
return fs7.existsSync(
|
|
18229
|
+
return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
17930
18230
|
} catch {
|
|
17931
18231
|
return false;
|
|
17932
18232
|
}
|
|
17933
18233
|
}
|
|
17934
18234
|
detectDefaultUserDir() {
|
|
17935
|
-
const fallback =
|
|
18235
|
+
const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17936
18236
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17937
18237
|
const visited = /* @__PURE__ */ new Set();
|
|
17938
18238
|
for (const start of this.probeStarts) {
|
|
17939
|
-
let current =
|
|
18239
|
+
let current = path18.resolve(start);
|
|
17940
18240
|
while (!visited.has(current)) {
|
|
17941
18241
|
visited.add(current);
|
|
17942
|
-
const siblingCandidate =
|
|
18242
|
+
const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17943
18243
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17944
18244
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17945
18245
|
if (envOptIn || hasMarker) {
|
|
@@ -17961,7 +18261,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17961
18261
|
return { path: siblingCandidate, source };
|
|
17962
18262
|
}
|
|
17963
18263
|
}
|
|
17964
|
-
const parent =
|
|
18264
|
+
const parent = path18.dirname(current);
|
|
17965
18265
|
if (parent === current) break;
|
|
17966
18266
|
current = parent;
|
|
17967
18267
|
}
|
|
@@ -17971,11 +18271,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17971
18271
|
constructor(options) {
|
|
17972
18272
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17973
18273
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17974
|
-
this.defaultProvidersDir =
|
|
18274
|
+
this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17975
18275
|
const detected = this.detectDefaultUserDir();
|
|
17976
18276
|
this.userDir = detected.path;
|
|
17977
18277
|
this.userDirSource = detected.source;
|
|
17978
|
-
this.upstreamDir =
|
|
18278
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17979
18279
|
this.disableUpstream = false;
|
|
17980
18280
|
this.applySourceConfig({
|
|
17981
18281
|
userDir: options?.userDir,
|
|
@@ -18034,7 +18334,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18034
18334
|
this.userDir = detected.path;
|
|
18035
18335
|
this.userDirSource = detected.source;
|
|
18036
18336
|
}
|
|
18037
|
-
this.upstreamDir =
|
|
18337
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
18038
18338
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
18039
18339
|
if (this.explicitProviderDir) {
|
|
18040
18340
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -18048,7 +18348,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18048
18348
|
* Canonical provider directory shape for a given root.
|
|
18049
18349
|
*/
|
|
18050
18350
|
getProviderDir(root, category, type) {
|
|
18051
|
-
return
|
|
18351
|
+
return path18.join(root, category, type);
|
|
18052
18352
|
}
|
|
18053
18353
|
/**
|
|
18054
18354
|
* Canonical user override directory for a provider.
|
|
@@ -18075,7 +18375,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18075
18375
|
resolveProviderFile(type, ...segments) {
|
|
18076
18376
|
const dir = this.findProviderDirInternal(type);
|
|
18077
18377
|
if (!dir) return null;
|
|
18078
|
-
return
|
|
18378
|
+
return path18.join(dir, ...segments);
|
|
18079
18379
|
}
|
|
18080
18380
|
/**
|
|
18081
18381
|
* Load all providers (3-tier priority)
|
|
@@ -18114,7 +18414,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18114
18414
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
18115
18415
|
try {
|
|
18116
18416
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
18117
|
-
(d) => fs7.statSync(
|
|
18417
|
+
(d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
|
|
18118
18418
|
);
|
|
18119
18419
|
} catch {
|
|
18120
18420
|
return false;
|
|
@@ -18611,8 +18911,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18611
18911
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
18612
18912
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
18613
18913
|
if (providerDir) {
|
|
18614
|
-
const fullDir =
|
|
18615
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18914
|
+
const fullDir = path18.join(providerDir, entry.scriptDir);
|
|
18915
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18616
18916
|
}
|
|
18617
18917
|
matched = true;
|
|
18618
18918
|
}
|
|
@@ -18627,8 +18927,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18627
18927
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18628
18928
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
18629
18929
|
if (providerDir) {
|
|
18630
|
-
const fullDir =
|
|
18631
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18930
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18931
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18632
18932
|
}
|
|
18633
18933
|
}
|
|
18634
18934
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -18645,8 +18945,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18645
18945
|
resolved._resolvedScriptDir = dirOverride;
|
|
18646
18946
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
18647
18947
|
if (providerDir) {
|
|
18648
|
-
const fullDir =
|
|
18649
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18948
|
+
const fullDir = path18.join(providerDir, dirOverride);
|
|
18949
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18650
18950
|
}
|
|
18651
18951
|
}
|
|
18652
18952
|
} else if (override.scripts) {
|
|
@@ -18662,8 +18962,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18662
18962
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18663
18963
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
18664
18964
|
if (providerDir) {
|
|
18665
|
-
const fullDir =
|
|
18666
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18965
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18966
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18667
18967
|
}
|
|
18668
18968
|
}
|
|
18669
18969
|
}
|
|
@@ -18695,14 +18995,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18695
18995
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
18696
18996
|
return null;
|
|
18697
18997
|
}
|
|
18698
|
-
const dir =
|
|
18998
|
+
const dir = path18.join(providerDir, scriptDir);
|
|
18699
18999
|
if (!fs7.existsSync(dir)) {
|
|
18700
19000
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
18701
19001
|
return null;
|
|
18702
19002
|
}
|
|
18703
19003
|
const cached = this.scriptsCache.get(dir);
|
|
18704
19004
|
if (cached) return cached;
|
|
18705
|
-
const scriptsJs =
|
|
19005
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
18706
19006
|
if (fs7.existsSync(scriptsJs)) {
|
|
18707
19007
|
try {
|
|
18708
19008
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -18744,7 +19044,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18744
19044
|
return;
|
|
18745
19045
|
}
|
|
18746
19046
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
18747
|
-
this.log(`File changed: ${
|
|
19047
|
+
this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
|
|
18748
19048
|
this.reload();
|
|
18749
19049
|
}
|
|
18750
19050
|
};
|
|
@@ -18799,7 +19099,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18799
19099
|
}
|
|
18800
19100
|
const https = require("https");
|
|
18801
19101
|
const { execSync: execSync7 } = require("child_process");
|
|
18802
|
-
const metaPath =
|
|
19102
|
+
const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
18803
19103
|
let prevEtag = "";
|
|
18804
19104
|
let prevTimestamp = 0;
|
|
18805
19105
|
try {
|
|
@@ -18859,17 +19159,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18859
19159
|
return { updated: false };
|
|
18860
19160
|
}
|
|
18861
19161
|
this.log("Downloading latest providers from GitHub...");
|
|
18862
|
-
const tmpTar =
|
|
18863
|
-
const tmpExtract =
|
|
19162
|
+
const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
19163
|
+
const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
18864
19164
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
18865
19165
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
18866
19166
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
18867
19167
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
18868
19168
|
const rootDir = extracted.find(
|
|
18869
|
-
(d) => fs7.statSync(
|
|
19169
|
+
(d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
18870
19170
|
);
|
|
18871
19171
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
18872
|
-
const sourceDir =
|
|
19172
|
+
const sourceDir = path18.join(tmpExtract, rootDir);
|
|
18873
19173
|
const backupDir = this.upstreamDir + ".bak";
|
|
18874
19174
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
18875
19175
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -18944,8 +19244,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18944
19244
|
copyDirRecursive(src, dest) {
|
|
18945
19245
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18946
19246
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18947
|
-
const srcPath =
|
|
18948
|
-
const destPath =
|
|
19247
|
+
const srcPath = path18.join(src, entry.name);
|
|
19248
|
+
const destPath = path18.join(dest, entry.name);
|
|
18949
19249
|
if (entry.isDirectory()) {
|
|
18950
19250
|
this.copyDirRecursive(srcPath, destPath);
|
|
18951
19251
|
} else {
|
|
@@ -18956,7 +19256,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18956
19256
|
/** .meta.json save */
|
|
18957
19257
|
writeMeta(metaPath, etag, timestamp) {
|
|
18958
19258
|
try {
|
|
18959
|
-
fs7.mkdirSync(
|
|
19259
|
+
fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
|
|
18960
19260
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18961
19261
|
etag,
|
|
18962
19262
|
timestamp,
|
|
@@ -18973,7 +19273,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18973
19273
|
const scan = (d) => {
|
|
18974
19274
|
try {
|
|
18975
19275
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18976
|
-
if (entry.isDirectory()) scan(
|
|
19276
|
+
if (entry.isDirectory()) scan(path18.join(d, entry.name));
|
|
18977
19277
|
else if (entry.name === "provider.json") count++;
|
|
18978
19278
|
}
|
|
18979
19279
|
} catch {
|
|
@@ -19201,17 +19501,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19201
19501
|
for (const root of searchRoots) {
|
|
19202
19502
|
if (!fs7.existsSync(root)) continue;
|
|
19203
19503
|
const candidate = this.getProviderDir(root, cat, type);
|
|
19204
|
-
if (fs7.existsSync(
|
|
19205
|
-
const catDir =
|
|
19504
|
+
if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
|
|
19505
|
+
const catDir = path18.join(root, cat);
|
|
19206
19506
|
if (fs7.existsSync(catDir)) {
|
|
19207
19507
|
try {
|
|
19208
19508
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
19209
19509
|
if (!entry.isDirectory()) continue;
|
|
19210
|
-
const jsonPath =
|
|
19510
|
+
const jsonPath = path18.join(catDir, entry.name, "provider.json");
|
|
19211
19511
|
if (fs7.existsSync(jsonPath)) {
|
|
19212
19512
|
try {
|
|
19213
19513
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
19214
|
-
if (data.type === type) return
|
|
19514
|
+
if (data.type === type) return path18.join(catDir, entry.name);
|
|
19215
19515
|
} catch {
|
|
19216
19516
|
}
|
|
19217
19517
|
}
|
|
@@ -19228,7 +19528,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19228
19528
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
19229
19529
|
*/
|
|
19230
19530
|
buildScriptWrappersFromDir(dir) {
|
|
19231
|
-
const scriptsJs =
|
|
19531
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
19232
19532
|
if (fs7.existsSync(scriptsJs)) {
|
|
19233
19533
|
try {
|
|
19234
19534
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -19242,7 +19542,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19242
19542
|
for (const file of fs7.readdirSync(dir)) {
|
|
19243
19543
|
if (!file.endsWith(".js")) continue;
|
|
19244
19544
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
19245
|
-
const filePath =
|
|
19545
|
+
const filePath = path18.join(dir, file);
|
|
19246
19546
|
result[scriptName] = (...args) => {
|
|
19247
19547
|
try {
|
|
19248
19548
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -19302,7 +19602,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19302
19602
|
}
|
|
19303
19603
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
19304
19604
|
if (hasJson) {
|
|
19305
|
-
const jsonPath =
|
|
19605
|
+
const jsonPath = path18.join(d, "provider.json");
|
|
19306
19606
|
try {
|
|
19307
19607
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
19308
19608
|
const mod = JSON.parse(raw);
|
|
@@ -19323,7 +19623,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19323
19623
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
19324
19624
|
} else {
|
|
19325
19625
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
19326
|
-
const scriptsPath =
|
|
19626
|
+
const scriptsPath = path18.join(d, "scripts.js");
|
|
19327
19627
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
19328
19628
|
try {
|
|
19329
19629
|
delete require.cache[require.resolve(scriptsPath)];
|
|
@@ -19349,7 +19649,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19349
19649
|
if (!entry.isDirectory()) continue;
|
|
19350
19650
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
19351
19651
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
19352
|
-
scan(
|
|
19652
|
+
scan(path18.join(d, entry.name));
|
|
19353
19653
|
}
|
|
19354
19654
|
}
|
|
19355
19655
|
};
|
|
@@ -19674,8 +19974,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
19674
19974
|
const appNameMap = getMacAppIdentifiers();
|
|
19675
19975
|
const appName = appNameMap[ideId];
|
|
19676
19976
|
if (appName) {
|
|
19677
|
-
const storagePath =
|
|
19678
|
-
process.env.APPDATA ||
|
|
19977
|
+
const storagePath = path19.join(
|
|
19978
|
+
process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
|
|
19679
19979
|
appName,
|
|
19680
19980
|
"storage.json"
|
|
19681
19981
|
);
|
|
@@ -19864,9 +20164,9 @@ init_logger();
|
|
|
19864
20164
|
|
|
19865
20165
|
// src/logging/command-log.ts
|
|
19866
20166
|
var fs8 = __toESM(require("fs"));
|
|
19867
|
-
var
|
|
20167
|
+
var path20 = __toESM(require("path"));
|
|
19868
20168
|
var os16 = __toESM(require("os"));
|
|
19869
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
20169
|
+
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
20170
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
19871
20171
|
var MAX_DAYS = 7;
|
|
19872
20172
|
try {
|
|
@@ -19904,13 +20204,13 @@ function getDateStr2() {
|
|
|
19904
20204
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19905
20205
|
}
|
|
19906
20206
|
var currentDate2 = getDateStr2();
|
|
19907
|
-
var currentFile =
|
|
20207
|
+
var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19908
20208
|
var writeCount2 = 0;
|
|
19909
20209
|
function checkRotation() {
|
|
19910
20210
|
const today = getDateStr2();
|
|
19911
20211
|
if (today !== currentDate2) {
|
|
19912
20212
|
currentDate2 = today;
|
|
19913
|
-
currentFile =
|
|
20213
|
+
currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19914
20214
|
cleanOldFiles();
|
|
19915
20215
|
}
|
|
19916
20216
|
}
|
|
@@ -19924,7 +20224,7 @@ function cleanOldFiles() {
|
|
|
19924
20224
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
19925
20225
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
19926
20226
|
try {
|
|
19927
|
-
fs8.unlinkSync(
|
|
20227
|
+
fs8.unlinkSync(path20.join(LOG_DIR2, file));
|
|
19928
20228
|
} catch {
|
|
19929
20229
|
}
|
|
19930
20230
|
}
|
|
@@ -20007,14 +20307,66 @@ function getRecentCommands(count = 50) {
|
|
|
20007
20307
|
cleanOldFiles();
|
|
20008
20308
|
|
|
20009
20309
|
// src/commands/router.ts
|
|
20310
|
+
var yaml = __toESM(require("js-yaml"));
|
|
20010
20311
|
init_logger();
|
|
20011
20312
|
|
|
20012
20313
|
// src/commands/mesh-coordinator.ts
|
|
20013
|
-
var
|
|
20314
|
+
var import_node_child_process3 = require("child_process");
|
|
20315
|
+
var import_node_fs3 = require("fs");
|
|
20014
20316
|
var import_node_module2 = require("module");
|
|
20317
|
+
var os17 = __toESM(require("os"));
|
|
20015
20318
|
var import_node_path = require("path");
|
|
20016
20319
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
20017
20320
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20321
|
+
var HERMES_CLI_TYPE = "hermes-cli";
|
|
20322
|
+
var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
|
|
20323
|
+
function isHermesProvider(provider, cliType) {
|
|
20324
|
+
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
20325
|
+
return type === HERMES_CLI_TYPE;
|
|
20326
|
+
}
|
|
20327
|
+
function resolveHermesMeshCoordinatorSetup(options) {
|
|
20328
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
20329
|
+
meshId: options.meshId,
|
|
20330
|
+
nodeExecutable: options.nodeExecutable,
|
|
20331
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath
|
|
20332
|
+
});
|
|
20333
|
+
if (!mcpServer) {
|
|
20334
|
+
return {
|
|
20335
|
+
kind: "unsupported",
|
|
20336
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20337
|
+
};
|
|
20338
|
+
}
|
|
20339
|
+
const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
|
|
20340
|
+
if (!configPath.trim()) {
|
|
20341
|
+
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20342
|
+
}
|
|
20343
|
+
return {
|
|
20344
|
+
kind: "auto_import",
|
|
20345
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20346
|
+
configPath,
|
|
20347
|
+
configFormat: "hermes_config_yaml",
|
|
20348
|
+
mcpServer
|
|
20349
|
+
};
|
|
20350
|
+
}
|
|
20351
|
+
function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
|
|
20352
|
+
return {
|
|
20353
|
+
kind: "manual",
|
|
20354
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20355
|
+
configFormat: "hermes_config_yaml",
|
|
20356
|
+
configPathCommand: HERMES_MCP_CONFIG_PATH,
|
|
20357
|
+
requiresRestart: true,
|
|
20358
|
+
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.",
|
|
20359
|
+
template: renderMeshCoordinatorTemplate(
|
|
20360
|
+
"mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
|
|
20361
|
+
{
|
|
20362
|
+
meshId,
|
|
20363
|
+
workspace,
|
|
20364
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20365
|
+
adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
|
|
20366
|
+
}
|
|
20367
|
+
)
|
|
20368
|
+
};
|
|
20369
|
+
}
|
|
20018
20370
|
function resolveMeshCoordinatorSetup(options) {
|
|
20019
20371
|
const { provider, meshId, workspace } = options;
|
|
20020
20372
|
const config = provider?.meshCoordinator;
|
|
@@ -20024,6 +20376,9 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20024
20376
|
reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
|
|
20025
20377
|
};
|
|
20026
20378
|
}
|
|
20379
|
+
if (isHermesProvider(provider, options.cliType)) {
|
|
20380
|
+
return resolveHermesMeshCoordinatorSetup(options);
|
|
20381
|
+
}
|
|
20027
20382
|
const mcpConfig = config.mcpConfig;
|
|
20028
20383
|
if (!mcpConfig || mcpConfig.mode === "none") {
|
|
20029
20384
|
return {
|
|
@@ -20033,8 +20388,8 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20033
20388
|
}
|
|
20034
20389
|
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
|
|
20035
20390
|
if (mcpConfig.mode === "auto_import") {
|
|
20036
|
-
const
|
|
20037
|
-
if (!
|
|
20391
|
+
const path27 = mcpConfig.path?.trim();
|
|
20392
|
+
if (!path27) {
|
|
20038
20393
|
return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
|
|
20039
20394
|
}
|
|
20040
20395
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
@@ -20045,13 +20400,13 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20045
20400
|
if (!mcpServer) {
|
|
20046
20401
|
return {
|
|
20047
20402
|
kind: "unsupported",
|
|
20048
|
-
reason: "Could not resolve the ADHDev MCP server entrypoint
|
|
20403
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20049
20404
|
};
|
|
20050
20405
|
}
|
|
20051
20406
|
return {
|
|
20052
20407
|
kind: "auto_import",
|
|
20053
20408
|
serverName,
|
|
20054
|
-
configPath: (
|
|
20409
|
+
configPath: resolveMcpConfigPath(path27, workspace),
|
|
20055
20410
|
configFormat: mcpConfig.format,
|
|
20056
20411
|
mcpServer
|
|
20057
20412
|
};
|
|
@@ -20085,13 +20440,84 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20085
20440
|
function renderMeshCoordinatorTemplate(template, values) {
|
|
20086
20441
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
|
|
20087
20442
|
}
|
|
20443
|
+
function resolveMcpConfigPath(configPath, workspace) {
|
|
20444
|
+
const trimmed = configPath.trim();
|
|
20445
|
+
if (trimmed === "~") return os17.homedir();
|
|
20446
|
+
if (trimmed.startsWith("~/")) return (0, import_node_path.join)(os17.homedir(), trimmed.slice(2));
|
|
20447
|
+
if ((0, import_node_path.isAbsolute)(trimmed)) return trimmed;
|
|
20448
|
+
return (0, import_node_path.join)(workspace, trimmed);
|
|
20449
|
+
}
|
|
20088
20450
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
20089
20451
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
20090
20452
|
if (!entryPath) return null;
|
|
20453
|
+
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
|
|
20454
|
+
if (!nodeExecutable) return null;
|
|
20091
20455
|
return {
|
|
20092
|
-
command:
|
|
20093
|
-
args: [entryPath, "--repo-mesh", options.meshId]
|
|
20456
|
+
command: nodeExecutable,
|
|
20457
|
+
args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
|
|
20458
|
+
};
|
|
20459
|
+
}
|
|
20460
|
+
function resolveMcpNodeExecutable(explicitExecutable) {
|
|
20461
|
+
const explicit = explicitExecutable?.trim();
|
|
20462
|
+
if (explicit) return explicit;
|
|
20463
|
+
const candidates = [];
|
|
20464
|
+
const addCandidate = (candidate) => {
|
|
20465
|
+
const trimmed = candidate?.trim();
|
|
20466
|
+
if (!trimmed) return;
|
|
20467
|
+
const normalized = normalizeExistingPath(trimmed) || trimmed;
|
|
20468
|
+
if (!candidates.includes(normalized)) candidates.push(normalized);
|
|
20094
20469
|
};
|
|
20470
|
+
addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
|
|
20471
|
+
addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
|
|
20472
|
+
addCandidate(process.env.npm_node_execpath);
|
|
20473
|
+
addNodeCandidatesFromPath(process.env.PATH, addCandidate);
|
|
20474
|
+
addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
|
|
20475
|
+
addCandidate("/opt/homebrew/bin/node");
|
|
20476
|
+
addCandidate("/usr/local/bin/node");
|
|
20477
|
+
addCandidate("/usr/bin/node");
|
|
20478
|
+
addCandidate(process.execPath);
|
|
20479
|
+
for (const candidate of candidates) {
|
|
20480
|
+
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
|
|
20481
|
+
}
|
|
20482
|
+
return null;
|
|
20483
|
+
}
|
|
20484
|
+
function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
20485
|
+
for (const entry of (pathValue || "").split(":")) {
|
|
20486
|
+
const dir = entry.trim();
|
|
20487
|
+
if (!dir) continue;
|
|
20488
|
+
addCandidate((0, import_node_path.join)(dir, "node"));
|
|
20489
|
+
}
|
|
20490
|
+
}
|
|
20491
|
+
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
20492
|
+
const versionsDir = (0, import_node_path.join)(homeDir, ".nvm", "versions", "node");
|
|
20493
|
+
try {
|
|
20494
|
+
const versionDirs = (0, import_node_fs3.readdirSync)(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
20495
|
+
for (const versionDir of versionDirs) {
|
|
20496
|
+
addCandidate((0, import_node_path.join)(versionsDir, versionDir, "bin", "node"));
|
|
20497
|
+
}
|
|
20498
|
+
} catch {
|
|
20499
|
+
}
|
|
20500
|
+
}
|
|
20501
|
+
function compareNodeVersionNamesDescending(a, b) {
|
|
20502
|
+
const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
20503
|
+
const left = parse(a);
|
|
20504
|
+
const right = parse(b);
|
|
20505
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
20506
|
+
const diff = (right[i] || 0) - (left[i] || 0);
|
|
20507
|
+
if (diff !== 0) return diff;
|
|
20508
|
+
}
|
|
20509
|
+
return b.localeCompare(a);
|
|
20510
|
+
}
|
|
20511
|
+
function nodeRuntimeSupportsWebSocket(nodeExecutable) {
|
|
20512
|
+
try {
|
|
20513
|
+
(0, import_node_child_process3.execFileSync)(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
|
|
20514
|
+
stdio: "ignore",
|
|
20515
|
+
timeout: 3e3
|
|
20516
|
+
});
|
|
20517
|
+
return true;
|
|
20518
|
+
} catch {
|
|
20519
|
+
return false;
|
|
20520
|
+
}
|
|
20095
20521
|
}
|
|
20096
20522
|
function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
20097
20523
|
const explicit = explicitPath?.trim();
|
|
@@ -20128,15 +20554,109 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
20128
20554
|
}
|
|
20129
20555
|
function normalizeExistingPath(filePath) {
|
|
20130
20556
|
try {
|
|
20131
|
-
if (!(0,
|
|
20132
|
-
return
|
|
20557
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return null;
|
|
20558
|
+
return import_node_fs3.realpathSync.native(filePath);
|
|
20133
20559
|
} catch {
|
|
20134
20560
|
return null;
|
|
20135
20561
|
}
|
|
20136
20562
|
}
|
|
20137
20563
|
|
|
20564
|
+
// src/mesh/mesh-events.ts
|
|
20565
|
+
init_mesh_config();
|
|
20566
|
+
init_logger();
|
|
20567
|
+
function readNonEmptyString(value) {
|
|
20568
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
20569
|
+
}
|
|
20570
|
+
function formatCompletionMetadata(event) {
|
|
20571
|
+
const parts = [
|
|
20572
|
+
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
20573
|
+
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
20574
|
+
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
20575
|
+
].filter(Boolean);
|
|
20576
|
+
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
20577
|
+
}
|
|
20578
|
+
function buildMeshSystemMessage(args) {
|
|
20579
|
+
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
20580
|
+
if (args.event === "agent:generating_completed") {
|
|
20581
|
+
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. You may use mesh_read_chat to review its progress.`;
|
|
20582
|
+
}
|
|
20583
|
+
if (args.event === "agent:waiting_approval") {
|
|
20584
|
+
return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
20585
|
+
}
|
|
20586
|
+
return "";
|
|
20587
|
+
}
|
|
20588
|
+
function injectMeshSystemMessage(components, args) {
|
|
20589
|
+
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
20590
|
+
const instState = inst.getState();
|
|
20591
|
+
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
20592
|
+
if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
|
|
20593
|
+
return true;
|
|
20594
|
+
});
|
|
20595
|
+
if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
|
|
20596
|
+
const messageText = buildMeshSystemMessage({
|
|
20597
|
+
event: args.event,
|
|
20598
|
+
nodeLabel: args.nodeLabel,
|
|
20599
|
+
metadataEvent: args.metadataEvent
|
|
20600
|
+
});
|
|
20601
|
+
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
20602
|
+
for (const coord of coordinatorInstances) {
|
|
20603
|
+
const coordState = coord.getState();
|
|
20604
|
+
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
20605
|
+
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
20606
|
+
}
|
|
20607
|
+
return { success: true, forwarded: coordinatorInstances.length };
|
|
20608
|
+
}
|
|
20609
|
+
function handleMeshForwardEvent(components, payload) {
|
|
20610
|
+
const eventName = readNonEmptyString(payload.event);
|
|
20611
|
+
if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
|
|
20612
|
+
return { success: false, error: "unsupported mesh event" };
|
|
20613
|
+
}
|
|
20614
|
+
const meshId = readNonEmptyString(payload.meshId);
|
|
20615
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
20616
|
+
const nodeId = readNonEmptyString(payload.nodeId);
|
|
20617
|
+
const workspace = readNonEmptyString(payload.workspace);
|
|
20618
|
+
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
20619
|
+
return injectMeshSystemMessage(components, {
|
|
20620
|
+
meshId,
|
|
20621
|
+
nodeLabel,
|
|
20622
|
+
event: eventName,
|
|
20623
|
+
metadataEvent: {
|
|
20624
|
+
targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
|
|
20625
|
+
providerType: readNonEmptyString(payload.providerType),
|
|
20626
|
+
providerSessionId: readNonEmptyString(payload.providerSessionId)
|
|
20627
|
+
}
|
|
20628
|
+
});
|
|
20629
|
+
}
|
|
20630
|
+
function setupMeshEventForwarding(components) {
|
|
20631
|
+
components.instanceManager.onEvent((event) => {
|
|
20632
|
+
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
20633
|
+
const instanceId = readNonEmptyString(event.instanceId);
|
|
20634
|
+
if (!instanceId) return;
|
|
20635
|
+
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
20636
|
+
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
20637
|
+
const state = sourceInstance.getState();
|
|
20638
|
+
const workspace = readNonEmptyString(state.workspace);
|
|
20639
|
+
if (!workspace) return;
|
|
20640
|
+
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
20641
|
+
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
20642
|
+
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
20643
|
+
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
20644
|
+
if (!meshId) return;
|
|
20645
|
+
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
20646
|
+
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
20647
|
+
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
20648
|
+
injectMeshSystemMessage(components, {
|
|
20649
|
+
meshId,
|
|
20650
|
+
sourceInstanceId: instanceId,
|
|
20651
|
+
nodeLabel,
|
|
20652
|
+
event: event.event,
|
|
20653
|
+
metadataEvent: event
|
|
20654
|
+
});
|
|
20655
|
+
});
|
|
20656
|
+
}
|
|
20657
|
+
|
|
20138
20658
|
// src/status/snapshot.ts
|
|
20139
|
-
var
|
|
20659
|
+
var os18 = __toESM(require("os"));
|
|
20140
20660
|
init_config();
|
|
20141
20661
|
init_terminal_screen();
|
|
20142
20662
|
init_logger();
|
|
@@ -20192,8 +20712,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20192
20712
|
}
|
|
20193
20713
|
function buildMachineInfo(profile = "full") {
|
|
20194
20714
|
const base = {
|
|
20195
|
-
hostname:
|
|
20196
|
-
platform:
|
|
20715
|
+
hostname: os18.hostname(),
|
|
20716
|
+
platform: os18.platform()
|
|
20197
20717
|
};
|
|
20198
20718
|
if (profile === "live") {
|
|
20199
20719
|
return base;
|
|
@@ -20202,23 +20722,23 @@ function buildMachineInfo(profile = "full") {
|
|
|
20202
20722
|
const memSnap2 = getHostMemorySnapshot();
|
|
20203
20723
|
return {
|
|
20204
20724
|
...base,
|
|
20205
|
-
arch:
|
|
20206
|
-
cpus:
|
|
20725
|
+
arch: os18.arch(),
|
|
20726
|
+
cpus: os18.cpus().length,
|
|
20207
20727
|
totalMem: memSnap2.totalMem,
|
|
20208
|
-
release:
|
|
20728
|
+
release: os18.release()
|
|
20209
20729
|
};
|
|
20210
20730
|
}
|
|
20211
20731
|
const memSnap = getHostMemorySnapshot();
|
|
20212
20732
|
return {
|
|
20213
20733
|
...base,
|
|
20214
|
-
arch:
|
|
20215
|
-
cpus:
|
|
20734
|
+
arch: os18.arch(),
|
|
20735
|
+
cpus: os18.cpus().length,
|
|
20216
20736
|
totalMem: memSnap.totalMem,
|
|
20217
20737
|
freeMem: memSnap.freeMem,
|
|
20218
20738
|
availableMem: memSnap.availableMem,
|
|
20219
|
-
loadavg:
|
|
20220
|
-
uptime:
|
|
20221
|
-
release:
|
|
20739
|
+
loadavg: os18.loadavg(),
|
|
20740
|
+
uptime: os18.uptime(),
|
|
20741
|
+
release: os18.release()
|
|
20222
20742
|
};
|
|
20223
20743
|
}
|
|
20224
20744
|
function parseMessageTime(value) {
|
|
@@ -20452,14 +20972,14 @@ function buildStatusSnapshot(options) {
|
|
|
20452
20972
|
var import_child_process8 = require("child_process");
|
|
20453
20973
|
var import_child_process9 = require("child_process");
|
|
20454
20974
|
var fs9 = __toESM(require("fs"));
|
|
20455
|
-
var
|
|
20456
|
-
var
|
|
20975
|
+
var os19 = __toESM(require("os"));
|
|
20976
|
+
var path21 = __toESM(require("path"));
|
|
20457
20977
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
20458
20978
|
function getUpgradeLogPath() {
|
|
20459
|
-
const home =
|
|
20460
|
-
const dir =
|
|
20979
|
+
const home = os19.homedir();
|
|
20980
|
+
const dir = path21.join(home, ".adhdev");
|
|
20461
20981
|
fs9.mkdirSync(dir, { recursive: true });
|
|
20462
|
-
return
|
|
20982
|
+
return path21.join(dir, "daemon-upgrade.log");
|
|
20463
20983
|
}
|
|
20464
20984
|
function appendUpgradeLog(message) {
|
|
20465
20985
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -20470,14 +20990,14 @@ function appendUpgradeLog(message) {
|
|
|
20470
20990
|
}
|
|
20471
20991
|
}
|
|
20472
20992
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
20473
|
-
const binDir =
|
|
20993
|
+
const binDir = path21.dirname(nodeExecutable);
|
|
20474
20994
|
if (platform10 === "win32") {
|
|
20475
|
-
const npmCliPath =
|
|
20995
|
+
const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
20476
20996
|
if (fs9.existsSync(npmCliPath)) {
|
|
20477
20997
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20478
20998
|
}
|
|
20479
20999
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
20480
|
-
const candidatePath =
|
|
21000
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20481
21001
|
if (fs9.existsSync(candidatePath)) {
|
|
20482
21002
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20483
21003
|
}
|
|
@@ -20485,7 +21005,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
20485
21005
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20486
21006
|
}
|
|
20487
21007
|
for (const candidate of ["npm"]) {
|
|
20488
|
-
const candidatePath =
|
|
21008
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20489
21009
|
if (fs9.existsSync(candidatePath)) {
|
|
20490
21010
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20491
21011
|
}
|
|
@@ -20502,13 +21022,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20502
21022
|
let currentDir = resolvedPath;
|
|
20503
21023
|
try {
|
|
20504
21024
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
20505
|
-
currentDir =
|
|
21025
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20506
21026
|
}
|
|
20507
21027
|
} catch {
|
|
20508
|
-
currentDir =
|
|
21028
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20509
21029
|
}
|
|
20510
21030
|
while (true) {
|
|
20511
|
-
const packageJsonPath =
|
|
21031
|
+
const packageJsonPath = path21.join(currentDir, "package.json");
|
|
20512
21032
|
try {
|
|
20513
21033
|
if (fs9.existsSync(packageJsonPath)) {
|
|
20514
21034
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -20519,7 +21039,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20519
21039
|
}
|
|
20520
21040
|
} catch {
|
|
20521
21041
|
}
|
|
20522
|
-
const parentDir =
|
|
21042
|
+
const parentDir = path21.dirname(currentDir);
|
|
20523
21043
|
if (parentDir === currentDir) {
|
|
20524
21044
|
return null;
|
|
20525
21045
|
}
|
|
@@ -20527,13 +21047,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20527
21047
|
}
|
|
20528
21048
|
}
|
|
20529
21049
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
20530
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
20531
|
-
if (
|
|
21050
|
+
const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
|
|
21051
|
+
if (path21.basename(nodeModulesDir) !== "node_modules") {
|
|
20532
21052
|
return null;
|
|
20533
21053
|
}
|
|
20534
|
-
const maybeLibDir =
|
|
20535
|
-
if (
|
|
20536
|
-
return
|
|
21054
|
+
const maybeLibDir = path21.dirname(nodeModulesDir);
|
|
21055
|
+
if (path21.basename(maybeLibDir) === "lib") {
|
|
21056
|
+
return path21.dirname(maybeLibDir);
|
|
20537
21057
|
}
|
|
20538
21058
|
return maybeLibDir;
|
|
20539
21059
|
}
|
|
@@ -20648,7 +21168,7 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
20648
21168
|
}
|
|
20649
21169
|
}
|
|
20650
21170
|
function stopSessionHostProcesses(appName) {
|
|
20651
|
-
const pidFile =
|
|
21171
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
20652
21172
|
try {
|
|
20653
21173
|
if (fs9.existsSync(pidFile)) {
|
|
20654
21174
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -20665,7 +21185,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
20665
21185
|
}
|
|
20666
21186
|
}
|
|
20667
21187
|
function removeDaemonPidFile() {
|
|
20668
|
-
const pidFile =
|
|
21188
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
20669
21189
|
try {
|
|
20670
21190
|
fs9.unlinkSync(pidFile);
|
|
20671
21191
|
} catch {
|
|
@@ -20676,7 +21196,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20676
21196
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20677
21197
|
if (!npmRoot) return;
|
|
20678
21198
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20679
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
21199
|
+
const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
|
|
20680
21200
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
20681
21201
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
20682
21202
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -20684,25 +21204,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20684
21204
|
}
|
|
20685
21205
|
if (pkgName.startsWith("@")) {
|
|
20686
21206
|
const [scope, name] = pkgName.split("/");
|
|
20687
|
-
const scopeDir =
|
|
21207
|
+
const scopeDir = path21.join(npmRoot, scope);
|
|
20688
21208
|
if (!fs9.existsSync(scopeDir)) return;
|
|
20689
21209
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
20690
21210
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
20691
|
-
fs9.rmSync(
|
|
20692
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
21211
|
+
fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
|
|
21212
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
|
|
20693
21213
|
}
|
|
20694
21214
|
} else {
|
|
20695
21215
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
20696
21216
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
20697
|
-
fs9.rmSync(
|
|
20698
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
21217
|
+
fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
|
|
21218
|
+
appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
|
|
20699
21219
|
}
|
|
20700
21220
|
}
|
|
20701
21221
|
if (fs9.existsSync(binDir)) {
|
|
20702
21222
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
20703
21223
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
20704
|
-
fs9.rmSync(
|
|
20705
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
21224
|
+
fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
|
|
21225
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
|
|
20706
21226
|
}
|
|
20707
21227
|
}
|
|
20708
21228
|
}
|
|
@@ -20803,6 +21323,56 @@ function normalizeReleaseChannel(value) {
|
|
|
20803
21323
|
function resolveUpgradeChannel(args) {
|
|
20804
21324
|
return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
|
|
20805
21325
|
}
|
|
21326
|
+
function readProviderPriorityFromPolicy(policy) {
|
|
21327
|
+
const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
|
|
21328
|
+
const raw = record.providerPriority;
|
|
21329
|
+
if (!Array.isArray(raw)) return [];
|
|
21330
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21331
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
21332
|
+
if (seen.has(type)) return false;
|
|
21333
|
+
seen.add(type);
|
|
21334
|
+
return true;
|
|
21335
|
+
});
|
|
21336
|
+
}
|
|
21337
|
+
async function resolveProviderTypeFromPriority(args) {
|
|
21338
|
+
if (!args.providerPriority.length) {
|
|
21339
|
+
return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
|
|
21340
|
+
}
|
|
21341
|
+
const failed = [];
|
|
21342
|
+
for (const requestedType of args.providerPriority) {
|
|
21343
|
+
const normalizedType = args.providerLoader.resolveAlias(requestedType);
|
|
21344
|
+
if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
21345
|
+
failed.push(`${requestedType}: disabled`);
|
|
21346
|
+
continue;
|
|
21347
|
+
}
|
|
21348
|
+
const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
|
|
21349
|
+
args.providerLoader.setCliDetectionResults([{
|
|
21350
|
+
id: normalizedType,
|
|
21351
|
+
installed: !!detected,
|
|
21352
|
+
path: detected?.path
|
|
21353
|
+
}], false);
|
|
21354
|
+
args.onStatusChange?.();
|
|
21355
|
+
if (detected) return { providerType: normalizedType };
|
|
21356
|
+
failed.push(`${requestedType}: not detected`);
|
|
21357
|
+
}
|
|
21358
|
+
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
21359
|
+
}
|
|
21360
|
+
function loadYamlModule() {
|
|
21361
|
+
return yaml;
|
|
21362
|
+
}
|
|
21363
|
+
function getMcpServersKey(format) {
|
|
21364
|
+
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
21365
|
+
}
|
|
21366
|
+
function parseMeshCoordinatorMcpConfig(text, format) {
|
|
21367
|
+
if (!text.trim()) return {};
|
|
21368
|
+
if (format === "claude_mcp_json") return JSON.parse(text);
|
|
21369
|
+
const parsed = loadYamlModule().load(text);
|
|
21370
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
21371
|
+
}
|
|
21372
|
+
function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
21373
|
+
if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
|
|
21374
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
21375
|
+
}
|
|
20806
21376
|
var CHAT_COMMANDS = [
|
|
20807
21377
|
"send_chat",
|
|
20808
21378
|
"new_chat",
|
|
@@ -20901,6 +21471,109 @@ var DaemonCommandRouter = class {
|
|
|
20901
21471
|
constructor(deps) {
|
|
20902
21472
|
this.deps = deps;
|
|
20903
21473
|
}
|
|
21474
|
+
getCachedInlineMesh(meshId, inlineMesh) {
|
|
21475
|
+
if (inlineMesh && typeof inlineMesh === "object") {
|
|
21476
|
+
this.inlineMeshCache.set(meshId, inlineMesh);
|
|
21477
|
+
return inlineMesh;
|
|
21478
|
+
}
|
|
21479
|
+
return this.inlineMeshCache.get(meshId);
|
|
21480
|
+
}
|
|
21481
|
+
async getMeshForCommand(meshId, inlineMesh) {
|
|
21482
|
+
try {
|
|
21483
|
+
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21484
|
+
const mesh = getMesh3(meshId);
|
|
21485
|
+
if (mesh) return { mesh, inline: false };
|
|
21486
|
+
} catch {
|
|
21487
|
+
}
|
|
21488
|
+
const cached = this.getCachedInlineMesh(meshId, inlineMesh);
|
|
21489
|
+
return cached ? { mesh: cached, inline: true } : null;
|
|
21490
|
+
}
|
|
21491
|
+
updateInlineMeshNode(meshId, mesh, node) {
|
|
21492
|
+
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
21493
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
21494
|
+
if (idx >= 0) mesh.nodes[idx] = node;
|
|
21495
|
+
else mesh.nodes.push(node);
|
|
21496
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21497
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21498
|
+
}
|
|
21499
|
+
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
21500
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
21501
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
|
|
21502
|
+
if (idx === -1) return false;
|
|
21503
|
+
mesh.nodes.splice(idx, 1);
|
|
21504
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21505
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21506
|
+
return true;
|
|
21507
|
+
}
|
|
21508
|
+
normalizeMeshSessionCleanupMode(value) {
|
|
21509
|
+
return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
|
|
21510
|
+
}
|
|
21511
|
+
sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
|
|
21512
|
+
const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
|
|
21513
|
+
if (!sessionId) return false;
|
|
21514
|
+
if (sessionIds?.size) return sessionIds.has(sessionId);
|
|
21515
|
+
const workspace = typeof node?.workspace === "string" ? node.workspace : "";
|
|
21516
|
+
if (workspace && record?.workspace === workspace) return true;
|
|
21517
|
+
if (record?.meta?.meshNodeId === nodeId) return true;
|
|
21518
|
+
return false;
|
|
21519
|
+
}
|
|
21520
|
+
isCompletedHostedSession(record) {
|
|
21521
|
+
return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
|
|
21522
|
+
}
|
|
21523
|
+
async cleanupMeshSessions(args) {
|
|
21524
|
+
if (args.mode === "preserve") {
|
|
21525
|
+
return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
|
|
21526
|
+
}
|
|
21527
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
21528
|
+
const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
|
|
21529
|
+
const sessions = await this.deps.sessionHostControl.listSessions();
|
|
21530
|
+
const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
|
|
21531
|
+
const stoppedSessionIds = [];
|
|
21532
|
+
const deletedSessionIds = [];
|
|
21533
|
+
const skippedSessionIds = [];
|
|
21534
|
+
const errors = [];
|
|
21535
|
+
for (const record of matched) {
|
|
21536
|
+
const sessionId = String(record.sessionId);
|
|
21537
|
+
const completed = this.isCompletedHostedSession(record);
|
|
21538
|
+
try {
|
|
21539
|
+
if (args.mode === "stop") {
|
|
21540
|
+
if (!completed) {
|
|
21541
|
+
if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21542
|
+
stoppedSessionIds.push(sessionId);
|
|
21543
|
+
} else {
|
|
21544
|
+
skippedSessionIds.push(sessionId);
|
|
21545
|
+
}
|
|
21546
|
+
continue;
|
|
21547
|
+
}
|
|
21548
|
+
if (args.mode === "delete_stopped") {
|
|
21549
|
+
if (completed) {
|
|
21550
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
|
|
21551
|
+
deletedSessionIds.push(sessionId);
|
|
21552
|
+
} else {
|
|
21553
|
+
skippedSessionIds.push(sessionId);
|
|
21554
|
+
}
|
|
21555
|
+
continue;
|
|
21556
|
+
}
|
|
21557
|
+
if (args.mode === "stop_and_delete") {
|
|
21558
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
|
|
21559
|
+
deletedSessionIds.push(sessionId);
|
|
21560
|
+
continue;
|
|
21561
|
+
}
|
|
21562
|
+
} catch (e) {
|
|
21563
|
+
errors.push({ sessionId, error: e?.message || String(e) });
|
|
21564
|
+
}
|
|
21565
|
+
}
|
|
21566
|
+
return {
|
|
21567
|
+
success: errors.length === 0,
|
|
21568
|
+
mode: args.mode,
|
|
21569
|
+
dryRun: args.dryRun === true,
|
|
21570
|
+
matchedCount: matched.length,
|
|
21571
|
+
stoppedSessionIds,
|
|
21572
|
+
deletedSessionIds,
|
|
21573
|
+
skippedSessionIds,
|
|
21574
|
+
...errors.length ? { errors } : {}
|
|
21575
|
+
};
|
|
21576
|
+
}
|
|
20904
21577
|
async traceSessionHostAction(action, args, run, summarizeResult) {
|
|
20905
21578
|
const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
|
|
20906
21579
|
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -21020,6 +21693,9 @@ var DaemonCommandRouter = class {
|
|
|
21020
21693
|
async executeDaemonCommand(cmd, args) {
|
|
21021
21694
|
switch (cmd) {
|
|
21022
21695
|
// ─── CLI / ACP commands ───
|
|
21696
|
+
case "mesh_forward_event": {
|
|
21697
|
+
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
21698
|
+
}
|
|
21023
21699
|
case "launch_cli":
|
|
21024
21700
|
case "stop_cli":
|
|
21025
21701
|
case "set_cli_view_mode":
|
|
@@ -21564,7 +22240,26 @@ var DaemonCommandRouter = class {
|
|
|
21564
22240
|
if (!name) return { success: false, error: "name required" };
|
|
21565
22241
|
try {
|
|
21566
22242
|
const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21567
|
-
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
|
|
22243
|
+
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
|
|
22244
|
+
return { success: true, mesh };
|
|
22245
|
+
} catch (e) {
|
|
22246
|
+
return { success: false, error: e.message };
|
|
22247
|
+
}
|
|
22248
|
+
}
|
|
22249
|
+
case "update_mesh": {
|
|
22250
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22251
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22252
|
+
try {
|
|
22253
|
+
const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22254
|
+
const patch = {};
|
|
22255
|
+
if (typeof args?.name === "string") patch.name = args.name;
|
|
22256
|
+
if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
|
|
22257
|
+
if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
|
|
22258
|
+
if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
|
|
22259
|
+
if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
|
|
22260
|
+
const mesh = updateMesh2(meshId, patch);
|
|
22261
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22262
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21568
22263
|
return { success: true, mesh };
|
|
21569
22264
|
} catch (e) {
|
|
21570
22265
|
return { success: false, error: e.message };
|
|
@@ -21588,21 +22283,164 @@ var DaemonCommandRouter = class {
|
|
|
21588
22283
|
if (!workspace) return { success: false, error: "workspace required" };
|
|
21589
22284
|
try {
|
|
21590
22285
|
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21591
|
-
const
|
|
22286
|
+
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
22287
|
+
const readOnly = args?.readOnly === true;
|
|
22288
|
+
const policy = {
|
|
22289
|
+
...readOnly ? { readOnly: true } : {},
|
|
22290
|
+
...providerPriority.length ? { providerPriority } : {}
|
|
22291
|
+
};
|
|
22292
|
+
const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
|
|
21592
22293
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
21593
22294
|
return { success: true, node };
|
|
21594
22295
|
} catch (e) {
|
|
21595
22296
|
return { success: false, error: e.message };
|
|
21596
22297
|
}
|
|
21597
22298
|
}
|
|
22299
|
+
case "update_mesh_node": {
|
|
22300
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22301
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22302
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22303
|
+
try {
|
|
22304
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22305
|
+
const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
|
|
22306
|
+
if (Array.isArray(args?.providerPriority)) {
|
|
22307
|
+
const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
|
|
22308
|
+
delete policy.provider_priority;
|
|
22309
|
+
if (providerPriority.length) {
|
|
22310
|
+
policy.providerPriority = providerPriority;
|
|
22311
|
+
} else {
|
|
22312
|
+
delete policy.providerPriority;
|
|
22313
|
+
}
|
|
22314
|
+
}
|
|
22315
|
+
const node = updateNode2(meshId, nodeId, { policy });
|
|
22316
|
+
if (!node) return { success: false, error: "Mesh node not found" };
|
|
22317
|
+
return { success: true, node };
|
|
22318
|
+
} catch (e) {
|
|
22319
|
+
return { success: false, error: e.message };
|
|
22320
|
+
}
|
|
22321
|
+
}
|
|
22322
|
+
case "cleanup_mesh_sessions": {
|
|
22323
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22324
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22325
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22326
|
+
try {
|
|
22327
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22328
|
+
const mesh = meshRecord?.mesh;
|
|
22329
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22330
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22331
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
22332
|
+
const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
|
|
22333
|
+
const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
|
|
22334
|
+
const result = await this.cleanupMeshSessions({
|
|
22335
|
+
meshId,
|
|
22336
|
+
nodeId,
|
|
22337
|
+
node,
|
|
22338
|
+
mode,
|
|
22339
|
+
sessionIds,
|
|
22340
|
+
dryRun: args?.dryRun === true
|
|
22341
|
+
});
|
|
22342
|
+
return result;
|
|
22343
|
+
} catch (e) {
|
|
22344
|
+
return { success: false, error: e.message };
|
|
22345
|
+
}
|
|
22346
|
+
}
|
|
21598
22347
|
case "remove_mesh_node": {
|
|
21599
22348
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21600
22349
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
21601
22350
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
21602
22351
|
try {
|
|
21603
|
-
const
|
|
21604
|
-
const
|
|
21605
|
-
|
|
22352
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22353
|
+
const mesh = meshRecord?.mesh;
|
|
22354
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22355
|
+
const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
|
|
22356
|
+
args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
|
|
22357
|
+
);
|
|
22358
|
+
let sessionCleanup;
|
|
22359
|
+
if (node && sessionCleanupMode !== "preserve") {
|
|
22360
|
+
sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
|
|
22361
|
+
if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
|
|
22362
|
+
}
|
|
22363
|
+
if (node?.isLocalWorktree && node.workspace) {
|
|
22364
|
+
try {
|
|
22365
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
22366
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
22367
|
+
if (repoRoot) {
|
|
22368
|
+
const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22369
|
+
await removeWorktree2(repoRoot, node.workspace);
|
|
22370
|
+
}
|
|
22371
|
+
} catch (e) {
|
|
22372
|
+
LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
|
|
22373
|
+
}
|
|
22374
|
+
}
|
|
22375
|
+
let removed = false;
|
|
22376
|
+
if (meshRecord?.inline) {
|
|
22377
|
+
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
22378
|
+
} else {
|
|
22379
|
+
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22380
|
+
removed = removeNode3(meshId, nodeId);
|
|
22381
|
+
}
|
|
22382
|
+
return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
|
|
22383
|
+
} catch (e) {
|
|
22384
|
+
return { success: false, error: e.message };
|
|
22385
|
+
}
|
|
22386
|
+
}
|
|
22387
|
+
case "clone_mesh_node": {
|
|
22388
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22389
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
22390
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
22391
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
22392
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22393
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
22394
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
22395
|
+
try {
|
|
22396
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22397
|
+
const mesh = meshRecord?.mesh;
|
|
22398
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22399
|
+
const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
|
|
22400
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
22401
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
22402
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22403
|
+
const result = await createWorktree2({
|
|
22404
|
+
repoRoot,
|
|
22405
|
+
branch,
|
|
22406
|
+
baseBranch,
|
|
22407
|
+
meshName: mesh.name
|
|
22408
|
+
});
|
|
22409
|
+
let node;
|
|
22410
|
+
if (meshRecord.inline) {
|
|
22411
|
+
const { randomUUID: randomUUID8 } = await import("crypto");
|
|
22412
|
+
node = {
|
|
22413
|
+
id: `node_${randomUUID8().replace(/-/g, "")}`,
|
|
22414
|
+
workspace: result.worktreePath,
|
|
22415
|
+
repoRoot: result.worktreePath,
|
|
22416
|
+
daemonId: sourceNode.daemonId,
|
|
22417
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22418
|
+
policy: { ...sourceNode.policy || {} },
|
|
22419
|
+
isLocalWorktree: true,
|
|
22420
|
+
worktreeBranch: result.branch,
|
|
22421
|
+
clonedFromNodeId: sourceNodeId
|
|
22422
|
+
};
|
|
22423
|
+
this.updateInlineMeshNode(meshId, mesh, node);
|
|
22424
|
+
} else {
|
|
22425
|
+
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22426
|
+
node = addNode3(meshId, {
|
|
22427
|
+
workspace: result.worktreePath,
|
|
22428
|
+
repoRoot: result.worktreePath,
|
|
22429
|
+
daemonId: sourceNode.daemonId,
|
|
22430
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22431
|
+
isLocalWorktree: true,
|
|
22432
|
+
worktreeBranch: result.branch,
|
|
22433
|
+
clonedFromNodeId: sourceNodeId,
|
|
22434
|
+
policy: { ...sourceNode.policy || {} }
|
|
22435
|
+
});
|
|
22436
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
22437
|
+
}
|
|
22438
|
+
return {
|
|
22439
|
+
success: true,
|
|
22440
|
+
node,
|
|
22441
|
+
worktreePath: result.worktreePath,
|
|
22442
|
+
branch: result.branch
|
|
22443
|
+
};
|
|
21606
22444
|
} catch (e) {
|
|
21607
22445
|
return { success: false, error: e.message };
|
|
21608
22446
|
}
|
|
@@ -21610,7 +22448,7 @@ var DaemonCommandRouter = class {
|
|
|
21610
22448
|
// ─── Mesh Coordinator Launch ───
|
|
21611
22449
|
case "launch_mesh_coordinator": {
|
|
21612
22450
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21613
|
-
|
|
22451
|
+
let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
|
|
21614
22452
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
21615
22453
|
try {
|
|
21616
22454
|
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
@@ -21638,9 +22476,29 @@ var DaemonCommandRouter = class {
|
|
|
21638
22476
|
}
|
|
21639
22477
|
const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
|
|
21640
22478
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
22479
|
+
if (!cliType) {
|
|
22480
|
+
const resolved = await resolveProviderTypeFromPriority({
|
|
22481
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
|
|
22482
|
+
providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
|
|
22483
|
+
providerLoader: this.deps.providerLoader,
|
|
22484
|
+
onStatusChange: this.deps.onStatusChange
|
|
22485
|
+
});
|
|
22486
|
+
if (!resolved.providerType) {
|
|
22487
|
+
return {
|
|
22488
|
+
success: false,
|
|
22489
|
+
code: "mesh_coordinator_provider_priority_unusable",
|
|
22490
|
+
error: resolved.error || "No usable provider found from node providerPriority",
|
|
22491
|
+
meshId,
|
|
22492
|
+
cliType,
|
|
22493
|
+
workspace
|
|
22494
|
+
};
|
|
22495
|
+
}
|
|
22496
|
+
cliType = resolved.providerType;
|
|
22497
|
+
}
|
|
21641
22498
|
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
21642
22499
|
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
21643
22500
|
provider: providerMeta,
|
|
22501
|
+
cliType,
|
|
21644
22502
|
meshId,
|
|
21645
22503
|
workspace
|
|
21646
22504
|
});
|
|
@@ -21665,7 +22523,8 @@ var DaemonCommandRouter = class {
|
|
|
21665
22523
|
meshCoordinatorSetup: coordinatorSetup
|
|
21666
22524
|
};
|
|
21667
22525
|
}
|
|
21668
|
-
|
|
22526
|
+
const configFormat = coordinatorSetup.configFormat;
|
|
22527
|
+
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
21669
22528
|
return {
|
|
21670
22529
|
success: false,
|
|
21671
22530
|
code: "mesh_coordinator_unsupported",
|
|
@@ -21675,44 +22534,93 @@ var DaemonCommandRouter = class {
|
|
|
21675
22534
|
workspace
|
|
21676
22535
|
};
|
|
21677
22536
|
}
|
|
21678
|
-
|
|
21679
|
-
|
|
21680
|
-
|
|
21681
|
-
|
|
21682
|
-
|
|
21683
|
-
|
|
21684
|
-
|
|
21685
|
-
|
|
21686
|
-
|
|
21687
|
-
|
|
22537
|
+
let systemPrompt = "";
|
|
22538
|
+
try {
|
|
22539
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
22540
|
+
} catch (error) {
|
|
22541
|
+
const message = error?.message || String(error);
|
|
22542
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
22543
|
+
return {
|
|
22544
|
+
success: false,
|
|
22545
|
+
code: "mesh_coordinator_prompt_failed",
|
|
22546
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
22547
|
+
meshId,
|
|
22548
|
+
cliType,
|
|
22549
|
+
workspace
|
|
22550
|
+
};
|
|
21688
22551
|
}
|
|
22552
|
+
const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
|
|
22553
|
+
const { dirname: dirname9 } = await import("path");
|
|
22554
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
22555
|
+
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
22556
|
+
const returnManualFallback = (message) => ({
|
|
22557
|
+
success: false,
|
|
22558
|
+
code: "mesh_coordinator_manual_mcp_setup_required",
|
|
22559
|
+
error: message,
|
|
22560
|
+
meshId,
|
|
22561
|
+
cliType,
|
|
22562
|
+
workspace,
|
|
22563
|
+
meshCoordinatorSetup: hermesManualFallback
|
|
22564
|
+
});
|
|
21689
22565
|
const mcpServerEntry = {
|
|
21690
22566
|
command: coordinatorSetup.mcpServer.command,
|
|
21691
22567
|
args: coordinatorSetup.mcpServer.args
|
|
21692
22568
|
};
|
|
21693
22569
|
if (args?.inlineMesh) {
|
|
21694
22570
|
mcpServerEntry.env = {
|
|
21695
|
-
ADHDEV_INLINE_MESH: JSON.stringify(mesh)
|
|
22571
|
+
ADHDEV_INLINE_MESH: JSON.stringify(mesh),
|
|
22572
|
+
ADHDEV_MCP_TRANSPORT: "ipc"
|
|
21696
22573
|
};
|
|
21697
22574
|
}
|
|
22575
|
+
try {
|
|
22576
|
+
mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
|
|
22577
|
+
} catch (error) {
|
|
22578
|
+
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
22579
|
+
LOG.error("MeshCoordinator", message);
|
|
22580
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22581
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
22582
|
+
}
|
|
22583
|
+
const hadExistingMcpConfig = existsSync23(mcpConfigPath);
|
|
22584
|
+
let existingMcpConfig = {};
|
|
22585
|
+
if (hadExistingMcpConfig) {
|
|
22586
|
+
try {
|
|
22587
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
|
|
22588
|
+
copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
|
|
22589
|
+
} catch (error) {
|
|
22590
|
+
LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
22591
|
+
return {
|
|
22592
|
+
success: false,
|
|
22593
|
+
code: "mesh_coordinator_config_parse_failed",
|
|
22594
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`
|
|
22595
|
+
};
|
|
22596
|
+
}
|
|
22597
|
+
}
|
|
22598
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
22599
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
21698
22600
|
const mcpConfig = {
|
|
21699
22601
|
...existingMcpConfig,
|
|
21700
|
-
|
|
21701
|
-
...
|
|
22602
|
+
[mcpServersKey]: {
|
|
22603
|
+
...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
|
|
21702
22604
|
[coordinatorSetup.serverName]: mcpServerEntry
|
|
21703
22605
|
}
|
|
21704
22606
|
};
|
|
21705
|
-
writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
21706
|
-
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21707
|
-
let systemPrompt = "";
|
|
21708
22607
|
try {
|
|
21709
|
-
|
|
21710
|
-
} catch {
|
|
21711
|
-
|
|
22608
|
+
writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
22609
|
+
} catch (error) {
|
|
22610
|
+
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
22611
|
+
LOG.error("MeshCoordinator", message);
|
|
22612
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22613
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21712
22614
|
}
|
|
22615
|
+
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21713
22616
|
const cliArgs = [];
|
|
22617
|
+
const launchEnv = {};
|
|
21714
22618
|
if (systemPrompt) {
|
|
21715
|
-
|
|
22619
|
+
if (configFormat === "hermes_config_yaml") {
|
|
22620
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
22621
|
+
} else {
|
|
22622
|
+
cliArgs.push("--append-system-prompt", systemPrompt);
|
|
22623
|
+
}
|
|
21716
22624
|
}
|
|
21717
22625
|
if (cliType === "claude-cli") {
|
|
21718
22626
|
cliArgs.push("--mcp-config", coordinatorSetup.configPath);
|
|
@@ -21721,6 +22629,7 @@ var DaemonCommandRouter = class {
|
|
|
21721
22629
|
cliType,
|
|
21722
22630
|
dir: workspace,
|
|
21723
22631
|
cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
|
|
22632
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
21724
22633
|
settings: {
|
|
21725
22634
|
meshCoordinatorFor: meshId
|
|
21726
22635
|
}
|
|
@@ -21900,6 +22809,12 @@ var DaemonStatusReporter = class {
|
|
|
21900
22809
|
if (providerType) {
|
|
21901
22810
|
payload.providerType = providerType;
|
|
21902
22811
|
}
|
|
22812
|
+
if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
|
|
22813
|
+
payload.providerSessionId = event.providerSessionId.trim();
|
|
22814
|
+
}
|
|
22815
|
+
if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
|
|
22816
|
+
payload.workspaceName = event.workspaceName.trim();
|
|
22817
|
+
}
|
|
21903
22818
|
if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
|
|
21904
22819
|
payload.duration = event.duration;
|
|
21905
22820
|
}
|
|
@@ -23147,7 +24062,10 @@ var ProviderInstanceManager = class {
|
|
|
23147
24062
|
this.instances.get(id).dispose();
|
|
23148
24063
|
}
|
|
23149
24064
|
this.instances.set(id, instance);
|
|
23150
|
-
await instance.init(
|
|
24065
|
+
await instance.init({
|
|
24066
|
+
...context,
|
|
24067
|
+
emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
|
|
24068
|
+
});
|
|
23151
24069
|
}
|
|
23152
24070
|
/**
|
|
23153
24071
|
* Instance remove
|
|
@@ -23309,6 +24227,17 @@ var ProviderInstanceManager = class {
|
|
|
23309
24227
|
onEvent(listener) {
|
|
23310
24228
|
this.eventListeners.push(listener);
|
|
23311
24229
|
}
|
|
24230
|
+
emitProviderEvent(providerType, instanceId, event) {
|
|
24231
|
+
const payload = {
|
|
24232
|
+
...event,
|
|
24233
|
+
providerType,
|
|
24234
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
|
|
24235
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
|
|
24236
|
+
};
|
|
24237
|
+
for (const listener of this.eventListeners) {
|
|
24238
|
+
listener(payload);
|
|
24239
|
+
}
|
|
24240
|
+
}
|
|
23312
24241
|
emitPendingEvents(providerType, state, extra = {}) {
|
|
23313
24242
|
for (const event of state.pendingEvents) {
|
|
23314
24243
|
for (const listener of this.eventListeners) {
|
|
@@ -23381,11 +24310,11 @@ var ProviderInstanceManager = class {
|
|
|
23381
24310
|
|
|
23382
24311
|
// src/providers/version-archive.ts
|
|
23383
24312
|
var fs11 = __toESM(require("fs"));
|
|
23384
|
-
var
|
|
23385
|
-
var
|
|
24313
|
+
var path22 = __toESM(require("path"));
|
|
24314
|
+
var os20 = __toESM(require("os"));
|
|
23386
24315
|
var import_child_process10 = require("child_process");
|
|
23387
24316
|
var import_os3 = require("os");
|
|
23388
|
-
var ARCHIVE_PATH =
|
|
24317
|
+
var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
|
|
23389
24318
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
23390
24319
|
var VersionArchive = class {
|
|
23391
24320
|
history = {};
|
|
@@ -23432,7 +24361,7 @@ var VersionArchive = class {
|
|
|
23432
24361
|
}
|
|
23433
24362
|
save() {
|
|
23434
24363
|
try {
|
|
23435
|
-
fs11.mkdirSync(
|
|
24364
|
+
fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
|
|
23436
24365
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
23437
24366
|
} catch {
|
|
23438
24367
|
}
|
|
@@ -23488,8 +24417,8 @@ function getVersion(binary, versionCommand) {
|
|
|
23488
24417
|
function checkPathExists2(paths) {
|
|
23489
24418
|
for (const p of paths) {
|
|
23490
24419
|
if (p.includes("*")) {
|
|
23491
|
-
const home =
|
|
23492
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
24420
|
+
const home = os20.homedir();
|
|
24421
|
+
const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
|
|
23493
24422
|
if (fs11.existsSync(resolved)) return resolved;
|
|
23494
24423
|
} else {
|
|
23495
24424
|
if (fs11.existsSync(p)) return p;
|
|
@@ -23499,7 +24428,7 @@ function checkPathExists2(paths) {
|
|
|
23499
24428
|
}
|
|
23500
24429
|
function getMacAppVersion(appPath) {
|
|
23501
24430
|
if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
23502
|
-
const plistPath =
|
|
24431
|
+
const plistPath = path22.join(appPath, "Contents", "Info.plist");
|
|
23503
24432
|
if (!fs11.existsSync(plistPath)) return null;
|
|
23504
24433
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
23505
24434
|
return raw || null;
|
|
@@ -23525,7 +24454,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23525
24454
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
23526
24455
|
let resolvedBin = cliBin;
|
|
23527
24456
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
23528
|
-
const bundled =
|
|
24457
|
+
const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
23529
24458
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
23530
24459
|
}
|
|
23531
24460
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -23566,7 +24495,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23566
24495
|
// src/daemon/dev-server.ts
|
|
23567
24496
|
var http2 = __toESM(require("http"));
|
|
23568
24497
|
var fs15 = __toESM(require("fs"));
|
|
23569
|
-
var
|
|
24498
|
+
var path26 = __toESM(require("path"));
|
|
23570
24499
|
init_config();
|
|
23571
24500
|
|
|
23572
24501
|
// src/daemon/scaffold-template.ts
|
|
@@ -23917,7 +24846,7 @@ init_logger();
|
|
|
23917
24846
|
|
|
23918
24847
|
// src/daemon/dev-cdp-handlers.ts
|
|
23919
24848
|
var fs12 = __toESM(require("fs"));
|
|
23920
|
-
var
|
|
24849
|
+
var path23 = __toESM(require("path"));
|
|
23921
24850
|
init_logger();
|
|
23922
24851
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
23923
24852
|
const body = await ctx.readBody(req);
|
|
@@ -24096,17 +25025,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
24096
25025
|
return;
|
|
24097
25026
|
}
|
|
24098
25027
|
let scriptsPath = "";
|
|
24099
|
-
const directScripts =
|
|
25028
|
+
const directScripts = path23.join(dir, "scripts.js");
|
|
24100
25029
|
if (fs12.existsSync(directScripts)) {
|
|
24101
25030
|
scriptsPath = directScripts;
|
|
24102
25031
|
} else {
|
|
24103
|
-
const scriptsDir =
|
|
25032
|
+
const scriptsDir = path23.join(dir, "scripts");
|
|
24104
25033
|
if (fs12.existsSync(scriptsDir)) {
|
|
24105
25034
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
24106
|
-
return fs12.statSync(
|
|
25035
|
+
return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
|
|
24107
25036
|
}).sort().reverse();
|
|
24108
25037
|
for (const ver of versions) {
|
|
24109
|
-
const p =
|
|
25038
|
+
const p = path23.join(scriptsDir, ver, "scripts.js");
|
|
24110
25039
|
if (fs12.existsSync(p)) {
|
|
24111
25040
|
scriptsPath = p;
|
|
24112
25041
|
break;
|
|
@@ -24935,7 +25864,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
24935
25864
|
|
|
24936
25865
|
// src/daemon/dev-cli-debug.ts
|
|
24937
25866
|
var fs13 = __toESM(require("fs"));
|
|
24938
|
-
var
|
|
25867
|
+
var path24 = __toESM(require("path"));
|
|
24939
25868
|
function slugifyFixtureName(value) {
|
|
24940
25869
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24941
25870
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -24945,11 +25874,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
24945
25874
|
if (!providerDir) {
|
|
24946
25875
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
24947
25876
|
}
|
|
24948
|
-
return
|
|
25877
|
+
return path24.join(providerDir, "fixtures");
|
|
24949
25878
|
}
|
|
24950
25879
|
function readCliFixture(ctx, type, name) {
|
|
24951
25880
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
24952
|
-
const filePath =
|
|
25881
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
24953
25882
|
if (!fs13.existsSync(filePath)) {
|
|
24954
25883
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
24955
25884
|
}
|
|
@@ -25716,7 +26645,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
25716
26645
|
},
|
|
25717
26646
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
25718
26647
|
};
|
|
25719
|
-
const filePath =
|
|
26648
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
25720
26649
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
25721
26650
|
ctx.json(res, 200, {
|
|
25722
26651
|
saved: true,
|
|
@@ -25740,7 +26669,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
25740
26669
|
return;
|
|
25741
26670
|
}
|
|
25742
26671
|
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 =
|
|
26672
|
+
const fullPath = path24.join(fixtureDir, file);
|
|
25744
26673
|
try {
|
|
25745
26674
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
25746
26675
|
return {
|
|
@@ -25876,8 +26805,8 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
25876
26805
|
|
|
25877
26806
|
// src/daemon/dev-auto-implement.ts
|
|
25878
26807
|
var fs14 = __toESM(require("fs"));
|
|
25879
|
-
var
|
|
25880
|
-
var
|
|
26808
|
+
var path25 = __toESM(require("path"));
|
|
26809
|
+
var os21 = __toESM(require("os"));
|
|
25881
26810
|
function getAutoImplPid(ctx) {
|
|
25882
26811
|
const pid = ctx.autoImplProcess?.pid;
|
|
25883
26812
|
return typeof pid === "number" && pid > 0 ? pid : null;
|
|
@@ -25926,22 +26855,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
25926
26855
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
25927
26856
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
25928
26857
|
try {
|
|
25929
|
-
return fs14.statSync(
|
|
26858
|
+
return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
25930
26859
|
} catch {
|
|
25931
26860
|
return false;
|
|
25932
26861
|
}
|
|
25933
26862
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
25934
26863
|
if (versions.length === 0) return null;
|
|
25935
|
-
return
|
|
26864
|
+
return path25.join(scriptsDir, versions[0]);
|
|
25936
26865
|
}
|
|
25937
26866
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
25938
|
-
const canonicalUserDir =
|
|
25939
|
-
const desiredDir = requestedDir ?
|
|
25940
|
-
const upstreamRoot =
|
|
25941
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
26867
|
+
const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
26868
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
26869
|
+
const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
|
|
26870
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
25942
26871
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
25943
26872
|
}
|
|
25944
|
-
if (
|
|
26873
|
+
if (path25.basename(desiredDir) !== type) {
|
|
25945
26874
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
25946
26875
|
}
|
|
25947
26876
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -25949,11 +26878,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
25949
26878
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
25950
26879
|
}
|
|
25951
26880
|
if (!fs14.existsSync(desiredDir)) {
|
|
25952
|
-
fs14.mkdirSync(
|
|
26881
|
+
fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
25953
26882
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
25954
26883
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
25955
26884
|
}
|
|
25956
|
-
const providerJson =
|
|
26885
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
25957
26886
|
if (!fs14.existsSync(providerJson)) {
|
|
25958
26887
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
25959
26888
|
}
|
|
@@ -25964,13 +26893,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
25964
26893
|
const refDir = ctx.findProviderDir(referenceType);
|
|
25965
26894
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
25966
26895
|
const referenceScripts = {};
|
|
25967
|
-
const scriptsDir =
|
|
26896
|
+
const scriptsDir = path25.join(refDir, "scripts");
|
|
25968
26897
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
25969
26898
|
if (!latestDir) return referenceScripts;
|
|
25970
26899
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
25971
26900
|
if (!file.endsWith(".js")) continue;
|
|
25972
26901
|
try {
|
|
25973
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
26902
|
+
referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
|
|
25974
26903
|
} catch {
|
|
25975
26904
|
}
|
|
25976
26905
|
}
|
|
@@ -26078,9 +27007,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26078
27007
|
});
|
|
26079
27008
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
26080
27009
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
26081
|
-
const tmpDir =
|
|
27010
|
+
const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
|
|
26082
27011
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
26083
|
-
const promptFile =
|
|
27012
|
+
const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
26084
27013
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
26085
27014
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
26086
27015
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -26233,7 +27162,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26233
27162
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
26234
27163
|
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
26235
27164
|
let shellCmd;
|
|
26236
|
-
const isWin =
|
|
27165
|
+
const isWin = os21.platform() === "win32";
|
|
26237
27166
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
26238
27167
|
const promptMode = autoImpl?.promptMode ?? "stdin";
|
|
26239
27168
|
const extraArgs = autoImpl?.extraArgs ?? [];
|
|
@@ -26272,7 +27201,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26272
27201
|
try {
|
|
26273
27202
|
const pty = require("node-pty");
|
|
26274
27203
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
26275
|
-
const isWin2 =
|
|
27204
|
+
const isWin2 = os21.platform() === "win32";
|
|
26276
27205
|
child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
26277
27206
|
name: "xterm-256color",
|
|
26278
27207
|
cols: 120,
|
|
@@ -26512,7 +27441,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26512
27441
|
setMode: "set_mode.js"
|
|
26513
27442
|
};
|
|
26514
27443
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26515
|
-
const scriptsDir =
|
|
27444
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26516
27445
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26517
27446
|
if (latestScriptsDir) {
|
|
26518
27447
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26523,7 +27452,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26523
27452
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
26524
27453
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26525
27454
|
try {
|
|
26526
|
-
const content = fs14.readFileSync(
|
|
27455
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26527
27456
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26528
27457
|
lines.push("```javascript");
|
|
26529
27458
|
lines.push(content);
|
|
@@ -26540,7 +27469,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26540
27469
|
lines.push("");
|
|
26541
27470
|
for (const file of refFiles) {
|
|
26542
27471
|
try {
|
|
26543
|
-
const content = fs14.readFileSync(
|
|
27472
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26544
27473
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26545
27474
|
lines.push("```javascript");
|
|
26546
27475
|
lines.push(content);
|
|
@@ -26581,10 +27510,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26581
27510
|
lines.push("");
|
|
26582
27511
|
}
|
|
26583
27512
|
}
|
|
26584
|
-
const docsDir =
|
|
27513
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26585
27514
|
const loadGuide = (name) => {
|
|
26586
27515
|
try {
|
|
26587
|
-
const p =
|
|
27516
|
+
const p = path25.join(docsDir, name);
|
|
26588
27517
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26589
27518
|
} catch {
|
|
26590
27519
|
}
|
|
@@ -26821,7 +27750,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26821
27750
|
parseApproval: "parse_approval.js"
|
|
26822
27751
|
};
|
|
26823
27752
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26824
|
-
const scriptsDir =
|
|
27753
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26825
27754
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26826
27755
|
if (latestScriptsDir) {
|
|
26827
27756
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26833,7 +27762,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26833
27762
|
if (!file.endsWith(".js")) continue;
|
|
26834
27763
|
if (!targetFileNames.has(file)) continue;
|
|
26835
27764
|
try {
|
|
26836
|
-
const content = fs14.readFileSync(
|
|
27765
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26837
27766
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26838
27767
|
lines.push("```javascript");
|
|
26839
27768
|
lines.push(content);
|
|
@@ -26849,7 +27778,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26849
27778
|
lines.push("");
|
|
26850
27779
|
for (const file of refFiles) {
|
|
26851
27780
|
try {
|
|
26852
|
-
const content = fs14.readFileSync(
|
|
27781
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26853
27782
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26854
27783
|
lines.push("```javascript");
|
|
26855
27784
|
lines.push(content);
|
|
@@ -26882,10 +27811,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26882
27811
|
lines.push("");
|
|
26883
27812
|
}
|
|
26884
27813
|
}
|
|
26885
|
-
const docsDir =
|
|
27814
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26886
27815
|
const loadGuide = (name) => {
|
|
26887
27816
|
try {
|
|
26888
|
-
const p =
|
|
27817
|
+
const p = path25.join(docsDir, name);
|
|
26889
27818
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26890
27819
|
} catch {
|
|
26891
27820
|
}
|
|
@@ -27332,8 +28261,8 @@ var DevServer = class _DevServer {
|
|
|
27332
28261
|
}
|
|
27333
28262
|
getEndpointList() {
|
|
27334
28263
|
return this.routes.map((r) => {
|
|
27335
|
-
const
|
|
27336
|
-
return `${r.method.padEnd(5)} ${
|
|
28264
|
+
const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
28265
|
+
return `${r.method.padEnd(5)} ${path27}`;
|
|
27337
28266
|
});
|
|
27338
28267
|
}
|
|
27339
28268
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -27621,12 +28550,12 @@ var DevServer = class _DevServer {
|
|
|
27621
28550
|
// ─── DevConsole SPA ───
|
|
27622
28551
|
getConsoleDistDir() {
|
|
27623
28552
|
const candidates = [
|
|
27624
|
-
|
|
27625
|
-
|
|
27626
|
-
|
|
28553
|
+
path26.resolve(__dirname, "../../web-devconsole/dist"),
|
|
28554
|
+
path26.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
28555
|
+
path26.join(process.cwd(), "packages/web-devconsole/dist")
|
|
27627
28556
|
];
|
|
27628
28557
|
for (const dir of candidates) {
|
|
27629
|
-
if (fs15.existsSync(
|
|
28558
|
+
if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
|
|
27630
28559
|
}
|
|
27631
28560
|
return null;
|
|
27632
28561
|
}
|
|
@@ -27636,7 +28565,7 @@ var DevServer = class _DevServer {
|
|
|
27636
28565
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
27637
28566
|
return;
|
|
27638
28567
|
}
|
|
27639
|
-
const htmlPath =
|
|
28568
|
+
const htmlPath = path26.join(distDir, "index.html");
|
|
27640
28569
|
try {
|
|
27641
28570
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
27642
28571
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -27661,15 +28590,15 @@ var DevServer = class _DevServer {
|
|
|
27661
28590
|
this.json(res, 404, { error: "Not found" });
|
|
27662
28591
|
return;
|
|
27663
28592
|
}
|
|
27664
|
-
const safePath =
|
|
27665
|
-
const filePath =
|
|
28593
|
+
const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
|
|
28594
|
+
const filePath = path26.join(distDir, safePath);
|
|
27666
28595
|
if (!filePath.startsWith(distDir)) {
|
|
27667
28596
|
this.json(res, 403, { error: "Forbidden" });
|
|
27668
28597
|
return;
|
|
27669
28598
|
}
|
|
27670
28599
|
try {
|
|
27671
28600
|
const content = fs15.readFileSync(filePath);
|
|
27672
|
-
const ext =
|
|
28601
|
+
const ext = path26.extname(filePath);
|
|
27673
28602
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
27674
28603
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
27675
28604
|
res.end(content);
|
|
@@ -27782,9 +28711,9 @@ var DevServer = class _DevServer {
|
|
|
27782
28711
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27783
28712
|
if (entry.isDirectory()) {
|
|
27784
28713
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
27785
|
-
scan(
|
|
28714
|
+
scan(path26.join(d, entry.name), rel);
|
|
27786
28715
|
} else {
|
|
27787
|
-
const stat2 = fs15.statSync(
|
|
28716
|
+
const stat2 = fs15.statSync(path26.join(d, entry.name));
|
|
27788
28717
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
27789
28718
|
}
|
|
27790
28719
|
}
|
|
@@ -27807,7 +28736,7 @@ var DevServer = class _DevServer {
|
|
|
27807
28736
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27808
28737
|
return;
|
|
27809
28738
|
}
|
|
27810
|
-
const fullPath =
|
|
28739
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27811
28740
|
if (!fullPath.startsWith(dir)) {
|
|
27812
28741
|
this.json(res, 403, { error: "Forbidden" });
|
|
27813
28742
|
return;
|
|
@@ -27832,14 +28761,14 @@ var DevServer = class _DevServer {
|
|
|
27832
28761
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27833
28762
|
return;
|
|
27834
28763
|
}
|
|
27835
|
-
const fullPath =
|
|
28764
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27836
28765
|
if (!fullPath.startsWith(dir)) {
|
|
27837
28766
|
this.json(res, 403, { error: "Forbidden" });
|
|
27838
28767
|
return;
|
|
27839
28768
|
}
|
|
27840
28769
|
try {
|
|
27841
28770
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
27842
|
-
fs15.mkdirSync(
|
|
28771
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27843
28772
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27844
28773
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
27845
28774
|
this.providerLoader.reload();
|
|
@@ -27856,7 +28785,7 @@ var DevServer = class _DevServer {
|
|
|
27856
28785
|
return;
|
|
27857
28786
|
}
|
|
27858
28787
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
27859
|
-
const p =
|
|
28788
|
+
const p = path26.join(dir, name);
|
|
27860
28789
|
if (fs15.existsSync(p)) {
|
|
27861
28790
|
const source = fs15.readFileSync(p, "utf-8");
|
|
27862
28791
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -27877,8 +28806,8 @@ var DevServer = class _DevServer {
|
|
|
27877
28806
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
27878
28807
|
return;
|
|
27879
28808
|
}
|
|
27880
|
-
const target = fs15.existsSync(
|
|
27881
|
-
const targetPath =
|
|
28809
|
+
const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
28810
|
+
const targetPath = path26.join(dir, target);
|
|
27882
28811
|
try {
|
|
27883
28812
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
27884
28813
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -28025,7 +28954,7 @@ var DevServer = class _DevServer {
|
|
|
28025
28954
|
}
|
|
28026
28955
|
let targetDir;
|
|
28027
28956
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
28028
|
-
const jsonPath =
|
|
28957
|
+
const jsonPath = path26.join(targetDir, "provider.json");
|
|
28029
28958
|
if (fs15.existsSync(jsonPath)) {
|
|
28030
28959
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
28031
28960
|
return;
|
|
@@ -28037,8 +28966,8 @@ var DevServer = class _DevServer {
|
|
|
28037
28966
|
const createdFiles = ["provider.json"];
|
|
28038
28967
|
if (result.files) {
|
|
28039
28968
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
28040
|
-
const fullPath =
|
|
28041
|
-
fs15.mkdirSync(
|
|
28969
|
+
const fullPath = path26.join(targetDir, relPath);
|
|
28970
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
28042
28971
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
28043
28972
|
createdFiles.push(relPath);
|
|
28044
28973
|
}
|
|
@@ -28091,22 +29020,22 @@ var DevServer = class _DevServer {
|
|
|
28091
29020
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
28092
29021
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
28093
29022
|
try {
|
|
28094
|
-
return fs15.statSync(
|
|
29023
|
+
return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
|
|
28095
29024
|
} catch {
|
|
28096
29025
|
return false;
|
|
28097
29026
|
}
|
|
28098
29027
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
28099
29028
|
if (versions.length === 0) return null;
|
|
28100
|
-
return
|
|
29029
|
+
return path26.join(scriptsDir, versions[0]);
|
|
28101
29030
|
}
|
|
28102
29031
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
28103
|
-
const canonicalUserDir =
|
|
28104
|
-
const desiredDir = requestedDir ?
|
|
28105
|
-
const upstreamRoot =
|
|
28106
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
29032
|
+
const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
29033
|
+
const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
|
|
29034
|
+
const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
|
|
29035
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
|
|
28107
29036
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
28108
29037
|
}
|
|
28109
|
-
if (
|
|
29038
|
+
if (path26.basename(desiredDir) !== type) {
|
|
28110
29039
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
28111
29040
|
}
|
|
28112
29041
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -28114,11 +29043,11 @@ var DevServer = class _DevServer {
|
|
|
28114
29043
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
28115
29044
|
}
|
|
28116
29045
|
if (!fs15.existsSync(desiredDir)) {
|
|
28117
|
-
fs15.mkdirSync(
|
|
29046
|
+
fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
|
|
28118
29047
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
28119
29048
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
28120
29049
|
}
|
|
28121
|
-
const providerJson =
|
|
29050
|
+
const providerJson = path26.join(desiredDir, "provider.json");
|
|
28122
29051
|
if (!fs15.existsSync(providerJson)) {
|
|
28123
29052
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
28124
29053
|
}
|
|
@@ -28154,7 +29083,7 @@ var DevServer = class _DevServer {
|
|
|
28154
29083
|
setMode: "set_mode.js"
|
|
28155
29084
|
};
|
|
28156
29085
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28157
|
-
const scriptsDir =
|
|
29086
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28158
29087
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28159
29088
|
if (latestScriptsDir) {
|
|
28160
29089
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28165,7 +29094,7 @@ var DevServer = class _DevServer {
|
|
|
28165
29094
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
28166
29095
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
28167
29096
|
try {
|
|
28168
|
-
const content = fs15.readFileSync(
|
|
29097
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28169
29098
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28170
29099
|
lines.push("```javascript");
|
|
28171
29100
|
lines.push(content);
|
|
@@ -28182,7 +29111,7 @@ var DevServer = class _DevServer {
|
|
|
28182
29111
|
lines.push("");
|
|
28183
29112
|
for (const file of refFiles) {
|
|
28184
29113
|
try {
|
|
28185
|
-
const content = fs15.readFileSync(
|
|
29114
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28186
29115
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28187
29116
|
lines.push("```javascript");
|
|
28188
29117
|
lines.push(content);
|
|
@@ -28223,10 +29152,10 @@ var DevServer = class _DevServer {
|
|
|
28223
29152
|
lines.push("");
|
|
28224
29153
|
}
|
|
28225
29154
|
}
|
|
28226
|
-
const docsDir =
|
|
29155
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28227
29156
|
const loadGuide = (name) => {
|
|
28228
29157
|
try {
|
|
28229
|
-
const p =
|
|
29158
|
+
const p = path26.join(docsDir, name);
|
|
28230
29159
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28231
29160
|
} catch {
|
|
28232
29161
|
}
|
|
@@ -28400,7 +29329,7 @@ var DevServer = class _DevServer {
|
|
|
28400
29329
|
parseApproval: "parse_approval.js"
|
|
28401
29330
|
};
|
|
28402
29331
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28403
|
-
const scriptsDir =
|
|
29332
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28404
29333
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28405
29334
|
if (latestScriptsDir) {
|
|
28406
29335
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28412,7 +29341,7 @@ var DevServer = class _DevServer {
|
|
|
28412
29341
|
if (!file.endsWith(".js")) continue;
|
|
28413
29342
|
if (!targetFileNames.has(file)) continue;
|
|
28414
29343
|
try {
|
|
28415
|
-
const content = fs15.readFileSync(
|
|
29344
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28416
29345
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28417
29346
|
lines.push("```javascript");
|
|
28418
29347
|
lines.push(content);
|
|
@@ -28428,7 +29357,7 @@ var DevServer = class _DevServer {
|
|
|
28428
29357
|
lines.push("");
|
|
28429
29358
|
for (const file of refFiles) {
|
|
28430
29359
|
try {
|
|
28431
|
-
const content = fs15.readFileSync(
|
|
29360
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28432
29361
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28433
29362
|
lines.push("```javascript");
|
|
28434
29363
|
lines.push(content);
|
|
@@ -28461,10 +29390,10 @@ var DevServer = class _DevServer {
|
|
|
28461
29390
|
lines.push("");
|
|
28462
29391
|
}
|
|
28463
29392
|
}
|
|
28464
|
-
const docsDir =
|
|
29393
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28465
29394
|
const loadGuide = (name) => {
|
|
28466
29395
|
try {
|
|
28467
|
-
const p =
|
|
29396
|
+
const p = path26.join(docsDir, name);
|
|
28468
29397
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28469
29398
|
} catch {
|
|
28470
29399
|
}
|
|
@@ -29464,48 +30393,6 @@ var SessionRegistry = class {
|
|
|
29464
30393
|
// src/boot/daemon-lifecycle.ts
|
|
29465
30394
|
init_logger();
|
|
29466
30395
|
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
30396
|
async function initDaemonComponents(config) {
|
|
29510
30397
|
installGlobalInterceptor();
|
|
29511
30398
|
const appConfig = loadConfig();
|
|
@@ -29812,6 +30699,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29812
30699
|
createGitWorkspaceMonitor,
|
|
29813
30700
|
createInteractionId,
|
|
29814
30701
|
createMesh,
|
|
30702
|
+
createWorktree,
|
|
29815
30703
|
deleteMesh,
|
|
29816
30704
|
detectAllVersions,
|
|
29817
30705
|
detectCLIs,
|
|
@@ -29864,6 +30752,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29864
30752
|
launchWithCdp,
|
|
29865
30753
|
listHostedCliRuntimes,
|
|
29866
30754
|
listMeshes,
|
|
30755
|
+
listWorktrees,
|
|
29867
30756
|
loadConfig,
|
|
29868
30757
|
loadState,
|
|
29869
30758
|
logCommand,
|
|
@@ -29883,6 +30772,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29883
30772
|
normalizeSessionModalFields,
|
|
29884
30773
|
parsePorcelainV2Status,
|
|
29885
30774
|
parseProviderSourceConfigUpdate,
|
|
30775
|
+
parseWorktreeListOutput,
|
|
29886
30776
|
partitionSessionHostDiagnosticsSessions,
|
|
29887
30777
|
partitionSessionHostRecords,
|
|
29888
30778
|
prepareSessionChatTailUpdate,
|
|
@@ -29892,6 +30782,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29892
30782
|
recordDebugTrace,
|
|
29893
30783
|
registerExtensionProviders,
|
|
29894
30784
|
removeNode,
|
|
30785
|
+
removeWorktree,
|
|
29895
30786
|
resetConfig,
|
|
29896
30787
|
resetDebugRuntimeConfig,
|
|
29897
30788
|
resetState,
|
|
@@ -29901,6 +30792,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29901
30792
|
resolveGitRepository,
|
|
29902
30793
|
resolveSessionHostAppName,
|
|
29903
30794
|
resolveSessionHostAppNameResolution,
|
|
30795
|
+
resolveWorktreePath,
|
|
29904
30796
|
runAsyncBatch,
|
|
29905
30797
|
runGit,
|
|
29906
30798
|
saveConfig,
|