@adhdev/daemon-core 0.9.76-rc.5 → 0.9.76-rc.50
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 +1382 -430
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1409 -461
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +1 -0
- package/dist/mesh/mesh-events.d.ts +9 -0
- package/dist/providers/chat-message-normalization.d.ts +11 -0
- package/dist/providers/cli-provider-instance.d.ts +3 -0
- package/dist/providers/provider-instance-manager.d.ts +1 -0
- package/dist/providers/provider-instance.d.ts +2 -0
- package/dist/repo-mesh-types.d.ts +13 -0
- package/dist/shared-types.d.ts +4 -0
- package/package.json +4 -5
- package/src/cli-adapters/provider-cli-adapter.ts +28 -7
- package/src/cli-adapters/provider-cli-runtime.ts +3 -2
- package/src/commands/chat-commands.ts +94 -8
- package/src/commands/cli-manager.ts +78 -5
- package/src/commands/handler.ts +13 -4
- package/src/commands/mesh-coordinator.ts +149 -6
- package/src/commands/router.d.ts +1 -0
- package/src/commands/router.ts +554 -34
- package/src/config/mesh-config.ts +23 -2
- package/src/git/git-commands.ts +5 -1
- package/src/git/git-types.ts +1 -0
- package/src/git/git-worktree.ts +214 -0
- package/src/git/index.ts +14 -0
- package/src/mesh/coordinator-prompt.ts +25 -10
- package/src/mesh/mesh-events.ts +109 -43
- package/src/providers/chat-message-normalization.ts +54 -0
- package/src/providers/cli-provider-instance.d.ts +2 -0
- package/src/providers/cli-provider-instance.ts +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 +4 -0
- package/src/status/builders.ts +17 -12
- package/src/status/reporter.ts +6 -0
package/dist/index.js
CHANGED
|
@@ -41,11 +41,140 @@ var init_repo_mesh_types = __esm({
|
|
|
41
41
|
requireApprovalForPush: true,
|
|
42
42
|
requireApprovalForDestructiveGit: true,
|
|
43
43
|
dirtyWorkspaceBehavior: "warn",
|
|
44
|
-
maxParallelTasks: 2
|
|
44
|
+
maxParallelTasks: 2,
|
|
45
|
+
sessionCleanupOnNodeRemove: "preserve"
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
});
|
|
48
49
|
|
|
50
|
+
// src/git/git-worktree.ts
|
|
51
|
+
var git_worktree_exports = {};
|
|
52
|
+
__export(git_worktree_exports, {
|
|
53
|
+
createWorktree: () => createWorktree,
|
|
54
|
+
listWorktrees: () => listWorktrees,
|
|
55
|
+
parseWorktreeListOutput: () => parseWorktreeListOutput,
|
|
56
|
+
removeWorktree: () => removeWorktree,
|
|
57
|
+
resolveWorktreePath: () => resolveWorktreePath
|
|
58
|
+
});
|
|
59
|
+
function resolveWorktreePath(repoRoot, meshName, branch) {
|
|
60
|
+
const safeBranch = branch.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
|
|
61
|
+
const safeMeshName = meshName.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
|
|
62
|
+
const parentDir = path4.dirname(repoRoot);
|
|
63
|
+
return path4.join(parentDir, WORKTREE_DIR_NAME, safeMeshName, safeBranch);
|
|
64
|
+
}
|
|
65
|
+
async function createWorktree(opts) {
|
|
66
|
+
const { repoRoot, branch, baseBranch, meshName } = opts;
|
|
67
|
+
const targetDir = opts.targetDir || resolveWorktreePath(repoRoot, meshName, branch);
|
|
68
|
+
if ((0, import_node_fs2.existsSync)(targetDir)) {
|
|
69
|
+
throw new Error(`Worktree target directory already exists: ${targetDir}`);
|
|
70
|
+
}
|
|
71
|
+
await (0, import_promises3.mkdir)(path4.dirname(targetDir), { recursive: true });
|
|
72
|
+
const args = ["worktree", "add", targetDir, "-b", branch];
|
|
73
|
+
if (baseBranch) {
|
|
74
|
+
args.push(baseBranch);
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
await execFileAsync2("git", args, {
|
|
78
|
+
cwd: repoRoot,
|
|
79
|
+
encoding: "utf8",
|
|
80
|
+
timeout: GIT_TIMEOUT_MS,
|
|
81
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
82
|
+
windowsHide: true
|
|
83
|
+
});
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const stderr = typeof error.stderr === "string" ? error.stderr : "";
|
|
86
|
+
if (/already exists/i.test(stderr)) {
|
|
87
|
+
throw new Error(`Branch '${branch}' already exists or is checked out in another worktree`);
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`git worktree add failed: ${stderr.trim() || error.message}`);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
worktreePath: targetDir,
|
|
94
|
+
branch
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async function removeWorktree(repoRoot, worktreePath) {
|
|
98
|
+
if (!(0, import_node_fs2.existsSync)(worktreePath)) {
|
|
99
|
+
await pruneWorktrees(repoRoot);
|
|
100
|
+
return { success: true, removedPath: worktreePath };
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
await execFileAsync2("git", ["worktree", "remove", worktreePath, "--force"], {
|
|
104
|
+
cwd: repoRoot,
|
|
105
|
+
encoding: "utf8",
|
|
106
|
+
timeout: GIT_TIMEOUT_MS,
|
|
107
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
108
|
+
windowsHide: true
|
|
109
|
+
});
|
|
110
|
+
} catch (error) {
|
|
111
|
+
const stderr = typeof error.stderr === "string" ? error.stderr : "";
|
|
112
|
+
throw new Error(`git worktree remove failed: ${stderr.trim() || error.message}`);
|
|
113
|
+
}
|
|
114
|
+
return { success: true, removedPath: worktreePath };
|
|
115
|
+
}
|
|
116
|
+
async function listWorktrees(repoRoot) {
|
|
117
|
+
const { stdout } = await execFileAsync2("git", ["worktree", "list", "--porcelain"], {
|
|
118
|
+
cwd: repoRoot,
|
|
119
|
+
encoding: "utf8",
|
|
120
|
+
timeout: GIT_TIMEOUT_MS,
|
|
121
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
122
|
+
windowsHide: true
|
|
123
|
+
});
|
|
124
|
+
return parseWorktreeListOutput(stdout);
|
|
125
|
+
}
|
|
126
|
+
function parseWorktreeListOutput(output) {
|
|
127
|
+
const entries = [];
|
|
128
|
+
const blocks = output.trim().split(/\n\n+/);
|
|
129
|
+
for (const block of blocks) {
|
|
130
|
+
if (!block.trim()) continue;
|
|
131
|
+
const lines = block.trim().split("\n");
|
|
132
|
+
const entry = { path: "", head: "", branch: null, bare: false };
|
|
133
|
+
for (const line of lines) {
|
|
134
|
+
if (line.startsWith("worktree ")) {
|
|
135
|
+
entry.path = line.slice("worktree ".length).trim();
|
|
136
|
+
} else if (line.startsWith("HEAD ")) {
|
|
137
|
+
entry.head = line.slice("HEAD ".length).trim();
|
|
138
|
+
} else if (line.startsWith("branch ")) {
|
|
139
|
+
const ref = line.slice("branch ".length).trim();
|
|
140
|
+
entry.branch = ref.replace(/^refs\/heads\//, "");
|
|
141
|
+
} else if (line === "bare") {
|
|
142
|
+
entry.bare = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (entry.path) {
|
|
146
|
+
entries.push(entry);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return entries;
|
|
150
|
+
}
|
|
151
|
+
async function pruneWorktrees(repoRoot) {
|
|
152
|
+
try {
|
|
153
|
+
await execFileAsync2("git", ["worktree", "prune"], {
|
|
154
|
+
cwd: repoRoot,
|
|
155
|
+
encoding: "utf8",
|
|
156
|
+
timeout: GIT_TIMEOUT_MS,
|
|
157
|
+
windowsHide: true
|
|
158
|
+
});
|
|
159
|
+
} catch {
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
var path4, import_promises3, import_node_fs2, import_node_child_process2, import_node_util2, execFileAsync2, WORKTREE_DIR_NAME, GIT_TIMEOUT_MS, GIT_MAX_BUFFER;
|
|
163
|
+
var init_git_worktree = __esm({
|
|
164
|
+
"src/git/git-worktree.ts"() {
|
|
165
|
+
"use strict";
|
|
166
|
+
path4 = __toESM(require("path"));
|
|
167
|
+
import_promises3 = require("fs/promises");
|
|
168
|
+
import_node_fs2 = require("fs");
|
|
169
|
+
import_node_child_process2 = require("child_process");
|
|
170
|
+
import_node_util2 = require("util");
|
|
171
|
+
execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
|
|
172
|
+
WORKTREE_DIR_NAME = ".adhdev-worktrees";
|
|
173
|
+
GIT_TIMEOUT_MS = 3e4;
|
|
174
|
+
GIT_MAX_BUFFER = 4 * 1024 * 1024;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
49
178
|
// src/config/config.ts
|
|
50
179
|
var config_exports = {};
|
|
51
180
|
__export(config_exports, {
|
|
@@ -304,10 +433,10 @@ function getMeshConfigPath() {
|
|
|
304
433
|
return (0, import_path2.join)(getConfigDir(), "meshes.json");
|
|
305
434
|
}
|
|
306
435
|
function loadMeshConfig() {
|
|
307
|
-
const
|
|
308
|
-
if (!(0, import_fs2.existsSync)(
|
|
436
|
+
const path27 = getMeshConfigPath();
|
|
437
|
+
if (!(0, import_fs2.existsSync)(path27)) return { meshes: [] };
|
|
309
438
|
try {
|
|
310
|
-
const raw = JSON.parse((0, import_fs2.readFileSync)(
|
|
439
|
+
const raw = JSON.parse((0, import_fs2.readFileSync)(path27, "utf-8"));
|
|
311
440
|
if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
|
|
312
441
|
return raw;
|
|
313
442
|
} catch {
|
|
@@ -315,16 +444,16 @@ function loadMeshConfig() {
|
|
|
315
444
|
}
|
|
316
445
|
}
|
|
317
446
|
function saveMeshConfig(config) {
|
|
318
|
-
const
|
|
319
|
-
(0, import_fs2.writeFileSync)(
|
|
447
|
+
const path27 = getMeshConfigPath();
|
|
448
|
+
(0, import_fs2.writeFileSync)(path27, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
|
|
320
449
|
}
|
|
321
450
|
function normalizeRepoIdentity(remoteUrl) {
|
|
322
451
|
let identity = remoteUrl.trim();
|
|
323
452
|
if (identity.startsWith("http://") || identity.startsWith("https://")) {
|
|
324
453
|
try {
|
|
325
454
|
const url = new URL(identity);
|
|
326
|
-
const
|
|
327
|
-
return `${url.hostname}/${
|
|
455
|
+
const path27 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
|
|
456
|
+
return `${url.hostname}/${path27}`;
|
|
328
457
|
} catch {
|
|
329
458
|
}
|
|
330
459
|
}
|
|
@@ -332,6 +461,18 @@ function normalizeRepoIdentity(remoteUrl) {
|
|
|
332
461
|
if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
|
|
333
462
|
return identity;
|
|
334
463
|
}
|
|
464
|
+
function mergeMeshPolicy(base, patch) {
|
|
465
|
+
const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
|
|
466
|
+
if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
|
|
467
|
+
policy.dirtyWorkspaceBehavior = "warn";
|
|
468
|
+
}
|
|
469
|
+
const maxParallelTasks = Number(policy.maxParallelTasks);
|
|
470
|
+
policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
|
|
471
|
+
if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
|
|
472
|
+
policy.sessionCleanupOnNodeRemove = "preserve";
|
|
473
|
+
}
|
|
474
|
+
return policy;
|
|
475
|
+
}
|
|
335
476
|
function listMeshes() {
|
|
336
477
|
return loadMeshConfig().meshes;
|
|
337
478
|
}
|
|
@@ -355,7 +496,7 @@ function createMesh(opts) {
|
|
|
355
496
|
repoIdentity,
|
|
356
497
|
repoRemoteUrl: opts.repoRemoteUrl,
|
|
357
498
|
defaultBranch: opts.defaultBranch,
|
|
358
|
-
policy:
|
|
499
|
+
policy: mergeMeshPolicy(void 0, opts.policy),
|
|
359
500
|
coordinator: opts.coordinator || {},
|
|
360
501
|
nodes: [],
|
|
361
502
|
createdAt: now,
|
|
@@ -371,7 +512,7 @@ function updateMesh(meshId, opts) {
|
|
|
371
512
|
if (!mesh) return void 0;
|
|
372
513
|
if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
|
|
373
514
|
if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
|
|
374
|
-
if (opts.policy) mesh.policy =
|
|
515
|
+
if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
|
|
375
516
|
if (opts.coordinator) mesh.coordinator = opts.coordinator;
|
|
376
517
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
377
518
|
saveMeshConfig(config);
|
|
@@ -399,9 +540,12 @@ function addNode(meshId, opts) {
|
|
|
399
540
|
id: `node_${(0, import_crypto3.randomUUID)().replace(/-/g, "")}`,
|
|
400
541
|
workspace: opts.workspace.trim(),
|
|
401
542
|
repoRoot: opts.repoRoot,
|
|
543
|
+
daemonId: opts.daemonId,
|
|
402
544
|
userOverrides: opts.userOverrides || {},
|
|
403
545
|
policy: opts.policy || {},
|
|
404
|
-
isLocalWorktree: opts.isLocalWorktree
|
|
546
|
+
isLocalWorktree: opts.isLocalWorktree,
|
|
547
|
+
worktreeBranch: opts.worktreeBranch,
|
|
548
|
+
clonedFromNodeId: opts.clonedFromNodeId
|
|
405
549
|
};
|
|
406
550
|
mesh.nodes.push(node);
|
|
407
551
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -431,7 +575,7 @@ function updateNode(meshId, nodeId, opts) {
|
|
|
431
575
|
saveMeshConfig(config);
|
|
432
576
|
return node;
|
|
433
577
|
}
|
|
434
|
-
var import_fs2, import_path2, import_crypto3;
|
|
578
|
+
var import_fs2, import_path2, import_crypto3, SESSION_CLEANUP_MODES;
|
|
435
579
|
var init_mesh_config = __esm({
|
|
436
580
|
"src/config/mesh-config.ts"() {
|
|
437
581
|
"use strict";
|
|
@@ -440,6 +584,7 @@ var init_mesh_config = __esm({
|
|
|
440
584
|
import_crypto3 = require("crypto");
|
|
441
585
|
init_config();
|
|
442
586
|
init_repo_mesh_types();
|
|
587
|
+
SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
|
|
443
588
|
}
|
|
444
589
|
});
|
|
445
590
|
|
|
@@ -449,7 +594,7 @@ __export(coordinator_prompt_exports, {
|
|
|
449
594
|
buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
|
|
450
595
|
});
|
|
451
596
|
function buildCoordinatorSystemPrompt(ctx) {
|
|
452
|
-
const { mesh, status, userInstruction } = ctx;
|
|
597
|
+
const { mesh, status, userInstruction, coordinatorCliType } = ctx;
|
|
453
598
|
const sections = [];
|
|
454
599
|
sections.push(`You are a **Repo Mesh Coordinator** \u2014 a technical team lead who orchestrates work across multiple agent sessions on a shared Git repository.
|
|
455
600
|
|
|
@@ -463,15 +608,15 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
463
608
|
} else {
|
|
464
609
|
sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
|
|
465
610
|
}
|
|
466
|
-
sections.push(buildPolicySection(mesh.policy));
|
|
611
|
+
sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
|
|
467
612
|
sections.push(TOOLS_SECTION);
|
|
468
613
|
sections.push(WORKFLOW_SECTION);
|
|
469
|
-
sections.push(
|
|
614
|
+
sections.push(buildRulesSection(coordinatorCliType));
|
|
470
615
|
if (userInstruction) {
|
|
471
616
|
sections.push(`## Additional Context
|
|
472
617
|
${userInstruction}`);
|
|
473
618
|
}
|
|
474
|
-
if (mesh.coordinator
|
|
619
|
+
if (mesh.coordinator?.systemPromptSuffix) {
|
|
475
620
|
sections.push(mesh.coordinator.systemPromptSuffix);
|
|
476
621
|
}
|
|
477
622
|
return sections.join("\n\n");
|
|
@@ -516,10 +661,29 @@ function buildPolicySection(policy) {
|
|
|
516
661
|
return `## Policy
|
|
517
662
|
${rules.join("\n")}`;
|
|
518
663
|
}
|
|
519
|
-
|
|
664
|
+
function buildRulesSection(coordinatorCliType) {
|
|
665
|
+
const coordinatorNote = coordinatorCliType ? `
|
|
666
|
+
- **Coordinator runtime is not a delegation default.** This coordinator is running as \`${coordinatorCliType}\`, but delegated node sessions must follow the user's requested provider, not the coordinator's own runtime.` : "";
|
|
667
|
+
return `## Rules
|
|
668
|
+
|
|
669
|
+
- **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
|
|
670
|
+
- **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
|
|
671
|
+
- **Respect explicit provider requests.** If the user names an agent/provider, pass the matching provider type to \`mesh_launch_session\`: Hermes \u2192 \`hermes-cli\`, Claude Code/Claude \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`. Never substitute \`claude-cli\` just because the coordinator itself is Claude Code.
|
|
672
|
+
- **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
|
|
673
|
+
- **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
|
|
674
|
+
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
|
|
675
|
+
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
676
|
+
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
677
|
+
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
678
|
+
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.
|
|
679
|
+
- **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
|
|
680
|
+
- **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
|
|
681
|
+
}
|
|
682
|
+
var TOOLS_SECTION, WORKFLOW_SECTION;
|
|
520
683
|
var init_coordinator_prompt = __esm({
|
|
521
684
|
"src/mesh/coordinator-prompt.ts"() {
|
|
522
685
|
"use strict";
|
|
686
|
+
init_repo_mesh_types();
|
|
523
687
|
TOOLS_SECTION = `## Available Tools
|
|
524
688
|
|
|
525
689
|
| Tool | Purpose |
|
|
@@ -531,30 +695,23 @@ var init_coordinator_prompt = __esm({
|
|
|
531
695
|
| \`mesh_read_chat\` | Read an agent's recent messages to check progress |
|
|
532
696
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
533
697
|
| \`mesh_checkpoint\` | Create a git checkpoint on a node |
|
|
534
|
-
| \`mesh_approve\` | Approve/reject a pending agent action
|
|
698
|
+
| \`mesh_approve\` | Approve/reject a pending agent action |
|
|
699
|
+
| \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
|
|
700
|
+
| \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |`;
|
|
535
701
|
WORKFLOW_SECTION = `## Orchestration Workflow
|
|
536
702
|
|
|
537
703
|
1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
|
|
538
704
|
2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
|
|
539
705
|
3. **Delegate** \u2014 For each task:
|
|
540
706
|
a. Pick the best node (consider: health, dirty state, current workload).
|
|
541
|
-
b. If
|
|
542
|
-
c.
|
|
707
|
+
b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
|
|
708
|
+
c. If no session exists, call \`mesh_launch_session\` to start one.
|
|
709
|
+
d. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
|
|
543
710
|
4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
|
|
544
711
|
5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
|
|
545
712
|
6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
|
|
546
|
-
7. **
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
- **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
|
|
550
|
-
- **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
|
|
551
|
-
- **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
|
|
552
|
-
- **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
|
|
553
|
-
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
|
|
554
|
-
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
555
|
-
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
556
|
-
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
557
|
-
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
|
|
713
|
+
7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
|
|
714
|
+
8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
|
|
558
715
|
}
|
|
559
716
|
});
|
|
560
717
|
|
|
@@ -573,13 +730,13 @@ function getDaemonLogDir() {
|
|
|
573
730
|
return LOG_DIR;
|
|
574
731
|
}
|
|
575
732
|
function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
|
|
576
|
-
return
|
|
733
|
+
return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
|
|
577
734
|
}
|
|
578
735
|
function checkDateRotation() {
|
|
579
736
|
const today = getDateStr();
|
|
580
737
|
if (today !== currentDate) {
|
|
581
738
|
currentDate = today;
|
|
582
|
-
currentLogFile =
|
|
739
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
583
740
|
cleanOldLogs();
|
|
584
741
|
}
|
|
585
742
|
}
|
|
@@ -593,7 +750,7 @@ function cleanOldLogs() {
|
|
|
593
750
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
594
751
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
595
752
|
try {
|
|
596
|
-
fs2.unlinkSync(
|
|
753
|
+
fs2.unlinkSync(path10.join(LOG_DIR, file));
|
|
597
754
|
} catch {
|
|
598
755
|
}
|
|
599
756
|
}
|
|
@@ -709,17 +866,17 @@ function installGlobalInterceptor() {
|
|
|
709
866
|
writeToFile(`Log file: ${currentLogFile}`);
|
|
710
867
|
writeToFile(`Log level: ${currentLevel}`);
|
|
711
868
|
}
|
|
712
|
-
var fs2,
|
|
869
|
+
var fs2, path10, os4, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
|
|
713
870
|
var init_logger = __esm({
|
|
714
871
|
"src/logging/logger.ts"() {
|
|
715
872
|
"use strict";
|
|
716
873
|
fs2 = __toESM(require("fs"));
|
|
717
|
-
|
|
874
|
+
path10 = __toESM(require("path"));
|
|
718
875
|
os4 = __toESM(require("os"));
|
|
719
876
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
720
877
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
721
878
|
currentLevel = "info";
|
|
722
|
-
LOG_DIR = process.platform === "win32" ?
|
|
879
|
+
LOG_DIR = process.platform === "win32" ? path10.join(process.env.LOCALAPPDATA || process.env.APPDATA || path10.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path10.join(os4.homedir(), "Library", "Logs", "adhdev") : path10.join(os4.homedir(), ".local", "share", "adhdev", "logs");
|
|
723
880
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
724
881
|
MAX_LOG_DAYS = 7;
|
|
725
882
|
try {
|
|
@@ -727,16 +884,16 @@ var init_logger = __esm({
|
|
|
727
884
|
} catch {
|
|
728
885
|
}
|
|
729
886
|
currentDate = getDateStr();
|
|
730
|
-
currentLogFile =
|
|
887
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
731
888
|
cleanOldLogs();
|
|
732
889
|
try {
|
|
733
|
-
const oldLog =
|
|
890
|
+
const oldLog = path10.join(LOG_DIR, "daemon.log");
|
|
734
891
|
if (fs2.existsSync(oldLog)) {
|
|
735
892
|
const stat2 = fs2.statSync(oldLog);
|
|
736
893
|
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
737
|
-
fs2.renameSync(oldLog,
|
|
894
|
+
fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
738
895
|
}
|
|
739
|
-
const oldLogBackup =
|
|
896
|
+
const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
|
|
740
897
|
if (fs2.existsSync(oldLogBackup)) {
|
|
741
898
|
fs2.unlinkSync(oldLogBackup);
|
|
742
899
|
}
|
|
@@ -768,7 +925,7 @@ var init_logger = __esm({
|
|
|
768
925
|
}
|
|
769
926
|
};
|
|
770
927
|
interceptorInstalled = false;
|
|
771
|
-
LOG_PATH =
|
|
928
|
+
LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
772
929
|
}
|
|
773
930
|
});
|
|
774
931
|
|
|
@@ -1236,9 +1393,9 @@ function buildCliScreenSnapshot(text) {
|
|
|
1236
1393
|
function findBinary(name) {
|
|
1237
1394
|
const trimmed = String(name || "").trim();
|
|
1238
1395
|
if (!trimmed) return trimmed;
|
|
1239
|
-
const expanded = trimmed.startsWith("~") ?
|
|
1240
|
-
if (
|
|
1241
|
-
return
|
|
1396
|
+
const expanded = trimmed.startsWith("~") ? path14.join(os9.homedir(), trimmed.slice(1)) : trimmed;
|
|
1397
|
+
if (path14.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
|
|
1398
|
+
return path14.isAbsolute(expanded) ? expanded : path14.resolve(expanded);
|
|
1242
1399
|
}
|
|
1243
1400
|
const isWin = os9.platform() === "win32";
|
|
1244
1401
|
try {
|
|
@@ -1254,7 +1411,7 @@ function findBinary(name) {
|
|
|
1254
1411
|
}
|
|
1255
1412
|
}
|
|
1256
1413
|
function isScriptBinary(binaryPath) {
|
|
1257
|
-
if (!
|
|
1414
|
+
if (!path14.isAbsolute(binaryPath)) return false;
|
|
1258
1415
|
try {
|
|
1259
1416
|
const fs16 = require("fs");
|
|
1260
1417
|
const resolved = fs16.realpathSync(binaryPath);
|
|
@@ -1270,7 +1427,7 @@ function isScriptBinary(binaryPath) {
|
|
|
1270
1427
|
}
|
|
1271
1428
|
}
|
|
1272
1429
|
function looksLikeMachOOrElf(filePath) {
|
|
1273
|
-
if (!
|
|
1430
|
+
if (!path14.isAbsolute(filePath)) return false;
|
|
1274
1431
|
try {
|
|
1275
1432
|
const fs16 = require("fs");
|
|
1276
1433
|
const resolved = fs16.realpathSync(filePath);
|
|
@@ -1359,12 +1516,12 @@ function normalizeCliProviderForRuntime(raw) {
|
|
|
1359
1516
|
}
|
|
1360
1517
|
};
|
|
1361
1518
|
}
|
|
1362
|
-
var os9,
|
|
1519
|
+
var os9, path14, import_child_process4, buildCliSpawnEnv;
|
|
1363
1520
|
var init_provider_cli_shared = __esm({
|
|
1364
1521
|
"src/cli-adapters/provider-cli-shared.ts"() {
|
|
1365
1522
|
"use strict";
|
|
1366
1523
|
os9 = __toESM(require("os"));
|
|
1367
|
-
|
|
1524
|
+
path14 = __toESM(require("path"));
|
|
1368
1525
|
import_child_process4 = require("child_process");
|
|
1369
1526
|
init_spawn_env();
|
|
1370
1527
|
buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
|
|
@@ -1487,7 +1644,7 @@ var init_provider_cli_config = __esm({
|
|
|
1487
1644
|
|
|
1488
1645
|
// src/cli-adapters/provider-cli-runtime.ts
|
|
1489
1646
|
function resolveCliSpawnPlan(options) {
|
|
1490
|
-
const { provider, runtimeSettings, workingDir, extraArgs } = options;
|
|
1647
|
+
const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
|
|
1491
1648
|
const { spawn: spawnConfig } = provider;
|
|
1492
1649
|
const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
|
|
1493
1650
|
const binaryPath = findBinary(configuredCommand);
|
|
@@ -1495,9 +1652,9 @@ function resolveCliSpawnPlan(options) {
|
|
|
1495
1652
|
const allArgs = [...spawnConfig.args, ...extraArgs];
|
|
1496
1653
|
let shellCmd;
|
|
1497
1654
|
let shellArgs;
|
|
1498
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1655
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1499
1656
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
1500
|
-
const useShellWin = !!spawnConfig.shell || isCmdShim || !
|
|
1657
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
1501
1658
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
1502
1659
|
if (useShell) {
|
|
1503
1660
|
shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
|
|
@@ -1511,7 +1668,7 @@ function resolveCliSpawnPlan(options) {
|
|
|
1511
1668
|
shellCmd = binaryPath;
|
|
1512
1669
|
shellArgs = allArgs;
|
|
1513
1670
|
}
|
|
1514
|
-
const env = buildCliSpawnEnv(process.env, spawnConfig.env);
|
|
1671
|
+
const env = buildCliSpawnEnv(process.env, { ...spawnConfig.env || {}, ...extraEnv || {} });
|
|
1515
1672
|
env.TERMINAL_CWD = workingDir;
|
|
1516
1673
|
return {
|
|
1517
1674
|
binaryPath,
|
|
@@ -1573,12 +1730,12 @@ function respondToCliTerminalQueries(options) {
|
|
|
1573
1730
|
}
|
|
1574
1731
|
return "";
|
|
1575
1732
|
}
|
|
1576
|
-
var os10,
|
|
1733
|
+
var os10, path15, import_session_host_core2;
|
|
1577
1734
|
var init_provider_cli_runtime = __esm({
|
|
1578
1735
|
"src/cli-adapters/provider-cli-runtime.ts"() {
|
|
1579
1736
|
"use strict";
|
|
1580
1737
|
os10 = __toESM(require("os"));
|
|
1581
|
-
|
|
1738
|
+
path15 = __toESM(require("path"));
|
|
1582
1739
|
import_session_host_core2 = require("@adhdev/session-host-core");
|
|
1583
1740
|
init_provider_cli_shared();
|
|
1584
1741
|
}
|
|
@@ -1614,8 +1771,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1614
1771
|
init_provider_cli_runtime();
|
|
1615
1772
|
init_provider_cli_shared();
|
|
1616
1773
|
ProviderCliAdapter = class _ProviderCliAdapter {
|
|
1617
|
-
constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
|
|
1774
|
+
constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
|
|
1618
1775
|
this.extraArgs = extraArgs;
|
|
1776
|
+
this.extraEnv = extraEnv;
|
|
1619
1777
|
this.provider = provider;
|
|
1620
1778
|
this.transportFactory = transportFactory;
|
|
1621
1779
|
this.cliType = provider.type;
|
|
@@ -1766,8 +1924,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1766
1924
|
const currentSnapshot = normalizeScreenSnapshot(screenText);
|
|
1767
1925
|
const lastSnapshot = this.lastScreenSnapshot;
|
|
1768
1926
|
if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
|
|
1769
|
-
const
|
|
1770
|
-
const
|
|
1927
|
+
const activeScreenPattern = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel|Enter to confirm\s*[·•-]\s*Esc to cancel|\b(?:MCP servers?|tool calls?)\b[^\n\r]{0,160}\brequire approval\b/i;
|
|
1928
|
+
const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
|
|
1929
|
+
const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
|
|
1771
1930
|
if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
|
|
1772
1931
|
if (currentSnapshot.length >= lastSnapshot.length) return screenText;
|
|
1773
1932
|
return `${screenText}
|
|
@@ -1930,7 +2089,8 @@ ${lastSnapshot}`;
|
|
|
1930
2089
|
provider: this.provider,
|
|
1931
2090
|
runtimeSettings: this.runtimeSettings,
|
|
1932
2091
|
workingDir: this.workingDir,
|
|
1933
|
-
extraArgs: this.extraArgs
|
|
2092
|
+
extraArgs: this.extraArgs,
|
|
2093
|
+
extraEnv: this.extraEnv
|
|
1934
2094
|
});
|
|
1935
2095
|
LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
1936
2096
|
this.resetTraceSession();
|
|
@@ -3128,9 +3288,8 @@ ${lastSnapshot}`;
|
|
|
3128
3288
|
};
|
|
3129
3289
|
this.recordTrace("submit_echo_missing", diagnostic);
|
|
3130
3290
|
if (this.requirePromptEchoBeforeSubmit) {
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
completion.rejectOnce(new Error(message));
|
|
3291
|
+
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending guarded submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
|
|
3292
|
+
this.submitSendKey(state, completion);
|
|
3134
3293
|
return;
|
|
3135
3294
|
}
|
|
3136
3295
|
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
|
|
@@ -3177,7 +3336,14 @@ ${lastSnapshot}`;
|
|
|
3177
3336
|
})() : null;
|
|
3178
3337
|
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
|
|
3179
3338
|
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
|
|
3180
|
-
|
|
3339
|
+
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
3340
|
+
const parsedHasActionableModal = Boolean(
|
|
3341
|
+
parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
|
|
3342
|
+
);
|
|
3343
|
+
const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
|
|
3344
|
+
if (!terminalLooksIdle) {
|
|
3345
|
+
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
3346
|
+
}
|
|
3181
3347
|
}
|
|
3182
3348
|
if (this.isWaitingForResponse && !allowInputDuringGeneration) {
|
|
3183
3349
|
if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
|
|
@@ -3727,6 +3893,7 @@ __export(index_exports, {
|
|
|
3727
3893
|
createGitWorkspaceMonitor: () => createGitWorkspaceMonitor,
|
|
3728
3894
|
createInteractionId: () => createInteractionId,
|
|
3729
3895
|
createMesh: () => createMesh,
|
|
3896
|
+
createWorktree: () => createWorktree,
|
|
3730
3897
|
deleteMesh: () => deleteMesh,
|
|
3731
3898
|
detectAllVersions: () => detectAllVersions,
|
|
3732
3899
|
detectCLIs: () => detectCLIs,
|
|
@@ -3779,6 +3946,7 @@ __export(index_exports, {
|
|
|
3779
3946
|
launchWithCdp: () => launchWithCdp,
|
|
3780
3947
|
listHostedCliRuntimes: () => listHostedCliRuntimes,
|
|
3781
3948
|
listMeshes: () => listMeshes,
|
|
3949
|
+
listWorktrees: () => listWorktrees,
|
|
3782
3950
|
loadConfig: () => loadConfig,
|
|
3783
3951
|
loadState: () => loadState,
|
|
3784
3952
|
logCommand: () => logCommand,
|
|
@@ -3798,6 +3966,7 @@ __export(index_exports, {
|
|
|
3798
3966
|
normalizeSessionModalFields: () => normalizeSessionModalFields,
|
|
3799
3967
|
parsePorcelainV2Status: () => parsePorcelainV2Status,
|
|
3800
3968
|
parseProviderSourceConfigUpdate: () => parseProviderSourceConfigUpdate,
|
|
3969
|
+
parseWorktreeListOutput: () => parseWorktreeListOutput,
|
|
3801
3970
|
partitionSessionHostDiagnosticsSessions: () => partitionSessionHostDiagnosticsSessions,
|
|
3802
3971
|
partitionSessionHostRecords: () => partitionSessionHostRecords,
|
|
3803
3972
|
prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
|
|
@@ -3807,6 +3976,7 @@ __export(index_exports, {
|
|
|
3807
3976
|
recordDebugTrace: () => recordDebugTrace,
|
|
3808
3977
|
registerExtensionProviders: () => registerExtensionProviders,
|
|
3809
3978
|
removeNode: () => removeNode,
|
|
3979
|
+
removeWorktree: () => removeWorktree,
|
|
3810
3980
|
resetConfig: () => resetConfig,
|
|
3811
3981
|
resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
|
|
3812
3982
|
resetState: () => resetState,
|
|
@@ -3816,6 +3986,7 @@ __export(index_exports, {
|
|
|
3816
3986
|
resolveGitRepository: () => resolveGitRepository,
|
|
3817
3987
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
3818
3988
|
resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
|
|
3989
|
+
resolveWorktreePath: () => resolveWorktreePath,
|
|
3819
3990
|
runAsyncBatch: () => runAsyncBatch,
|
|
3820
3991
|
runGit: () => runGit,
|
|
3821
3992
|
saveConfig: () => saveConfig,
|
|
@@ -4739,6 +4910,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
|
4739
4910
|
"dirty_index_required",
|
|
4740
4911
|
"conflict",
|
|
4741
4912
|
"invalid_args",
|
|
4913
|
+
"nothing_to_commit",
|
|
4742
4914
|
"git_command_failed"
|
|
4743
4915
|
]);
|
|
4744
4916
|
function failure(reason, error) {
|
|
@@ -4983,7 +5155,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
|
4983
5155
|
} catch (err) {
|
|
4984
5156
|
const output = (err?.stdout || "") + (err?.stderr || "");
|
|
4985
5157
|
if (/nothing to commit/i.test(output)) {
|
|
4986
|
-
throw new GitCommandError("
|
|
5158
|
+
throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
|
|
5159
|
+
stdout: err?.stdout,
|
|
5160
|
+
stderr: err?.stderr
|
|
5161
|
+
});
|
|
4987
5162
|
}
|
|
4988
5163
|
throw err;
|
|
4989
5164
|
}
|
|
@@ -5175,20 +5350,23 @@ var TurnSnapshotTracker = class {
|
|
|
5175
5350
|
}
|
|
5176
5351
|
};
|
|
5177
5352
|
|
|
5353
|
+
// src/git/index.ts
|
|
5354
|
+
init_git_worktree();
|
|
5355
|
+
|
|
5178
5356
|
// src/index.ts
|
|
5179
5357
|
init_config();
|
|
5180
5358
|
|
|
5181
5359
|
// src/config/workspaces.ts
|
|
5182
5360
|
var fs = __toESM(require("fs"));
|
|
5183
5361
|
var os = __toESM(require("os"));
|
|
5184
|
-
var
|
|
5362
|
+
var path5 = __toESM(require("path"));
|
|
5185
5363
|
var import_crypto2 = require("crypto");
|
|
5186
5364
|
var MAX_WORKSPACES = 50;
|
|
5187
5365
|
function expandPath(p) {
|
|
5188
5366
|
const t = (p || "").trim();
|
|
5189
5367
|
if (!t) return "";
|
|
5190
|
-
if (t.startsWith("~")) return
|
|
5191
|
-
return
|
|
5368
|
+
if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5369
|
+
return path5.resolve(t);
|
|
5192
5370
|
}
|
|
5193
5371
|
function validateWorkspacePath(absPath) {
|
|
5194
5372
|
try {
|
|
@@ -5202,7 +5380,7 @@ function validateWorkspacePath(absPath) {
|
|
|
5202
5380
|
}
|
|
5203
5381
|
}
|
|
5204
5382
|
function defaultWorkspaceLabel(absPath) {
|
|
5205
|
-
const base =
|
|
5383
|
+
const base = path5.basename(absPath) || absPath;
|
|
5206
5384
|
return base;
|
|
5207
5385
|
}
|
|
5208
5386
|
function getDefaultWorkspacePath(config) {
|
|
@@ -5293,9 +5471,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
5293
5471
|
return getDefaultWorkspacePath(config) || void 0;
|
|
5294
5472
|
}
|
|
5295
5473
|
function findWorkspaceByPath(config, rawPath) {
|
|
5296
|
-
const abs =
|
|
5474
|
+
const abs = path5.resolve(expandPath(rawPath));
|
|
5297
5475
|
if (!abs) return void 0;
|
|
5298
|
-
return (config.workspaces || []).find((w) =>
|
|
5476
|
+
return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
|
|
5299
5477
|
}
|
|
5300
5478
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
5301
5479
|
const abs = expandPath(rawPath);
|
|
@@ -5311,7 +5489,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
5311
5489
|
const v = validateWorkspacePath(abs);
|
|
5312
5490
|
if (!v.ok) return { error: v.error };
|
|
5313
5491
|
const list = [...config.workspaces || []];
|
|
5314
|
-
if (list.some((w) =>
|
|
5492
|
+
if (list.some((w) => path5.resolve(w.path) === abs)) {
|
|
5315
5493
|
return { error: "Workspace already in list" };
|
|
5316
5494
|
}
|
|
5317
5495
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -5345,7 +5523,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
5345
5523
|
}
|
|
5346
5524
|
|
|
5347
5525
|
// src/config/recent-activity.ts
|
|
5348
|
-
var
|
|
5526
|
+
var path6 = __toESM(require("path"));
|
|
5349
5527
|
|
|
5350
5528
|
// src/providers/summary-metadata.ts
|
|
5351
5529
|
function normalizeSummaryItem(item) {
|
|
@@ -5414,9 +5592,9 @@ var MAX_ACTIVITY = 30;
|
|
|
5414
5592
|
function normalizeWorkspace(workspace) {
|
|
5415
5593
|
if (!workspace) return "";
|
|
5416
5594
|
try {
|
|
5417
|
-
return
|
|
5595
|
+
return path6.resolve(expandPath(workspace));
|
|
5418
5596
|
} catch {
|
|
5419
|
-
return
|
|
5597
|
+
return path6.resolve(workspace);
|
|
5420
5598
|
}
|
|
5421
5599
|
}
|
|
5422
5600
|
function buildRecentActivityKey(entry) {
|
|
@@ -5584,14 +5762,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5584
5762
|
}
|
|
5585
5763
|
|
|
5586
5764
|
// src/config/saved-sessions.ts
|
|
5587
|
-
var
|
|
5765
|
+
var path7 = __toESM(require("path"));
|
|
5588
5766
|
var MAX_SAVED_SESSIONS = 500;
|
|
5589
5767
|
function normalizeWorkspace2(workspace) {
|
|
5590
5768
|
if (!workspace) return "";
|
|
5591
5769
|
try {
|
|
5592
|
-
return
|
|
5770
|
+
return path7.resolve(expandPath(workspace));
|
|
5593
5771
|
} catch {
|
|
5594
|
-
return
|
|
5772
|
+
return path7.resolve(workspace);
|
|
5595
5773
|
}
|
|
5596
5774
|
}
|
|
5597
5775
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5770,7 +5948,7 @@ function resetState() {
|
|
|
5770
5948
|
var import_child_process = require("child_process");
|
|
5771
5949
|
var import_fs4 = require("fs");
|
|
5772
5950
|
var import_os2 = require("os");
|
|
5773
|
-
var
|
|
5951
|
+
var path8 = __toESM(require("path"));
|
|
5774
5952
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5775
5953
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5776
5954
|
function registerIDEDefinition(def) {
|
|
@@ -5789,9 +5967,9 @@ function getMergedDefinitions() {
|
|
|
5789
5967
|
function findCliCommand(command) {
|
|
5790
5968
|
const trimmed = String(command || "").trim();
|
|
5791
5969
|
if (!trimmed) return null;
|
|
5792
|
-
if (
|
|
5793
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5794
|
-
const resolved =
|
|
5970
|
+
if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
5971
|
+
const candidate = trimmed.startsWith("~") ? path8.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
|
|
5972
|
+
const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
|
|
5795
5973
|
return (0, import_fs4.existsSync)(resolved) ? resolved : null;
|
|
5796
5974
|
}
|
|
5797
5975
|
try {
|
|
@@ -5819,7 +5997,7 @@ function getIdeVersion(cliCommand) {
|
|
|
5819
5997
|
function checkPathExists(paths) {
|
|
5820
5998
|
const home = (0, import_os2.homedir)();
|
|
5821
5999
|
for (const p of paths) {
|
|
5822
|
-
const normalized = p.startsWith("~") ?
|
|
6000
|
+
const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
|
|
5823
6001
|
if (normalized.includes("*")) {
|
|
5824
6002
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5825
6003
|
const resolved = normalized.replace("*", username);
|
|
@@ -5831,19 +6009,19 @@ function checkPathExists(paths) {
|
|
|
5831
6009
|
return null;
|
|
5832
6010
|
}
|
|
5833
6011
|
async function detectIDEs(providerLoader) {
|
|
5834
|
-
const
|
|
6012
|
+
const os22 = (0, import_os2.platform)();
|
|
5835
6013
|
const results = [];
|
|
5836
6014
|
for (const def of getMergedDefinitions()) {
|
|
5837
6015
|
const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
|
|
5838
|
-
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[
|
|
6016
|
+
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
|
|
5839
6017
|
let resolvedCli = cliPath;
|
|
5840
|
-
if (!resolvedCli && appPath &&
|
|
6018
|
+
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
5841
6019
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
5842
6020
|
if ((0, import_fs4.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
5843
6021
|
}
|
|
5844
|
-
if (!resolvedCli && appPath &&
|
|
5845
|
-
const { dirname:
|
|
5846
|
-
const appDir =
|
|
6022
|
+
if (!resolvedCli && appPath && os22 === "win32") {
|
|
6023
|
+
const { dirname: dirname9 } = await import("path");
|
|
6024
|
+
const appDir = dirname9(appPath);
|
|
5847
6025
|
const candidates = [
|
|
5848
6026
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
5849
6027
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -5858,7 +6036,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5858
6036
|
}
|
|
5859
6037
|
}
|
|
5860
6038
|
}
|
|
5861
|
-
const installed =
|
|
6039
|
+
const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
|
|
5862
6040
|
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
5863
6041
|
results.push({
|
|
5864
6042
|
id: def.id,
|
|
@@ -5877,7 +6055,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5877
6055
|
// src/detection/cli-detector.ts
|
|
5878
6056
|
var import_child_process2 = require("child_process");
|
|
5879
6057
|
var os2 = __toESM(require("os"));
|
|
5880
|
-
var
|
|
6058
|
+
var path9 = __toESM(require("path"));
|
|
5881
6059
|
var import_fs5 = require("fs");
|
|
5882
6060
|
function parseVersion(raw) {
|
|
5883
6061
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
@@ -5890,18 +6068,18 @@ function shellQuote(value) {
|
|
|
5890
6068
|
function expandHome(value) {
|
|
5891
6069
|
const trimmed = value.trim();
|
|
5892
6070
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5893
|
-
return
|
|
6071
|
+
return path9.join(os2.homedir(), trimmed.slice(1));
|
|
5894
6072
|
}
|
|
5895
6073
|
function isExplicitCommandPath(command) {
|
|
5896
6074
|
const trimmed = command.trim();
|
|
5897
|
-
return
|
|
6075
|
+
return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5898
6076
|
}
|
|
5899
6077
|
function resolveCommandPath(command) {
|
|
5900
6078
|
const trimmed = command.trim();
|
|
5901
6079
|
if (!trimmed) return null;
|
|
5902
6080
|
if (isExplicitCommandPath(trimmed)) {
|
|
5903
6081
|
const expanded = expandHome(trimmed);
|
|
5904
|
-
const candidate =
|
|
6082
|
+
const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
|
|
5905
6083
|
return (0, import_fs5.existsSync)(candidate) ? candidate : null;
|
|
5906
6084
|
}
|
|
5907
6085
|
return null;
|
|
@@ -8170,9 +8348,9 @@ ${cleanBody}`;
|
|
|
8170
8348
|
|
|
8171
8349
|
// src/config/chat-history.ts
|
|
8172
8350
|
var fs3 = __toESM(require("fs"));
|
|
8173
|
-
var
|
|
8351
|
+
var path11 = __toESM(require("path"));
|
|
8174
8352
|
var os5 = __toESM(require("os"));
|
|
8175
|
-
var HISTORY_DIR =
|
|
8353
|
+
var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
|
|
8176
8354
|
var RETAIN_DAYS = 30;
|
|
8177
8355
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
8178
8356
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -8335,7 +8513,7 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
8335
8513
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
8336
8514
|
return new Map(files.map((file) => {
|
|
8337
8515
|
try {
|
|
8338
|
-
const stat2 = fs3.statSync(
|
|
8516
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8339
8517
|
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
8340
8518
|
} catch {
|
|
8341
8519
|
return [file, `${file}:missing`];
|
|
@@ -8346,7 +8524,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
8346
8524
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
8347
8525
|
}
|
|
8348
8526
|
function getSavedHistoryIndexFilePath(dir) {
|
|
8349
|
-
return
|
|
8527
|
+
return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
8350
8528
|
}
|
|
8351
8529
|
function getSavedHistoryIndexLockPath(dir) {
|
|
8352
8530
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -8448,7 +8626,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
8448
8626
|
}
|
|
8449
8627
|
for (const file of Array.from(currentEntries.keys())) {
|
|
8450
8628
|
if (incomingFiles.has(file)) continue;
|
|
8451
|
-
if (!fs3.existsSync(
|
|
8629
|
+
if (!fs3.existsSync(path11.join(dir, file))) {
|
|
8452
8630
|
currentEntries.delete(file);
|
|
8453
8631
|
}
|
|
8454
8632
|
}
|
|
@@ -8474,7 +8652,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8474
8652
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8475
8653
|
const files = listHistoryFiles(dir);
|
|
8476
8654
|
for (const file of files) {
|
|
8477
|
-
const stat2 = fs3.statSync(
|
|
8655
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8478
8656
|
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
8479
8657
|
}
|
|
8480
8658
|
return false;
|
|
@@ -8484,14 +8662,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8484
8662
|
}
|
|
8485
8663
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
8486
8664
|
try {
|
|
8487
|
-
const stat2 = fs3.statSync(
|
|
8665
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8488
8666
|
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
8489
8667
|
} catch {
|
|
8490
8668
|
return `${file}:missing`;
|
|
8491
8669
|
}
|
|
8492
8670
|
}
|
|
8493
8671
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
8494
|
-
const filePath =
|
|
8672
|
+
const filePath = path11.join(dir, file);
|
|
8495
8673
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
8496
8674
|
const currentEntry = entries.get(file) || null;
|
|
8497
8675
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -8564,7 +8742,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
8564
8742
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
8565
8743
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
8566
8744
|
if (!historySessionId) return null;
|
|
8567
|
-
const filePath =
|
|
8745
|
+
const filePath = path11.join(dir, file);
|
|
8568
8746
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8569
8747
|
const lines = content.split("\n").filter(Boolean);
|
|
8570
8748
|
let messageCount = 0;
|
|
@@ -8651,7 +8829,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
8651
8829
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
8652
8830
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
8653
8831
|
for (const file of files.slice().sort()) {
|
|
8654
|
-
const filePath =
|
|
8832
|
+
const filePath = path11.join(dir, file);
|
|
8655
8833
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
8656
8834
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
8657
8835
|
const persisted = persistedEntries.get(file);
|
|
@@ -8771,12 +8949,12 @@ var ChatHistoryWriter = class {
|
|
|
8771
8949
|
});
|
|
8772
8950
|
}
|
|
8773
8951
|
if (newMessages.length === 0) return;
|
|
8774
|
-
const dir =
|
|
8952
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8775
8953
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8776
8954
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8777
8955
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
8778
8956
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
8779
|
-
const filePath =
|
|
8957
|
+
const filePath = path11.join(dir, fileName);
|
|
8780
8958
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
8781
8959
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
8782
8960
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -8867,11 +9045,11 @@ var ChatHistoryWriter = class {
|
|
|
8867
9045
|
const ws = String(workspace || "").trim();
|
|
8868
9046
|
if (!id || !ws) return;
|
|
8869
9047
|
try {
|
|
8870
|
-
const dir =
|
|
9048
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8871
9049
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8872
9050
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8873
9051
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
8874
|
-
const filePath =
|
|
9052
|
+
const filePath = path11.join(dir, fileName);
|
|
8875
9053
|
const record = {
|
|
8876
9054
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8877
9055
|
receivedAt: Date.now(),
|
|
@@ -8917,14 +9095,14 @@ var ChatHistoryWriter = class {
|
|
|
8917
9095
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8918
9096
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8919
9097
|
}
|
|
8920
|
-
const dir =
|
|
9098
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8921
9099
|
if (!fs3.existsSync(dir)) return;
|
|
8922
9100
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8923
9101
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8924
9102
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8925
9103
|
for (const file of files) {
|
|
8926
|
-
const sourcePath =
|
|
8927
|
-
const targetPath =
|
|
9104
|
+
const sourcePath = path11.join(dir, file);
|
|
9105
|
+
const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8928
9106
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8929
9107
|
const rewritten = sourceLines.map((line) => {
|
|
8930
9108
|
try {
|
|
@@ -8958,13 +9136,13 @@ var ChatHistoryWriter = class {
|
|
|
8958
9136
|
const sessionId = String(historySessionId || "").trim();
|
|
8959
9137
|
if (!sessionId) return;
|
|
8960
9138
|
try {
|
|
8961
|
-
const dir =
|
|
9139
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8962
9140
|
if (!fs3.existsSync(dir)) return;
|
|
8963
9141
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8964
9142
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8965
9143
|
const seen = /* @__PURE__ */ new Set();
|
|
8966
9144
|
for (const file of files) {
|
|
8967
|
-
const filePath =
|
|
9145
|
+
const filePath = path11.join(dir, file);
|
|
8968
9146
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8969
9147
|
const next = [];
|
|
8970
9148
|
for (const line of lines) {
|
|
@@ -9018,11 +9196,11 @@ var ChatHistoryWriter = class {
|
|
|
9018
9196
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
9019
9197
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
9020
9198
|
for (const dir of agentDirs) {
|
|
9021
|
-
const dirPath =
|
|
9199
|
+
const dirPath = path11.join(HISTORY_DIR, dir.name);
|
|
9022
9200
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
9023
9201
|
let removedAny = false;
|
|
9024
9202
|
for (const file of files) {
|
|
9025
|
-
const filePath =
|
|
9203
|
+
const filePath = path11.join(dirPath, file);
|
|
9026
9204
|
const stat2 = fs3.statSync(filePath);
|
|
9027
9205
|
if (stat2.mtimeMs < cutoff) {
|
|
9028
9206
|
fs3.unlinkSync(filePath);
|
|
@@ -9072,13 +9250,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
9072
9250
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
9073
9251
|
try {
|
|
9074
9252
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9075
|
-
const dir =
|
|
9253
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
9076
9254
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
9077
9255
|
const files = listHistoryFiles(dir, historySessionId);
|
|
9078
9256
|
const allMessages = [];
|
|
9079
9257
|
const seen = /* @__PURE__ */ new Set();
|
|
9080
9258
|
for (const file of files) {
|
|
9081
|
-
const filePath =
|
|
9259
|
+
const filePath = path11.join(dir, file);
|
|
9082
9260
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
9083
9261
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
9084
9262
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -9102,7 +9280,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
9102
9280
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
9103
9281
|
try {
|
|
9104
9282
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9105
|
-
const dir =
|
|
9283
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
9106
9284
|
if (!fs3.existsSync(dir)) {
|
|
9107
9285
|
savedHistorySessionCache.delete(sanitized);
|
|
9108
9286
|
return { sessions: [], hasMore: false };
|
|
@@ -9163,11 +9341,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
9163
9341
|
}
|
|
9164
9342
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
9165
9343
|
try {
|
|
9166
|
-
const dir =
|
|
9344
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
9167
9345
|
if (!fs3.existsSync(dir)) return null;
|
|
9168
9346
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
9169
9347
|
for (const file of files) {
|
|
9170
|
-
const lines = fs3.readFileSync(
|
|
9348
|
+
const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
9171
9349
|
for (const line of lines) {
|
|
9172
9350
|
try {
|
|
9173
9351
|
const parsed = JSON.parse(line);
|
|
@@ -9187,16 +9365,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
9187
9365
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
9188
9366
|
if (records.length === 0) return false;
|
|
9189
9367
|
try {
|
|
9190
|
-
const dir =
|
|
9368
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
9191
9369
|
fs3.mkdirSync(dir, { recursive: true });
|
|
9192
9370
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
9193
9371
|
for (const file of fs3.readdirSync(dir)) {
|
|
9194
9372
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
9195
|
-
fs3.unlinkSync(
|
|
9373
|
+
fs3.unlinkSync(path11.join(dir, file));
|
|
9196
9374
|
}
|
|
9197
9375
|
}
|
|
9198
9376
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
9199
|
-
const filePath =
|
|
9377
|
+
const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
9200
9378
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
9201
9379
|
`, "utf-8");
|
|
9202
9380
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -11191,6 +11369,14 @@ function getActiveChatOptions(profile) {
|
|
|
11191
11369
|
if (profile === "full") return {};
|
|
11192
11370
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
11193
11371
|
}
|
|
11372
|
+
function resolveSessionStatus(activeChat, providerStatus) {
|
|
11373
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
11374
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
11375
|
+
if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
|
|
11376
|
+
if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
|
|
11377
|
+
if (topLevelStatus !== "idle") return topLevelStatus;
|
|
11378
|
+
return chatStatus;
|
|
11379
|
+
}
|
|
11194
11380
|
function shouldIncludeSessionControls(profile) {
|
|
11195
11381
|
return profile !== "live";
|
|
11196
11382
|
}
|
|
@@ -11269,9 +11455,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11269
11455
|
providerName: state.name,
|
|
11270
11456
|
kind: "workspace",
|
|
11271
11457
|
transport: "cdp-page",
|
|
11272
|
-
status:
|
|
11273
|
-
activeModal: activeChat?.activeModal || null
|
|
11274
|
-
}),
|
|
11458
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11275
11459
|
title,
|
|
11276
11460
|
workspace,
|
|
11277
11461
|
...git && { git },
|
|
@@ -11306,9 +11490,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11306
11490
|
providerSessionId: ext.providerSessionId,
|
|
11307
11491
|
kind: "agent",
|
|
11308
11492
|
transport: "cdp-webview",
|
|
11309
|
-
status:
|
|
11310
|
-
activeModal: activeChat?.activeModal || null
|
|
11311
|
-
}),
|
|
11493
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
11312
11494
|
title: activeChat?.title || ext.name,
|
|
11313
11495
|
workspace,
|
|
11314
11496
|
...git && { git },
|
|
@@ -11358,9 +11540,7 @@ function buildCliSession(state, options) {
|
|
|
11358
11540
|
providerSessionId: state.providerSessionId,
|
|
11359
11541
|
kind: "agent",
|
|
11360
11542
|
transport: "pty",
|
|
11361
|
-
status:
|
|
11362
|
-
activeModal: activeChat?.activeModal || null
|
|
11363
|
-
}),
|
|
11543
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11364
11544
|
title: activeChat?.title || state.name,
|
|
11365
11545
|
workspace,
|
|
11366
11546
|
...git && { git },
|
|
@@ -11408,9 +11588,7 @@ function buildAcpSession(state, options) {
|
|
|
11408
11588
|
providerName: state.name,
|
|
11409
11589
|
kind: "agent",
|
|
11410
11590
|
transport: "acp",
|
|
11411
|
-
status:
|
|
11412
|
-
activeModal: activeChat?.activeModal || null
|
|
11413
|
-
}),
|
|
11591
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11414
11592
|
title: activeChat?.title || state.name,
|
|
11415
11593
|
workspace,
|
|
11416
11594
|
...git && { git },
|
|
@@ -11533,7 +11711,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
11533
11711
|
// src/commands/chat-commands.ts
|
|
11534
11712
|
var fs4 = __toESM(require("fs"));
|
|
11535
11713
|
var os6 = __toESM(require("os"));
|
|
11536
|
-
var
|
|
11714
|
+
var path12 = __toESM(require("path"));
|
|
11537
11715
|
var import_node_crypto = require("crypto");
|
|
11538
11716
|
|
|
11539
11717
|
// src/providers/provider-input-support.ts
|
|
@@ -11896,6 +12074,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
11896
12074
|
return raw;
|
|
11897
12075
|
}
|
|
11898
12076
|
}
|
|
12077
|
+
function isGeneratingLikeStatus(status) {
|
|
12078
|
+
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
12079
|
+
}
|
|
12080
|
+
function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
12081
|
+
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
12082
|
+
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
12083
|
+
const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
|
|
12084
|
+
if (adapterRawStatus !== "idle") return false;
|
|
12085
|
+
if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
|
|
12086
|
+
return true;
|
|
12087
|
+
}
|
|
12088
|
+
function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
12089
|
+
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
12090
|
+
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
12091
|
+
}
|
|
12092
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
12093
|
+
if (status !== "idle") return messages;
|
|
12094
|
+
return messages.map((message) => {
|
|
12095
|
+
const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
12096
|
+
const hasStreamingMeta = meta?.streaming === true;
|
|
12097
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
12098
|
+
return {
|
|
12099
|
+
...message,
|
|
12100
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
12101
|
+
...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
|
|
12102
|
+
};
|
|
12103
|
+
});
|
|
12104
|
+
}
|
|
11899
12105
|
function buildReadChatCommandResult(payload, args) {
|
|
11900
12106
|
let validatedPayload;
|
|
11901
12107
|
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
@@ -12044,7 +12250,7 @@ function buildDebugBundleText(bundle) {
|
|
|
12044
12250
|
}
|
|
12045
12251
|
function getChatDebugBundleDir() {
|
|
12046
12252
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
12047
|
-
return override ||
|
|
12253
|
+
return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
12048
12254
|
}
|
|
12049
12255
|
function safeBundleIdSegment(value, fallback) {
|
|
12050
12256
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -12060,6 +12266,14 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
12060
12266
|
const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
|
|
12061
12267
|
const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
|
|
12062
12268
|
const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
|
|
12269
|
+
const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
|
|
12270
|
+
const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
|
|
12271
|
+
const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
|
|
12272
|
+
const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
|
|
12273
|
+
const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
|
|
12274
|
+
const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
|
|
12275
|
+
const cliStatus = typeof cli?.status === "string" ? cli.status : "";
|
|
12276
|
+
const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
|
|
12063
12277
|
return {
|
|
12064
12278
|
createdAt: bundle.createdAt,
|
|
12065
12279
|
targetSessionId: target.targetSessionId,
|
|
@@ -12068,8 +12282,22 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
12068
12282
|
readChatSuccess: readChat.success,
|
|
12069
12283
|
readChatStatus: readChat.status,
|
|
12070
12284
|
readChatTotalMessages: readChat.totalMessages,
|
|
12285
|
+
readChatReturnedMessages,
|
|
12071
12286
|
cliStatus: cli?.status,
|
|
12287
|
+
cliParsedStatus: cliParsedStatus || void 0,
|
|
12072
12288
|
cliMessageCount: cli?.messageCount,
|
|
12289
|
+
cliParsedMessageCount,
|
|
12290
|
+
cliPartialResponseChars: cliPartialResponse.length,
|
|
12291
|
+
parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
|
|
12292
|
+
parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
|
|
12293
|
+
readChatDebug: Object.keys(debugReadChat).length ? {
|
|
12294
|
+
adapterStatus: debugReadChat.adapterStatus,
|
|
12295
|
+
parsedStatus: debugReadChat.parsedStatus,
|
|
12296
|
+
returnedStatus: debugReadChat.returnedStatus,
|
|
12297
|
+
parsedMsgCount: debugReadChat.parsedMsgCount,
|
|
12298
|
+
returnedMsgCount: debugReadChat.returnedMsgCount,
|
|
12299
|
+
shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
|
|
12300
|
+
} : void 0,
|
|
12073
12301
|
hasFrontendSnapshot: !!frontend
|
|
12074
12302
|
};
|
|
12075
12303
|
}
|
|
@@ -12077,7 +12305,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
12077
12305
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
12078
12306
|
const dir = getChatDebugBundleDir();
|
|
12079
12307
|
fs4.mkdirSync(dir, { recursive: true });
|
|
12080
|
-
const savedPath =
|
|
12308
|
+
const savedPath = path12.join(dir, `${bundleId}.json`);
|
|
12081
12309
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
12082
12310
|
`;
|
|
12083
12311
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -12307,7 +12535,7 @@ async function handleChatHistory(h, args) {
|
|
|
12307
12535
|
}
|
|
12308
12536
|
}
|
|
12309
12537
|
async function handleReadChat(h, args) {
|
|
12310
|
-
const provider = h.getProvider(args?.agentType);
|
|
12538
|
+
const provider = h.getProvider(args?.agentType || args?.providerType);
|
|
12311
12539
|
const transport = getTargetTransport(h, provider);
|
|
12312
12540
|
const historySessionId = getHistorySessionId(h, args);
|
|
12313
12541
|
const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
|
|
@@ -12334,10 +12562,13 @@ async function handleReadChat(h, args) {
|
|
|
12334
12562
|
const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
12335
12563
|
const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
12336
12564
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
12337
|
-
const returnedStatus = parsedRecord.status
|
|
12338
|
-
|
|
12565
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
12566
|
+
const runtimeMessageMerger = getTargetInstance(h, args);
|
|
12567
|
+
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
|
|
12568
|
+
const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
|
|
12569
|
+
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
12570
|
return buildReadChatCommandResult({
|
|
12340
|
-
messages:
|
|
12571
|
+
messages: returnedMessages,
|
|
12341
12572
|
status: returnedStatus,
|
|
12342
12573
|
activeModal,
|
|
12343
12574
|
debugReadChat: {
|
|
@@ -12348,7 +12579,7 @@ async function handleReadChat(h, args) {
|
|
|
12348
12579
|
returnedStatus: String(returnedStatus || ""),
|
|
12349
12580
|
shouldPreferAdapterMessages: false,
|
|
12350
12581
|
parsedMsgCount: parsedRecord.messages.length,
|
|
12351
|
-
returnedMsgCount:
|
|
12582
|
+
returnedMsgCount: returnedMessages.length
|
|
12352
12583
|
},
|
|
12353
12584
|
...title ? { title } : {},
|
|
12354
12585
|
...providerSessionId ? { providerSessionId } : {},
|
|
@@ -13093,9 +13324,17 @@ async function handleResolveAction(h, args) {
|
|
|
13093
13324
|
const targetState = targetInstance?.getState?.();
|
|
13094
13325
|
const surfacedModal = targetState?.activeChat?.activeModal && Array.isArray(targetState.activeChat.activeModal.buttons) && targetState.activeChat.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? targetState.activeChat.activeModal : null;
|
|
13095
13326
|
const statusModal = status?.activeModal && Array.isArray(status.activeModal.buttons) && status.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? status.activeModal : null;
|
|
13096
|
-
const
|
|
13097
|
-
|
|
13098
|
-
|
|
13327
|
+
const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
|
|
13328
|
+
try {
|
|
13329
|
+
return parseMaybeJson(adapter.getScriptParsedStatus());
|
|
13330
|
+
} catch {
|
|
13331
|
+
return null;
|
|
13332
|
+
}
|
|
13333
|
+
})() : null;
|
|
13334
|
+
const parsedModal = parsedStatus?.status === "waiting_approval" && parsedStatus?.activeModal && Array.isArray(parsedStatus.activeModal.buttons) && parsedStatus.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? parsedStatus.activeModal : null;
|
|
13335
|
+
const effectiveModal = statusModal || surfacedModal || parsedModal;
|
|
13336
|
+
const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
|
|
13337
|
+
LOG.info("Command", `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || "")} rawStatus=${String(status?.status || "")} effectiveStatus=${String(effectiveStatus || "")} statusModal=${statusModal ? "yes" : "no"} surfacedModal=${surfacedModal ? "yes" : "no"} parsedModal=${parsedModal ? "yes" : "no"} instance=${targetInstance ? "yes" : "no"}`);
|
|
13099
13338
|
if (!effectiveModal) {
|
|
13100
13339
|
return { success: false, error: "Not in approval state" };
|
|
13101
13340
|
}
|
|
@@ -13221,7 +13460,7 @@ async function handleResolveAction(h, args) {
|
|
|
13221
13460
|
|
|
13222
13461
|
// src/commands/cdp-commands.ts
|
|
13223
13462
|
var fs5 = __toESM(require("fs"));
|
|
13224
|
-
var
|
|
13463
|
+
var path13 = __toESM(require("path"));
|
|
13225
13464
|
var os7 = __toESM(require("os"));
|
|
13226
13465
|
var KEY_TO_VK = {
|
|
13227
13466
|
Backspace: 8,
|
|
@@ -13478,25 +13717,25 @@ function resolveSafePath(requestedPath) {
|
|
|
13478
13717
|
const inputPath = rawPath || ".";
|
|
13479
13718
|
const home = os7.homedir();
|
|
13480
13719
|
if (inputPath.startsWith("~")) {
|
|
13481
|
-
return
|
|
13720
|
+
return path13.resolve(path13.join(home, inputPath.slice(1)));
|
|
13482
13721
|
}
|
|
13483
13722
|
if (process.platform === "win32") {
|
|
13484
13723
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
13485
|
-
if (
|
|
13486
|
-
return
|
|
13724
|
+
if (path13.win32.isAbsolute(normalized)) {
|
|
13725
|
+
return path13.win32.normalize(normalized);
|
|
13487
13726
|
}
|
|
13488
|
-
return
|
|
13727
|
+
return path13.win32.resolve(normalized);
|
|
13489
13728
|
}
|
|
13490
|
-
if (
|
|
13491
|
-
return
|
|
13729
|
+
if (path13.isAbsolute(inputPath)) {
|
|
13730
|
+
return path13.normalize(inputPath);
|
|
13492
13731
|
}
|
|
13493
|
-
return
|
|
13732
|
+
return path13.resolve(inputPath);
|
|
13494
13733
|
}
|
|
13495
13734
|
function listDirectoryEntriesSafe(dirPath) {
|
|
13496
13735
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
13497
13736
|
const files = [];
|
|
13498
13737
|
for (const entry of entries) {
|
|
13499
|
-
const entryPath =
|
|
13738
|
+
const entryPath = path13.join(dirPath, entry.name);
|
|
13500
13739
|
try {
|
|
13501
13740
|
if (entry.isDirectory()) {
|
|
13502
13741
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -13550,7 +13789,7 @@ async function handleFileRead(h, args) {
|
|
|
13550
13789
|
async function handleFileWrite(h, args) {
|
|
13551
13790
|
try {
|
|
13552
13791
|
const filePath = resolveSafePath(args?.path);
|
|
13553
|
-
fs5.mkdirSync(
|
|
13792
|
+
fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
13554
13793
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
13555
13794
|
return { success: true, path: filePath };
|
|
13556
13795
|
} catch (e) {
|
|
@@ -14334,9 +14573,11 @@ var DaemonCommandHandler = class {
|
|
|
14334
14573
|
}
|
|
14335
14574
|
const sessionLookupFailed = !!targetSessionId && !session;
|
|
14336
14575
|
const managerKey = this.extractIdeType(args, sessionLookupFailed);
|
|
14337
|
-
let providerType;
|
|
14576
|
+
let providerType = args?.agentType || args?.providerType;
|
|
14338
14577
|
if (!sessionLookupFailed) {
|
|
14339
|
-
providerType = session?.providerType ||
|
|
14578
|
+
providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
|
|
14579
|
+
} else if (!providerType) {
|
|
14580
|
+
providerType = this.inferProviderType(managerKey);
|
|
14340
14581
|
}
|
|
14341
14582
|
return { session, managerKey, providerType, sessionLookupFailed };
|
|
14342
14583
|
}
|
|
@@ -14416,7 +14657,8 @@ var DaemonCommandHandler = class {
|
|
|
14416
14657
|
"pty_resize",
|
|
14417
14658
|
"invoke_provider_script"
|
|
14418
14659
|
]);
|
|
14419
|
-
|
|
14660
|
+
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);
|
|
14661
|
+
if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
|
|
14420
14662
|
const result2 = {
|
|
14421
14663
|
success: false,
|
|
14422
14664
|
error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
|
|
@@ -14669,7 +14911,7 @@ var DaemonCommandHandler = class {
|
|
|
14669
14911
|
|
|
14670
14912
|
// src/commands/cli-manager.ts
|
|
14671
14913
|
var os13 = __toESM(require("os"));
|
|
14672
|
-
var
|
|
14914
|
+
var path17 = __toESM(require("path"));
|
|
14673
14915
|
var crypto4 = __toESM(require("crypto"));
|
|
14674
14916
|
var import_fs6 = require("fs");
|
|
14675
14917
|
var import_child_process6 = require("child_process");
|
|
@@ -14679,7 +14921,7 @@ init_config();
|
|
|
14679
14921
|
|
|
14680
14922
|
// src/providers/cli-provider-instance.ts
|
|
14681
14923
|
var os12 = __toESM(require("os"));
|
|
14682
|
-
var
|
|
14924
|
+
var path16 = __toESM(require("path"));
|
|
14683
14925
|
var crypto3 = __toESM(require("crypto"));
|
|
14684
14926
|
var fs6 = __toESM(require("fs"));
|
|
14685
14927
|
var import_node_module = require("module");
|
|
@@ -14738,7 +14980,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
14738
14980
|
var CachedDatabaseSync = null;
|
|
14739
14981
|
function getDatabaseSync() {
|
|
14740
14982
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
14741
|
-
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(
|
|
14983
|
+
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
14742
14984
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
14743
14985
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
14744
14986
|
if (!CachedDatabaseSync) {
|
|
@@ -14791,7 +15033,7 @@ var CliProviderInstance = class {
|
|
|
14791
15033
|
this.providerSessionId = options?.providerSessionId;
|
|
14792
15034
|
this.launchMode = options?.launchMode || "new";
|
|
14793
15035
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
14794
|
-
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
|
|
15036
|
+
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
14795
15037
|
this.monitor = new StatusMonitor();
|
|
14796
15038
|
this.historyWriter = new ChatHistoryWriter();
|
|
14797
15039
|
}
|
|
@@ -15268,7 +15510,19 @@ var CliProviderInstance = class {
|
|
|
15268
15510
|
}
|
|
15269
15511
|
}
|
|
15270
15512
|
pushEvent(event) {
|
|
15271
|
-
|
|
15513
|
+
const enrichedEvent = {
|
|
15514
|
+
...event,
|
|
15515
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
|
|
15516
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
|
|
15517
|
+
providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
|
|
15518
|
+
workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
|
|
15519
|
+
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
15520
|
+
};
|
|
15521
|
+
if (this.context?.emitProviderEvent) {
|
|
15522
|
+
this.context.emitProviderEvent(enrichedEvent);
|
|
15523
|
+
return;
|
|
15524
|
+
}
|
|
15525
|
+
this.events.push(enrichedEvent);
|
|
15272
15526
|
}
|
|
15273
15527
|
flushEvents() {
|
|
15274
15528
|
const events = [...this.events];
|
|
@@ -15475,12 +15729,31 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15475
15729
|
);
|
|
15476
15730
|
}
|
|
15477
15731
|
}
|
|
15732
|
+
mergeRuntimeChatMessages(parsedMessages) {
|
|
15733
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
15734
|
+
}
|
|
15478
15735
|
mergeConversationMessages(parsedMessages) {
|
|
15479
15736
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15483
|
-
|
|
15737
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
15738
|
+
message,
|
|
15739
|
+
index,
|
|
15740
|
+
source: "parsed"
|
|
15741
|
+
}));
|
|
15742
|
+
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
15743
|
+
message: entry.message,
|
|
15744
|
+
index: parsedMessages.length + index,
|
|
15745
|
+
source: "runtime"
|
|
15746
|
+
}));
|
|
15747
|
+
const getTime = (message) => {
|
|
15748
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
15749
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
15750
|
+
};
|
|
15751
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
15752
|
+
const aTime = getTime(a.message);
|
|
15753
|
+
const bTime = getTime(b.message);
|
|
15754
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
15755
|
+
if (aTime && !bTime && a.source === "runtime" && b.source === "parsed") return -1;
|
|
15756
|
+
if (!aTime && bTime && a.source === "parsed" && b.source === "runtime") return 1;
|
|
15484
15757
|
return a.index - b.index;
|
|
15485
15758
|
}).map((entry) => entry.message));
|
|
15486
15759
|
}
|
|
@@ -16804,11 +17077,11 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
16804
17077
|
// src/commands/cli-manager.ts
|
|
16805
17078
|
function isExplicitCommand(command) {
|
|
16806
17079
|
const trimmed = command.trim();
|
|
16807
|
-
return
|
|
17080
|
+
return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
16808
17081
|
}
|
|
16809
17082
|
function expandExecutable(command) {
|
|
16810
17083
|
const trimmed = command.trim();
|
|
16811
|
-
return trimmed.startsWith("~") ?
|
|
17084
|
+
return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
16812
17085
|
}
|
|
16813
17086
|
function commandExists(command) {
|
|
16814
17087
|
const trimmed = command.trim();
|
|
@@ -16832,6 +17105,35 @@ function colorize(color, text) {
|
|
|
16832
17105
|
const fn = chalkApi?.[color];
|
|
16833
17106
|
return typeof fn === "function" ? fn(text) : text;
|
|
16834
17107
|
}
|
|
17108
|
+
var COORDINATOR_DELEGATED_ENV_UNSETS = {
|
|
17109
|
+
ADHDEV_INLINE_MESH: "",
|
|
17110
|
+
ADHDEV_MCP_TRANSPORT: "",
|
|
17111
|
+
ADHDEV_MESH_ID: "",
|
|
17112
|
+
HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
|
|
17113
|
+
};
|
|
17114
|
+
function hasCliArg(args, flag) {
|
|
17115
|
+
return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
17116
|
+
}
|
|
17117
|
+
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
17118
|
+
const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
17119
|
+
(0, import_fs6.mkdirSync)(baseDir, { recursive: true });
|
|
17120
|
+
const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
17121
|
+
const filePath = path17.join(baseDir, `${workspaceHash}.json`);
|
|
17122
|
+
(0, import_fs6.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
17123
|
+
return filePath;
|
|
17124
|
+
}
|
|
17125
|
+
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
17126
|
+
const cliType = String(input.cliType || "").trim();
|
|
17127
|
+
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
17128
|
+
const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
|
|
17129
|
+
if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
|
|
17130
|
+
cliArgs.unshift("--ignore-user-config");
|
|
17131
|
+
}
|
|
17132
|
+
if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
|
|
17133
|
+
cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
17134
|
+
}
|
|
17135
|
+
return { cliArgs, env };
|
|
17136
|
+
}
|
|
16835
17137
|
function isUuid(value) {
|
|
16836
17138
|
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
17139
|
}
|
|
@@ -17002,7 +17304,7 @@ var DaemonCliManager = class {
|
|
|
17002
17304
|
attachExisting
|
|
17003
17305
|
}) || void 0;
|
|
17004
17306
|
}
|
|
17005
|
-
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
|
|
17307
|
+
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
|
|
17006
17308
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
17007
17309
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
17008
17310
|
if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
|
|
@@ -17016,7 +17318,7 @@ var DaemonCliManager = class {
|
|
|
17016
17318
|
providerSessionId,
|
|
17017
17319
|
attachExisting
|
|
17018
17320
|
);
|
|
17019
|
-
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
|
|
17321
|
+
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
17020
17322
|
}
|
|
17021
17323
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
17022
17324
|
}
|
|
@@ -17089,7 +17391,7 @@ var DaemonCliManager = class {
|
|
|
17089
17391
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
17090
17392
|
const trimmed = (workingDir || "").trim();
|
|
17091
17393
|
if (!trimmed) throw new Error("working directory required");
|
|
17092
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17394
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
|
|
17093
17395
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
17094
17396
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
17095
17397
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -17219,6 +17521,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17219
17521
|
{
|
|
17220
17522
|
providerSessionId: sessionBinding.providerSessionId,
|
|
17221
17523
|
launchMode: sessionBinding.launchMode,
|
|
17524
|
+
extraEnv: options?.extraEnv,
|
|
17222
17525
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
17223
17526
|
this.persistRecentActivity({
|
|
17224
17527
|
kind: "cli",
|
|
@@ -17239,7 +17542,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17239
17542
|
resolvedCliArgs,
|
|
17240
17543
|
key,
|
|
17241
17544
|
sessionBinding.providerSessionId,
|
|
17242
|
-
false
|
|
17545
|
+
false,
|
|
17546
|
+
options?.extraEnv
|
|
17243
17547
|
);
|
|
17244
17548
|
try {
|
|
17245
17549
|
await adapter.spawn();
|
|
@@ -17463,12 +17767,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17463
17767
|
const dir = resolved.path;
|
|
17464
17768
|
const launchSource = resolved.source;
|
|
17465
17769
|
if (!cliType) throw new Error("cliType required");
|
|
17770
|
+
const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
|
|
17771
|
+
const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
|
|
17772
|
+
cliType,
|
|
17773
|
+
workspace: dir,
|
|
17774
|
+
cliArgs: args?.cliArgs,
|
|
17775
|
+
env: args?.env
|
|
17776
|
+
}) : null;
|
|
17466
17777
|
const started = await this.startSession(
|
|
17467
17778
|
cliType,
|
|
17468
17779
|
dir,
|
|
17469
|
-
args?.cliArgs,
|
|
17780
|
+
delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
|
|
17470
17781
|
args?.initialModel,
|
|
17471
|
-
{
|
|
17782
|
+
{
|
|
17783
|
+
resumeSessionId: args?.resumeSessionId,
|
|
17784
|
+
settingsOverride,
|
|
17785
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
17786
|
+
}
|
|
17472
17787
|
);
|
|
17473
17788
|
return {
|
|
17474
17789
|
success: true,
|
|
@@ -17590,11 +17905,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17590
17905
|
var import_child_process7 = require("child_process");
|
|
17591
17906
|
var net = __toESM(require("net"));
|
|
17592
17907
|
var os15 = __toESM(require("os"));
|
|
17593
|
-
var
|
|
17908
|
+
var path19 = __toESM(require("path"));
|
|
17594
17909
|
|
|
17595
17910
|
// src/providers/provider-loader.ts
|
|
17596
17911
|
var fs7 = __toESM(require("fs"));
|
|
17597
|
-
var
|
|
17912
|
+
var path18 = __toESM(require("path"));
|
|
17598
17913
|
var os14 = __toESM(require("os"));
|
|
17599
17914
|
var chokidar = __toESM(require("chokidar"));
|
|
17600
17915
|
init_logger();
|
|
@@ -17918,7 +18233,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17918
18233
|
try {
|
|
17919
18234
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
17920
18235
|
return ["ide", "extension", "cli", "acp"].some(
|
|
17921
|
-
(category) => fs7.existsSync(
|
|
18236
|
+
(category) => fs7.existsSync(path18.join(candidate, category))
|
|
17922
18237
|
);
|
|
17923
18238
|
} catch {
|
|
17924
18239
|
return false;
|
|
@@ -17926,20 +18241,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17926
18241
|
}
|
|
17927
18242
|
static hasProviderRootMarker(candidate) {
|
|
17928
18243
|
try {
|
|
17929
|
-
return fs7.existsSync(
|
|
18244
|
+
return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
17930
18245
|
} catch {
|
|
17931
18246
|
return false;
|
|
17932
18247
|
}
|
|
17933
18248
|
}
|
|
17934
18249
|
detectDefaultUserDir() {
|
|
17935
|
-
const fallback =
|
|
18250
|
+
const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17936
18251
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17937
18252
|
const visited = /* @__PURE__ */ new Set();
|
|
17938
18253
|
for (const start of this.probeStarts) {
|
|
17939
|
-
let current =
|
|
18254
|
+
let current = path18.resolve(start);
|
|
17940
18255
|
while (!visited.has(current)) {
|
|
17941
18256
|
visited.add(current);
|
|
17942
|
-
const siblingCandidate =
|
|
18257
|
+
const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17943
18258
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17944
18259
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17945
18260
|
if (envOptIn || hasMarker) {
|
|
@@ -17961,7 +18276,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17961
18276
|
return { path: siblingCandidate, source };
|
|
17962
18277
|
}
|
|
17963
18278
|
}
|
|
17964
|
-
const parent =
|
|
18279
|
+
const parent = path18.dirname(current);
|
|
17965
18280
|
if (parent === current) break;
|
|
17966
18281
|
current = parent;
|
|
17967
18282
|
}
|
|
@@ -17971,11 +18286,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17971
18286
|
constructor(options) {
|
|
17972
18287
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17973
18288
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17974
|
-
this.defaultProvidersDir =
|
|
18289
|
+
this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17975
18290
|
const detected = this.detectDefaultUserDir();
|
|
17976
18291
|
this.userDir = detected.path;
|
|
17977
18292
|
this.userDirSource = detected.source;
|
|
17978
|
-
this.upstreamDir =
|
|
18293
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17979
18294
|
this.disableUpstream = false;
|
|
17980
18295
|
this.applySourceConfig({
|
|
17981
18296
|
userDir: options?.userDir,
|
|
@@ -18034,7 +18349,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18034
18349
|
this.userDir = detected.path;
|
|
18035
18350
|
this.userDirSource = detected.source;
|
|
18036
18351
|
}
|
|
18037
|
-
this.upstreamDir =
|
|
18352
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
18038
18353
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
18039
18354
|
if (this.explicitProviderDir) {
|
|
18040
18355
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -18048,7 +18363,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18048
18363
|
* Canonical provider directory shape for a given root.
|
|
18049
18364
|
*/
|
|
18050
18365
|
getProviderDir(root, category, type) {
|
|
18051
|
-
return
|
|
18366
|
+
return path18.join(root, category, type);
|
|
18052
18367
|
}
|
|
18053
18368
|
/**
|
|
18054
18369
|
* Canonical user override directory for a provider.
|
|
@@ -18075,7 +18390,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18075
18390
|
resolveProviderFile(type, ...segments) {
|
|
18076
18391
|
const dir = this.findProviderDirInternal(type);
|
|
18077
18392
|
if (!dir) return null;
|
|
18078
|
-
return
|
|
18393
|
+
return path18.join(dir, ...segments);
|
|
18079
18394
|
}
|
|
18080
18395
|
/**
|
|
18081
18396
|
* Load all providers (3-tier priority)
|
|
@@ -18114,7 +18429,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18114
18429
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
18115
18430
|
try {
|
|
18116
18431
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
18117
|
-
(d) => fs7.statSync(
|
|
18432
|
+
(d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
|
|
18118
18433
|
);
|
|
18119
18434
|
} catch {
|
|
18120
18435
|
return false;
|
|
@@ -18611,8 +18926,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18611
18926
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
18612
18927
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
18613
18928
|
if (providerDir) {
|
|
18614
|
-
const fullDir =
|
|
18615
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18929
|
+
const fullDir = path18.join(providerDir, entry.scriptDir);
|
|
18930
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18616
18931
|
}
|
|
18617
18932
|
matched = true;
|
|
18618
18933
|
}
|
|
@@ -18627,8 +18942,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18627
18942
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18628
18943
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
18629
18944
|
if (providerDir) {
|
|
18630
|
-
const fullDir =
|
|
18631
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18945
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18946
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18632
18947
|
}
|
|
18633
18948
|
}
|
|
18634
18949
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -18645,8 +18960,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18645
18960
|
resolved._resolvedScriptDir = dirOverride;
|
|
18646
18961
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
18647
18962
|
if (providerDir) {
|
|
18648
|
-
const fullDir =
|
|
18649
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18963
|
+
const fullDir = path18.join(providerDir, dirOverride);
|
|
18964
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18650
18965
|
}
|
|
18651
18966
|
}
|
|
18652
18967
|
} else if (override.scripts) {
|
|
@@ -18662,8 +18977,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18662
18977
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18663
18978
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
18664
18979
|
if (providerDir) {
|
|
18665
|
-
const fullDir =
|
|
18666
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18980
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18981
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18667
18982
|
}
|
|
18668
18983
|
}
|
|
18669
18984
|
}
|
|
@@ -18695,14 +19010,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18695
19010
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
18696
19011
|
return null;
|
|
18697
19012
|
}
|
|
18698
|
-
const dir =
|
|
19013
|
+
const dir = path18.join(providerDir, scriptDir);
|
|
18699
19014
|
if (!fs7.existsSync(dir)) {
|
|
18700
19015
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
18701
19016
|
return null;
|
|
18702
19017
|
}
|
|
18703
19018
|
const cached = this.scriptsCache.get(dir);
|
|
18704
19019
|
if (cached) return cached;
|
|
18705
|
-
const scriptsJs =
|
|
19020
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
18706
19021
|
if (fs7.existsSync(scriptsJs)) {
|
|
18707
19022
|
try {
|
|
18708
19023
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -18744,7 +19059,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18744
19059
|
return;
|
|
18745
19060
|
}
|
|
18746
19061
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
18747
|
-
this.log(`File changed: ${
|
|
19062
|
+
this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
|
|
18748
19063
|
this.reload();
|
|
18749
19064
|
}
|
|
18750
19065
|
};
|
|
@@ -18799,7 +19114,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18799
19114
|
}
|
|
18800
19115
|
const https = require("https");
|
|
18801
19116
|
const { execSync: execSync7 } = require("child_process");
|
|
18802
|
-
const metaPath =
|
|
19117
|
+
const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
18803
19118
|
let prevEtag = "";
|
|
18804
19119
|
let prevTimestamp = 0;
|
|
18805
19120
|
try {
|
|
@@ -18859,17 +19174,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18859
19174
|
return { updated: false };
|
|
18860
19175
|
}
|
|
18861
19176
|
this.log("Downloading latest providers from GitHub...");
|
|
18862
|
-
const tmpTar =
|
|
18863
|
-
const tmpExtract =
|
|
19177
|
+
const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
19178
|
+
const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
18864
19179
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
18865
19180
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
18866
19181
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
18867
19182
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
18868
19183
|
const rootDir = extracted.find(
|
|
18869
|
-
(d) => fs7.statSync(
|
|
19184
|
+
(d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
18870
19185
|
);
|
|
18871
19186
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
18872
|
-
const sourceDir =
|
|
19187
|
+
const sourceDir = path18.join(tmpExtract, rootDir);
|
|
18873
19188
|
const backupDir = this.upstreamDir + ".bak";
|
|
18874
19189
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
18875
19190
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -18944,8 +19259,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18944
19259
|
copyDirRecursive(src, dest) {
|
|
18945
19260
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18946
19261
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18947
|
-
const srcPath =
|
|
18948
|
-
const destPath =
|
|
19262
|
+
const srcPath = path18.join(src, entry.name);
|
|
19263
|
+
const destPath = path18.join(dest, entry.name);
|
|
18949
19264
|
if (entry.isDirectory()) {
|
|
18950
19265
|
this.copyDirRecursive(srcPath, destPath);
|
|
18951
19266
|
} else {
|
|
@@ -18956,7 +19271,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18956
19271
|
/** .meta.json save */
|
|
18957
19272
|
writeMeta(metaPath, etag, timestamp) {
|
|
18958
19273
|
try {
|
|
18959
|
-
fs7.mkdirSync(
|
|
19274
|
+
fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
|
|
18960
19275
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18961
19276
|
etag,
|
|
18962
19277
|
timestamp,
|
|
@@ -18973,7 +19288,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18973
19288
|
const scan = (d) => {
|
|
18974
19289
|
try {
|
|
18975
19290
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18976
|
-
if (entry.isDirectory()) scan(
|
|
19291
|
+
if (entry.isDirectory()) scan(path18.join(d, entry.name));
|
|
18977
19292
|
else if (entry.name === "provider.json") count++;
|
|
18978
19293
|
}
|
|
18979
19294
|
} catch {
|
|
@@ -19201,17 +19516,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19201
19516
|
for (const root of searchRoots) {
|
|
19202
19517
|
if (!fs7.existsSync(root)) continue;
|
|
19203
19518
|
const candidate = this.getProviderDir(root, cat, type);
|
|
19204
|
-
if (fs7.existsSync(
|
|
19205
|
-
const catDir =
|
|
19519
|
+
if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
|
|
19520
|
+
const catDir = path18.join(root, cat);
|
|
19206
19521
|
if (fs7.existsSync(catDir)) {
|
|
19207
19522
|
try {
|
|
19208
19523
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
19209
19524
|
if (!entry.isDirectory()) continue;
|
|
19210
|
-
const jsonPath =
|
|
19525
|
+
const jsonPath = path18.join(catDir, entry.name, "provider.json");
|
|
19211
19526
|
if (fs7.existsSync(jsonPath)) {
|
|
19212
19527
|
try {
|
|
19213
19528
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
19214
|
-
if (data.type === type) return
|
|
19529
|
+
if (data.type === type) return path18.join(catDir, entry.name);
|
|
19215
19530
|
} catch {
|
|
19216
19531
|
}
|
|
19217
19532
|
}
|
|
@@ -19228,7 +19543,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19228
19543
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
19229
19544
|
*/
|
|
19230
19545
|
buildScriptWrappersFromDir(dir) {
|
|
19231
|
-
const scriptsJs =
|
|
19546
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
19232
19547
|
if (fs7.existsSync(scriptsJs)) {
|
|
19233
19548
|
try {
|
|
19234
19549
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -19242,7 +19557,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19242
19557
|
for (const file of fs7.readdirSync(dir)) {
|
|
19243
19558
|
if (!file.endsWith(".js")) continue;
|
|
19244
19559
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
19245
|
-
const filePath =
|
|
19560
|
+
const filePath = path18.join(dir, file);
|
|
19246
19561
|
result[scriptName] = (...args) => {
|
|
19247
19562
|
try {
|
|
19248
19563
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -19302,7 +19617,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19302
19617
|
}
|
|
19303
19618
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
19304
19619
|
if (hasJson) {
|
|
19305
|
-
const jsonPath =
|
|
19620
|
+
const jsonPath = path18.join(d, "provider.json");
|
|
19306
19621
|
try {
|
|
19307
19622
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
19308
19623
|
const mod = JSON.parse(raw);
|
|
@@ -19323,7 +19638,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19323
19638
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
19324
19639
|
} else {
|
|
19325
19640
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
19326
|
-
const scriptsPath =
|
|
19641
|
+
const scriptsPath = path18.join(d, "scripts.js");
|
|
19327
19642
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
19328
19643
|
try {
|
|
19329
19644
|
delete require.cache[require.resolve(scriptsPath)];
|
|
@@ -19349,7 +19664,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19349
19664
|
if (!entry.isDirectory()) continue;
|
|
19350
19665
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
19351
19666
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
19352
|
-
scan(
|
|
19667
|
+
scan(path18.join(d, entry.name));
|
|
19353
19668
|
}
|
|
19354
19669
|
}
|
|
19355
19670
|
};
|
|
@@ -19674,8 +19989,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
19674
19989
|
const appNameMap = getMacAppIdentifiers();
|
|
19675
19990
|
const appName = appNameMap[ideId];
|
|
19676
19991
|
if (appName) {
|
|
19677
|
-
const storagePath =
|
|
19678
|
-
process.env.APPDATA ||
|
|
19992
|
+
const storagePath = path19.join(
|
|
19993
|
+
process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
|
|
19679
19994
|
appName,
|
|
19680
19995
|
"storage.json"
|
|
19681
19996
|
);
|
|
@@ -19864,9 +20179,9 @@ init_logger();
|
|
|
19864
20179
|
|
|
19865
20180
|
// src/logging/command-log.ts
|
|
19866
20181
|
var fs8 = __toESM(require("fs"));
|
|
19867
|
-
var
|
|
20182
|
+
var path20 = __toESM(require("path"));
|
|
19868
20183
|
var os16 = __toESM(require("os"));
|
|
19869
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
20184
|
+
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
20185
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
19871
20186
|
var MAX_DAYS = 7;
|
|
19872
20187
|
try {
|
|
@@ -19904,13 +20219,13 @@ function getDateStr2() {
|
|
|
19904
20219
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19905
20220
|
}
|
|
19906
20221
|
var currentDate2 = getDateStr2();
|
|
19907
|
-
var currentFile =
|
|
20222
|
+
var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19908
20223
|
var writeCount2 = 0;
|
|
19909
20224
|
function checkRotation() {
|
|
19910
20225
|
const today = getDateStr2();
|
|
19911
20226
|
if (today !== currentDate2) {
|
|
19912
20227
|
currentDate2 = today;
|
|
19913
|
-
currentFile =
|
|
20228
|
+
currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19914
20229
|
cleanOldFiles();
|
|
19915
20230
|
}
|
|
19916
20231
|
}
|
|
@@ -19924,7 +20239,7 @@ function cleanOldFiles() {
|
|
|
19924
20239
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
19925
20240
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
19926
20241
|
try {
|
|
19927
|
-
fs8.unlinkSync(
|
|
20242
|
+
fs8.unlinkSync(path20.join(LOG_DIR2, file));
|
|
19928
20243
|
} catch {
|
|
19929
20244
|
}
|
|
19930
20245
|
}
|
|
@@ -20007,14 +20322,66 @@ function getRecentCommands(count = 50) {
|
|
|
20007
20322
|
cleanOldFiles();
|
|
20008
20323
|
|
|
20009
20324
|
// src/commands/router.ts
|
|
20325
|
+
var yaml = __toESM(require("js-yaml"));
|
|
20010
20326
|
init_logger();
|
|
20011
20327
|
|
|
20012
20328
|
// src/commands/mesh-coordinator.ts
|
|
20013
|
-
var
|
|
20329
|
+
var import_node_child_process3 = require("child_process");
|
|
20330
|
+
var import_node_fs3 = require("fs");
|
|
20014
20331
|
var import_node_module2 = require("module");
|
|
20332
|
+
var os17 = __toESM(require("os"));
|
|
20015
20333
|
var import_node_path = require("path");
|
|
20016
20334
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
20017
20335
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20336
|
+
var HERMES_CLI_TYPE = "hermes-cli";
|
|
20337
|
+
var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
|
|
20338
|
+
function isHermesProvider(provider, cliType) {
|
|
20339
|
+
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
20340
|
+
return type === HERMES_CLI_TYPE;
|
|
20341
|
+
}
|
|
20342
|
+
function resolveHermesMeshCoordinatorSetup(options) {
|
|
20343
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
20344
|
+
meshId: options.meshId,
|
|
20345
|
+
nodeExecutable: options.nodeExecutable,
|
|
20346
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath
|
|
20347
|
+
});
|
|
20348
|
+
if (!mcpServer) {
|
|
20349
|
+
return {
|
|
20350
|
+
kind: "unsupported",
|
|
20351
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20352
|
+
};
|
|
20353
|
+
}
|
|
20354
|
+
const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
|
|
20355
|
+
if (!configPath.trim()) {
|
|
20356
|
+
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20357
|
+
}
|
|
20358
|
+
return {
|
|
20359
|
+
kind: "auto_import",
|
|
20360
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20361
|
+
configPath,
|
|
20362
|
+
configFormat: "hermes_config_yaml",
|
|
20363
|
+
mcpServer
|
|
20364
|
+
};
|
|
20365
|
+
}
|
|
20366
|
+
function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
|
|
20367
|
+
return {
|
|
20368
|
+
kind: "manual",
|
|
20369
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20370
|
+
configFormat: "hermes_config_yaml",
|
|
20371
|
+
configPathCommand: HERMES_MCP_CONFIG_PATH,
|
|
20372
|
+
requiresRestart: true,
|
|
20373
|
+
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.",
|
|
20374
|
+
template: renderMeshCoordinatorTemplate(
|
|
20375
|
+
"mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
|
|
20376
|
+
{
|
|
20377
|
+
meshId,
|
|
20378
|
+
workspace,
|
|
20379
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20380
|
+
adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
|
|
20381
|
+
}
|
|
20382
|
+
)
|
|
20383
|
+
};
|
|
20384
|
+
}
|
|
20018
20385
|
function resolveMeshCoordinatorSetup(options) {
|
|
20019
20386
|
const { provider, meshId, workspace } = options;
|
|
20020
20387
|
const config = provider?.meshCoordinator;
|
|
@@ -20024,6 +20391,9 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20024
20391
|
reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
|
|
20025
20392
|
};
|
|
20026
20393
|
}
|
|
20394
|
+
if (isHermesProvider(provider, options.cliType)) {
|
|
20395
|
+
return resolveHermesMeshCoordinatorSetup(options);
|
|
20396
|
+
}
|
|
20027
20397
|
const mcpConfig = config.mcpConfig;
|
|
20028
20398
|
if (!mcpConfig || mcpConfig.mode === "none") {
|
|
20029
20399
|
return {
|
|
@@ -20033,8 +20403,8 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20033
20403
|
}
|
|
20034
20404
|
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
|
|
20035
20405
|
if (mcpConfig.mode === "auto_import") {
|
|
20036
|
-
const
|
|
20037
|
-
if (!
|
|
20406
|
+
const path27 = mcpConfig.path?.trim();
|
|
20407
|
+
if (!path27) {
|
|
20038
20408
|
return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
|
|
20039
20409
|
}
|
|
20040
20410
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
@@ -20045,13 +20415,13 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20045
20415
|
if (!mcpServer) {
|
|
20046
20416
|
return {
|
|
20047
20417
|
kind: "unsupported",
|
|
20048
|
-
reason: "Could not resolve the ADHDev MCP server entrypoint
|
|
20418
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20049
20419
|
};
|
|
20050
20420
|
}
|
|
20051
20421
|
return {
|
|
20052
20422
|
kind: "auto_import",
|
|
20053
20423
|
serverName,
|
|
20054
|
-
configPath: (
|
|
20424
|
+
configPath: resolveMcpConfigPath(path27, workspace),
|
|
20055
20425
|
configFormat: mcpConfig.format,
|
|
20056
20426
|
mcpServer
|
|
20057
20427
|
};
|
|
@@ -20085,14 +20455,85 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20085
20455
|
function renderMeshCoordinatorTemplate(template, values) {
|
|
20086
20456
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
|
|
20087
20457
|
}
|
|
20458
|
+
function resolveMcpConfigPath(configPath, workspace) {
|
|
20459
|
+
const trimmed = configPath.trim();
|
|
20460
|
+
if (trimmed === "~") return os17.homedir();
|
|
20461
|
+
if (trimmed.startsWith("~/")) return (0, import_node_path.join)(os17.homedir(), trimmed.slice(2));
|
|
20462
|
+
if ((0, import_node_path.isAbsolute)(trimmed)) return trimmed;
|
|
20463
|
+
return (0, import_node_path.join)(workspace, trimmed);
|
|
20464
|
+
}
|
|
20088
20465
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
20089
20466
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
20090
20467
|
if (!entryPath) return null;
|
|
20468
|
+
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
|
|
20469
|
+
if (!nodeExecutable) return null;
|
|
20091
20470
|
return {
|
|
20092
|
-
command:
|
|
20093
|
-
args: [entryPath, "--repo-mesh", options.meshId]
|
|
20471
|
+
command: nodeExecutable,
|
|
20472
|
+
args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
|
|
20094
20473
|
};
|
|
20095
20474
|
}
|
|
20475
|
+
function resolveMcpNodeExecutable(explicitExecutable) {
|
|
20476
|
+
const explicit = explicitExecutable?.trim();
|
|
20477
|
+
if (explicit) return explicit;
|
|
20478
|
+
const candidates = [];
|
|
20479
|
+
const addCandidate = (candidate) => {
|
|
20480
|
+
const trimmed = candidate?.trim();
|
|
20481
|
+
if (!trimmed) return;
|
|
20482
|
+
const normalized = normalizeExistingPath(trimmed) || trimmed;
|
|
20483
|
+
if (!candidates.includes(normalized)) candidates.push(normalized);
|
|
20484
|
+
};
|
|
20485
|
+
addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
|
|
20486
|
+
addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
|
|
20487
|
+
addCandidate(process.env.npm_node_execpath);
|
|
20488
|
+
addNodeCandidatesFromPath(process.env.PATH, addCandidate);
|
|
20489
|
+
addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
|
|
20490
|
+
addCandidate("/opt/homebrew/bin/node");
|
|
20491
|
+
addCandidate("/usr/local/bin/node");
|
|
20492
|
+
addCandidate("/usr/bin/node");
|
|
20493
|
+
addCandidate(process.execPath);
|
|
20494
|
+
for (const candidate of candidates) {
|
|
20495
|
+
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
|
|
20496
|
+
}
|
|
20497
|
+
return null;
|
|
20498
|
+
}
|
|
20499
|
+
function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
20500
|
+
for (const entry of (pathValue || "").split(":")) {
|
|
20501
|
+
const dir = entry.trim();
|
|
20502
|
+
if (!dir) continue;
|
|
20503
|
+
addCandidate((0, import_node_path.join)(dir, "node"));
|
|
20504
|
+
}
|
|
20505
|
+
}
|
|
20506
|
+
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
20507
|
+
const versionsDir = (0, import_node_path.join)(homeDir, ".nvm", "versions", "node");
|
|
20508
|
+
try {
|
|
20509
|
+
const versionDirs = (0, import_node_fs3.readdirSync)(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
20510
|
+
for (const versionDir of versionDirs) {
|
|
20511
|
+
addCandidate((0, import_node_path.join)(versionsDir, versionDir, "bin", "node"));
|
|
20512
|
+
}
|
|
20513
|
+
} catch {
|
|
20514
|
+
}
|
|
20515
|
+
}
|
|
20516
|
+
function compareNodeVersionNamesDescending(a, b) {
|
|
20517
|
+
const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
20518
|
+
const left = parse(a);
|
|
20519
|
+
const right = parse(b);
|
|
20520
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
20521
|
+
const diff = (right[i] || 0) - (left[i] || 0);
|
|
20522
|
+
if (diff !== 0) return diff;
|
|
20523
|
+
}
|
|
20524
|
+
return b.localeCompare(a);
|
|
20525
|
+
}
|
|
20526
|
+
function nodeRuntimeSupportsWebSocket(nodeExecutable) {
|
|
20527
|
+
try {
|
|
20528
|
+
(0, import_node_child_process3.execFileSync)(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
|
|
20529
|
+
stdio: "ignore",
|
|
20530
|
+
timeout: 3e3
|
|
20531
|
+
});
|
|
20532
|
+
return true;
|
|
20533
|
+
} catch {
|
|
20534
|
+
return false;
|
|
20535
|
+
}
|
|
20536
|
+
}
|
|
20096
20537
|
function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
20097
20538
|
const explicit = explicitPath?.trim();
|
|
20098
20539
|
if (explicit) return normalizeExistingPath(explicit) || explicit;
|
|
@@ -20128,15 +20569,109 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
20128
20569
|
}
|
|
20129
20570
|
function normalizeExistingPath(filePath) {
|
|
20130
20571
|
try {
|
|
20131
|
-
if (!(0,
|
|
20132
|
-
return
|
|
20572
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return null;
|
|
20573
|
+
return import_node_fs3.realpathSync.native(filePath);
|
|
20133
20574
|
} catch {
|
|
20134
20575
|
return null;
|
|
20135
20576
|
}
|
|
20136
20577
|
}
|
|
20137
20578
|
|
|
20579
|
+
// src/mesh/mesh-events.ts
|
|
20580
|
+
init_mesh_config();
|
|
20581
|
+
init_logger();
|
|
20582
|
+
function readNonEmptyString(value) {
|
|
20583
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
20584
|
+
}
|
|
20585
|
+
function formatCompletionMetadata(event) {
|
|
20586
|
+
const parts = [
|
|
20587
|
+
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
20588
|
+
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
20589
|
+
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
20590
|
+
].filter(Boolean);
|
|
20591
|
+
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
20592
|
+
}
|
|
20593
|
+
function buildMeshSystemMessage(args) {
|
|
20594
|
+
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
20595
|
+
if (args.event === "agent:generating_completed") {
|
|
20596
|
+
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path; use mesh_read_chat once to review its final progress, but do not poll repeatedly.`;
|
|
20597
|
+
}
|
|
20598
|
+
if (args.event === "agent:waiting_approval") {
|
|
20599
|
+
return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
20600
|
+
}
|
|
20601
|
+
return "";
|
|
20602
|
+
}
|
|
20603
|
+
function injectMeshSystemMessage(components, args) {
|
|
20604
|
+
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
20605
|
+
const instState = inst.getState();
|
|
20606
|
+
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
20607
|
+
if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
|
|
20608
|
+
return true;
|
|
20609
|
+
});
|
|
20610
|
+
if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
|
|
20611
|
+
const messageText = buildMeshSystemMessage({
|
|
20612
|
+
event: args.event,
|
|
20613
|
+
nodeLabel: args.nodeLabel,
|
|
20614
|
+
metadataEvent: args.metadataEvent
|
|
20615
|
+
});
|
|
20616
|
+
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
20617
|
+
for (const coord of coordinatorInstances) {
|
|
20618
|
+
const coordState = coord.getState();
|
|
20619
|
+
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
20620
|
+
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
20621
|
+
}
|
|
20622
|
+
return { success: true, forwarded: coordinatorInstances.length };
|
|
20623
|
+
}
|
|
20624
|
+
function handleMeshForwardEvent(components, payload) {
|
|
20625
|
+
const eventName = readNonEmptyString(payload.event);
|
|
20626
|
+
if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
|
|
20627
|
+
return { success: false, error: "unsupported mesh event" };
|
|
20628
|
+
}
|
|
20629
|
+
const meshId = readNonEmptyString(payload.meshId);
|
|
20630
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
20631
|
+
const nodeId = readNonEmptyString(payload.nodeId);
|
|
20632
|
+
const workspace = readNonEmptyString(payload.workspace);
|
|
20633
|
+
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
20634
|
+
return injectMeshSystemMessage(components, {
|
|
20635
|
+
meshId,
|
|
20636
|
+
nodeLabel,
|
|
20637
|
+
event: eventName,
|
|
20638
|
+
metadataEvent: {
|
|
20639
|
+
targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
|
|
20640
|
+
providerType: readNonEmptyString(payload.providerType),
|
|
20641
|
+
providerSessionId: readNonEmptyString(payload.providerSessionId)
|
|
20642
|
+
}
|
|
20643
|
+
});
|
|
20644
|
+
}
|
|
20645
|
+
function setupMeshEventForwarding(components) {
|
|
20646
|
+
components.instanceManager.onEvent((event) => {
|
|
20647
|
+
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
20648
|
+
const instanceId = readNonEmptyString(event.instanceId);
|
|
20649
|
+
if (!instanceId) return;
|
|
20650
|
+
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
20651
|
+
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
20652
|
+
const state = sourceInstance.getState();
|
|
20653
|
+
const workspace = readNonEmptyString(state.workspace);
|
|
20654
|
+
if (!workspace) return;
|
|
20655
|
+
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
20656
|
+
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
20657
|
+
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
20658
|
+
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
20659
|
+
if (!meshId) return;
|
|
20660
|
+
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
20661
|
+
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
20662
|
+
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
20663
|
+
injectMeshSystemMessage(components, {
|
|
20664
|
+
meshId,
|
|
20665
|
+
sourceInstanceId: instanceId,
|
|
20666
|
+
nodeLabel,
|
|
20667
|
+
event: event.event,
|
|
20668
|
+
metadataEvent: event
|
|
20669
|
+
});
|
|
20670
|
+
});
|
|
20671
|
+
}
|
|
20672
|
+
|
|
20138
20673
|
// src/status/snapshot.ts
|
|
20139
|
-
var
|
|
20674
|
+
var os18 = __toESM(require("os"));
|
|
20140
20675
|
init_config();
|
|
20141
20676
|
init_terminal_screen();
|
|
20142
20677
|
init_logger();
|
|
@@ -20192,8 +20727,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20192
20727
|
}
|
|
20193
20728
|
function buildMachineInfo(profile = "full") {
|
|
20194
20729
|
const base = {
|
|
20195
|
-
hostname:
|
|
20196
|
-
platform:
|
|
20730
|
+
hostname: os18.hostname(),
|
|
20731
|
+
platform: os18.platform()
|
|
20197
20732
|
};
|
|
20198
20733
|
if (profile === "live") {
|
|
20199
20734
|
return base;
|
|
@@ -20202,23 +20737,23 @@ function buildMachineInfo(profile = "full") {
|
|
|
20202
20737
|
const memSnap2 = getHostMemorySnapshot();
|
|
20203
20738
|
return {
|
|
20204
20739
|
...base,
|
|
20205
|
-
arch:
|
|
20206
|
-
cpus:
|
|
20740
|
+
arch: os18.arch(),
|
|
20741
|
+
cpus: os18.cpus().length,
|
|
20207
20742
|
totalMem: memSnap2.totalMem,
|
|
20208
|
-
release:
|
|
20743
|
+
release: os18.release()
|
|
20209
20744
|
};
|
|
20210
20745
|
}
|
|
20211
20746
|
const memSnap = getHostMemorySnapshot();
|
|
20212
20747
|
return {
|
|
20213
20748
|
...base,
|
|
20214
|
-
arch:
|
|
20215
|
-
cpus:
|
|
20749
|
+
arch: os18.arch(),
|
|
20750
|
+
cpus: os18.cpus().length,
|
|
20216
20751
|
totalMem: memSnap.totalMem,
|
|
20217
20752
|
freeMem: memSnap.freeMem,
|
|
20218
20753
|
availableMem: memSnap.availableMem,
|
|
20219
|
-
loadavg:
|
|
20220
|
-
uptime:
|
|
20221
|
-
release:
|
|
20754
|
+
loadavg: os18.loadavg(),
|
|
20755
|
+
uptime: os18.uptime(),
|
|
20756
|
+
release: os18.release()
|
|
20222
20757
|
};
|
|
20223
20758
|
}
|
|
20224
20759
|
function parseMessageTime(value) {
|
|
@@ -20452,14 +20987,14 @@ function buildStatusSnapshot(options) {
|
|
|
20452
20987
|
var import_child_process8 = require("child_process");
|
|
20453
20988
|
var import_child_process9 = require("child_process");
|
|
20454
20989
|
var fs9 = __toESM(require("fs"));
|
|
20455
|
-
var
|
|
20456
|
-
var
|
|
20990
|
+
var os19 = __toESM(require("os"));
|
|
20991
|
+
var path21 = __toESM(require("path"));
|
|
20457
20992
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
20458
20993
|
function getUpgradeLogPath() {
|
|
20459
|
-
const home =
|
|
20460
|
-
const dir =
|
|
20994
|
+
const home = os19.homedir();
|
|
20995
|
+
const dir = path21.join(home, ".adhdev");
|
|
20461
20996
|
fs9.mkdirSync(dir, { recursive: true });
|
|
20462
|
-
return
|
|
20997
|
+
return path21.join(dir, "daemon-upgrade.log");
|
|
20463
20998
|
}
|
|
20464
20999
|
function appendUpgradeLog(message) {
|
|
20465
21000
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -20470,14 +21005,14 @@ function appendUpgradeLog(message) {
|
|
|
20470
21005
|
}
|
|
20471
21006
|
}
|
|
20472
21007
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
20473
|
-
const binDir =
|
|
21008
|
+
const binDir = path21.dirname(nodeExecutable);
|
|
20474
21009
|
if (platform10 === "win32") {
|
|
20475
|
-
const npmCliPath =
|
|
21010
|
+
const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
20476
21011
|
if (fs9.existsSync(npmCliPath)) {
|
|
20477
21012
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20478
21013
|
}
|
|
20479
21014
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
20480
|
-
const candidatePath =
|
|
21015
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20481
21016
|
if (fs9.existsSync(candidatePath)) {
|
|
20482
21017
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20483
21018
|
}
|
|
@@ -20485,7 +21020,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
20485
21020
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20486
21021
|
}
|
|
20487
21022
|
for (const candidate of ["npm"]) {
|
|
20488
|
-
const candidatePath =
|
|
21023
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20489
21024
|
if (fs9.existsSync(candidatePath)) {
|
|
20490
21025
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20491
21026
|
}
|
|
@@ -20502,13 +21037,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20502
21037
|
let currentDir = resolvedPath;
|
|
20503
21038
|
try {
|
|
20504
21039
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
20505
|
-
currentDir =
|
|
21040
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20506
21041
|
}
|
|
20507
21042
|
} catch {
|
|
20508
|
-
currentDir =
|
|
21043
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20509
21044
|
}
|
|
20510
21045
|
while (true) {
|
|
20511
|
-
const packageJsonPath =
|
|
21046
|
+
const packageJsonPath = path21.join(currentDir, "package.json");
|
|
20512
21047
|
try {
|
|
20513
21048
|
if (fs9.existsSync(packageJsonPath)) {
|
|
20514
21049
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -20519,7 +21054,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20519
21054
|
}
|
|
20520
21055
|
} catch {
|
|
20521
21056
|
}
|
|
20522
|
-
const parentDir =
|
|
21057
|
+
const parentDir = path21.dirname(currentDir);
|
|
20523
21058
|
if (parentDir === currentDir) {
|
|
20524
21059
|
return null;
|
|
20525
21060
|
}
|
|
@@ -20527,13 +21062,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20527
21062
|
}
|
|
20528
21063
|
}
|
|
20529
21064
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
20530
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
20531
|
-
if (
|
|
21065
|
+
const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
|
|
21066
|
+
if (path21.basename(nodeModulesDir) !== "node_modules") {
|
|
20532
21067
|
return null;
|
|
20533
21068
|
}
|
|
20534
|
-
const maybeLibDir =
|
|
20535
|
-
if (
|
|
20536
|
-
return
|
|
21069
|
+
const maybeLibDir = path21.dirname(nodeModulesDir);
|
|
21070
|
+
if (path21.basename(maybeLibDir) === "lib") {
|
|
21071
|
+
return path21.dirname(maybeLibDir);
|
|
20537
21072
|
}
|
|
20538
21073
|
return maybeLibDir;
|
|
20539
21074
|
}
|
|
@@ -20648,7 +21183,7 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
20648
21183
|
}
|
|
20649
21184
|
}
|
|
20650
21185
|
function stopSessionHostProcesses(appName) {
|
|
20651
|
-
const pidFile =
|
|
21186
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
20652
21187
|
try {
|
|
20653
21188
|
if (fs9.existsSync(pidFile)) {
|
|
20654
21189
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -20665,7 +21200,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
20665
21200
|
}
|
|
20666
21201
|
}
|
|
20667
21202
|
function removeDaemonPidFile() {
|
|
20668
|
-
const pidFile =
|
|
21203
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
20669
21204
|
try {
|
|
20670
21205
|
fs9.unlinkSync(pidFile);
|
|
20671
21206
|
} catch {
|
|
@@ -20676,7 +21211,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20676
21211
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20677
21212
|
if (!npmRoot) return;
|
|
20678
21213
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20679
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
21214
|
+
const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
|
|
20680
21215
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
20681
21216
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
20682
21217
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -20684,25 +21219,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20684
21219
|
}
|
|
20685
21220
|
if (pkgName.startsWith("@")) {
|
|
20686
21221
|
const [scope, name] = pkgName.split("/");
|
|
20687
|
-
const scopeDir =
|
|
21222
|
+
const scopeDir = path21.join(npmRoot, scope);
|
|
20688
21223
|
if (!fs9.existsSync(scopeDir)) return;
|
|
20689
21224
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
20690
21225
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
20691
|
-
fs9.rmSync(
|
|
20692
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
21226
|
+
fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
|
|
21227
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
|
|
20693
21228
|
}
|
|
20694
21229
|
} else {
|
|
20695
21230
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
20696
21231
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
20697
|
-
fs9.rmSync(
|
|
20698
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
21232
|
+
fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
|
|
21233
|
+
appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
|
|
20699
21234
|
}
|
|
20700
21235
|
}
|
|
20701
21236
|
if (fs9.existsSync(binDir)) {
|
|
20702
21237
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
20703
21238
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
20704
|
-
fs9.rmSync(
|
|
20705
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
21239
|
+
fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
|
|
21240
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
|
|
20706
21241
|
}
|
|
20707
21242
|
}
|
|
20708
21243
|
}
|
|
@@ -20803,6 +21338,56 @@ function normalizeReleaseChannel(value) {
|
|
|
20803
21338
|
function resolveUpgradeChannel(args) {
|
|
20804
21339
|
return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
|
|
20805
21340
|
}
|
|
21341
|
+
function readProviderPriorityFromPolicy(policy) {
|
|
21342
|
+
const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
|
|
21343
|
+
const raw = record.providerPriority;
|
|
21344
|
+
if (!Array.isArray(raw)) return [];
|
|
21345
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21346
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
21347
|
+
if (seen.has(type)) return false;
|
|
21348
|
+
seen.add(type);
|
|
21349
|
+
return true;
|
|
21350
|
+
});
|
|
21351
|
+
}
|
|
21352
|
+
async function resolveProviderTypeFromPriority(args) {
|
|
21353
|
+
if (!args.providerPriority.length) {
|
|
21354
|
+
return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
|
|
21355
|
+
}
|
|
21356
|
+
const failed = [];
|
|
21357
|
+
for (const requestedType of args.providerPriority) {
|
|
21358
|
+
const normalizedType = args.providerLoader.resolveAlias(requestedType);
|
|
21359
|
+
if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
21360
|
+
failed.push(`${requestedType}: disabled`);
|
|
21361
|
+
continue;
|
|
21362
|
+
}
|
|
21363
|
+
const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
|
|
21364
|
+
args.providerLoader.setCliDetectionResults([{
|
|
21365
|
+
id: normalizedType,
|
|
21366
|
+
installed: !!detected,
|
|
21367
|
+
path: detected?.path
|
|
21368
|
+
}], false);
|
|
21369
|
+
args.onStatusChange?.();
|
|
21370
|
+
if (detected) return { providerType: normalizedType };
|
|
21371
|
+
failed.push(`${requestedType}: not detected`);
|
|
21372
|
+
}
|
|
21373
|
+
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
21374
|
+
}
|
|
21375
|
+
function loadYamlModule() {
|
|
21376
|
+
return yaml;
|
|
21377
|
+
}
|
|
21378
|
+
function getMcpServersKey(format) {
|
|
21379
|
+
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
21380
|
+
}
|
|
21381
|
+
function parseMeshCoordinatorMcpConfig(text, format) {
|
|
21382
|
+
if (!text.trim()) return {};
|
|
21383
|
+
if (format === "claude_mcp_json") return JSON.parse(text);
|
|
21384
|
+
const parsed = loadYamlModule().load(text);
|
|
21385
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
21386
|
+
}
|
|
21387
|
+
function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
21388
|
+
if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
|
|
21389
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
21390
|
+
}
|
|
20806
21391
|
var CHAT_COMMANDS = [
|
|
20807
21392
|
"send_chat",
|
|
20808
21393
|
"new_chat",
|
|
@@ -20901,6 +21486,154 @@ var DaemonCommandRouter = class {
|
|
|
20901
21486
|
constructor(deps) {
|
|
20902
21487
|
this.deps = deps;
|
|
20903
21488
|
}
|
|
21489
|
+
getCachedInlineMesh(meshId, inlineMesh) {
|
|
21490
|
+
if (inlineMesh && typeof inlineMesh === "object") {
|
|
21491
|
+
this.inlineMeshCache.set(meshId, inlineMesh);
|
|
21492
|
+
return inlineMesh;
|
|
21493
|
+
}
|
|
21494
|
+
return this.inlineMeshCache.get(meshId);
|
|
21495
|
+
}
|
|
21496
|
+
async getMeshForCommand(meshId, inlineMesh) {
|
|
21497
|
+
try {
|
|
21498
|
+
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21499
|
+
const mesh = getMesh3(meshId);
|
|
21500
|
+
if (mesh) return { mesh, inline: false };
|
|
21501
|
+
} catch {
|
|
21502
|
+
}
|
|
21503
|
+
const cached = this.getCachedInlineMesh(meshId, inlineMesh);
|
|
21504
|
+
return cached ? { mesh: cached, inline: true } : null;
|
|
21505
|
+
}
|
|
21506
|
+
updateInlineMeshNode(meshId, mesh, node) {
|
|
21507
|
+
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
21508
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
21509
|
+
if (idx >= 0) mesh.nodes[idx] = node;
|
|
21510
|
+
else mesh.nodes.push(node);
|
|
21511
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21512
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21513
|
+
}
|
|
21514
|
+
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
21515
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
21516
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
|
|
21517
|
+
if (idx === -1) return false;
|
|
21518
|
+
mesh.nodes.splice(idx, 1);
|
|
21519
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21520
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21521
|
+
return true;
|
|
21522
|
+
}
|
|
21523
|
+
normalizeMeshSessionCleanupMode(value) {
|
|
21524
|
+
return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
|
|
21525
|
+
}
|
|
21526
|
+
sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
|
|
21527
|
+
const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
|
|
21528
|
+
if (!sessionId) return false;
|
|
21529
|
+
if (sessionIds?.size) return sessionIds.has(sessionId);
|
|
21530
|
+
const workspace = typeof node?.workspace === "string" ? node.workspace : "";
|
|
21531
|
+
if (workspace && record?.workspace === workspace) return true;
|
|
21532
|
+
if (record?.meta?.meshNodeId === nodeId) return true;
|
|
21533
|
+
return false;
|
|
21534
|
+
}
|
|
21535
|
+
isCompletedHostedSession(record) {
|
|
21536
|
+
return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
|
|
21537
|
+
}
|
|
21538
|
+
async cleanupMeshSessions(args) {
|
|
21539
|
+
if (args.mode === "preserve") {
|
|
21540
|
+
return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
|
|
21541
|
+
}
|
|
21542
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
21543
|
+
const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
|
|
21544
|
+
const sessions = await this.deps.sessionHostControl.listSessions();
|
|
21545
|
+
const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
|
|
21546
|
+
const hasExplicitSessionIds = !!requestedSessionIds?.size;
|
|
21547
|
+
const stoppedSessionIds = [];
|
|
21548
|
+
const deletedSessionIds = [];
|
|
21549
|
+
const skippedSessionIds = [];
|
|
21550
|
+
const skippedLiveSessionIds = [];
|
|
21551
|
+
const deleteUnsupportedSessionIds = [];
|
|
21552
|
+
const recordsRemainSessionIds = [];
|
|
21553
|
+
const errors = [];
|
|
21554
|
+
const matchedBySurfaceKind = {
|
|
21555
|
+
live_runtime: 0,
|
|
21556
|
+
recovery_snapshot: 0,
|
|
21557
|
+
inactive_record: 0
|
|
21558
|
+
};
|
|
21559
|
+
for (const record of matched) {
|
|
21560
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21561
|
+
matchedBySurfaceKind[surfaceKind] += 1;
|
|
21562
|
+
}
|
|
21563
|
+
for (const record of matched) {
|
|
21564
|
+
const sessionId = String(record.sessionId);
|
|
21565
|
+
const completed = this.isCompletedHostedSession(record);
|
|
21566
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21567
|
+
const liveRuntime = surfaceKind === "live_runtime";
|
|
21568
|
+
if (!hasExplicitSessionIds && liveRuntime) {
|
|
21569
|
+
skippedSessionIds.push(sessionId);
|
|
21570
|
+
skippedLiveSessionIds.push(sessionId);
|
|
21571
|
+
continue;
|
|
21572
|
+
}
|
|
21573
|
+
try {
|
|
21574
|
+
if (args.mode === "stop") {
|
|
21575
|
+
if (!completed) {
|
|
21576
|
+
if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21577
|
+
stoppedSessionIds.push(sessionId);
|
|
21578
|
+
} else {
|
|
21579
|
+
skippedSessionIds.push(sessionId);
|
|
21580
|
+
}
|
|
21581
|
+
continue;
|
|
21582
|
+
}
|
|
21583
|
+
if (args.mode === "delete_stopped") {
|
|
21584
|
+
if (completed) {
|
|
21585
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
|
|
21586
|
+
deletedSessionIds.push(sessionId);
|
|
21587
|
+
} else {
|
|
21588
|
+
skippedSessionIds.push(sessionId);
|
|
21589
|
+
}
|
|
21590
|
+
continue;
|
|
21591
|
+
}
|
|
21592
|
+
if (args.mode === "stop_and_delete") {
|
|
21593
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
|
|
21594
|
+
deletedSessionIds.push(sessionId);
|
|
21595
|
+
continue;
|
|
21596
|
+
}
|
|
21597
|
+
} catch (e) {
|
|
21598
|
+
const message = e?.message || String(e);
|
|
21599
|
+
if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
|
|
21600
|
+
deleteUnsupportedSessionIds.push(sessionId);
|
|
21601
|
+
recordsRemainSessionIds.push(sessionId);
|
|
21602
|
+
if (args.mode === "stop_and_delete" && !completed) {
|
|
21603
|
+
try {
|
|
21604
|
+
await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21605
|
+
stoppedSessionIds.push(sessionId);
|
|
21606
|
+
} catch (stopError) {
|
|
21607
|
+
errors.push({ sessionId, error: stopError?.message || String(stopError) });
|
|
21608
|
+
continue;
|
|
21609
|
+
}
|
|
21610
|
+
}
|
|
21611
|
+
skippedSessionIds.push(sessionId);
|
|
21612
|
+
continue;
|
|
21613
|
+
}
|
|
21614
|
+
errors.push({ sessionId, error: message });
|
|
21615
|
+
}
|
|
21616
|
+
}
|
|
21617
|
+
const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
|
|
21618
|
+
return {
|
|
21619
|
+
success: errors.length === 0,
|
|
21620
|
+
mode: args.mode,
|
|
21621
|
+
dryRun: args.dryRun === true,
|
|
21622
|
+
matchedCount: matched.length,
|
|
21623
|
+
matchedBySurfaceKind,
|
|
21624
|
+
stoppedSessionIds,
|
|
21625
|
+
deletedSessionIds,
|
|
21626
|
+
skippedSessionIds,
|
|
21627
|
+
skippedLiveSessionIds,
|
|
21628
|
+
...deleteUnsupported ? {
|
|
21629
|
+
deleteUnsupported: true,
|
|
21630
|
+
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
21631
|
+
deleteUnsupportedSessionIds,
|
|
21632
|
+
recordsRemainSessionIds
|
|
21633
|
+
} : {},
|
|
21634
|
+
...errors.length ? { errors } : {}
|
|
21635
|
+
};
|
|
21636
|
+
}
|
|
20904
21637
|
async traceSessionHostAction(action, args, run, summarizeResult) {
|
|
20905
21638
|
const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
|
|
20906
21639
|
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -21020,6 +21753,9 @@ var DaemonCommandRouter = class {
|
|
|
21020
21753
|
async executeDaemonCommand(cmd, args) {
|
|
21021
21754
|
switch (cmd) {
|
|
21022
21755
|
// ─── CLI / ACP commands ───
|
|
21756
|
+
case "mesh_forward_event": {
|
|
21757
|
+
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
21758
|
+
}
|
|
21023
21759
|
case "launch_cli":
|
|
21024
21760
|
case "stop_cli":
|
|
21025
21761
|
case "set_cli_view_mode":
|
|
@@ -21564,7 +22300,26 @@ var DaemonCommandRouter = class {
|
|
|
21564
22300
|
if (!name) return { success: false, error: "name required" };
|
|
21565
22301
|
try {
|
|
21566
22302
|
const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21567
|
-
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
|
|
22303
|
+
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
|
|
22304
|
+
return { success: true, mesh };
|
|
22305
|
+
} catch (e) {
|
|
22306
|
+
return { success: false, error: e.message };
|
|
22307
|
+
}
|
|
22308
|
+
}
|
|
22309
|
+
case "update_mesh": {
|
|
22310
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22311
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22312
|
+
try {
|
|
22313
|
+
const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22314
|
+
const patch = {};
|
|
22315
|
+
if (typeof args?.name === "string") patch.name = args.name;
|
|
22316
|
+
if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
|
|
22317
|
+
if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
|
|
22318
|
+
if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
|
|
22319
|
+
if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
|
|
22320
|
+
const mesh = updateMesh2(meshId, patch);
|
|
22321
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22322
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21568
22323
|
return { success: true, mesh };
|
|
21569
22324
|
} catch (e) {
|
|
21570
22325
|
return { success: false, error: e.message };
|
|
@@ -21588,21 +22343,164 @@ var DaemonCommandRouter = class {
|
|
|
21588
22343
|
if (!workspace) return { success: false, error: "workspace required" };
|
|
21589
22344
|
try {
|
|
21590
22345
|
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21591
|
-
const
|
|
22346
|
+
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
22347
|
+
const readOnly = args?.readOnly === true;
|
|
22348
|
+
const policy = {
|
|
22349
|
+
...readOnly ? { readOnly: true } : {},
|
|
22350
|
+
...providerPriority.length ? { providerPriority } : {}
|
|
22351
|
+
};
|
|
22352
|
+
const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
|
|
21592
22353
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
21593
22354
|
return { success: true, node };
|
|
21594
22355
|
} catch (e) {
|
|
21595
22356
|
return { success: false, error: e.message };
|
|
21596
22357
|
}
|
|
21597
22358
|
}
|
|
22359
|
+
case "update_mesh_node": {
|
|
22360
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22361
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22362
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22363
|
+
try {
|
|
22364
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22365
|
+
const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
|
|
22366
|
+
if (Array.isArray(args?.providerPriority)) {
|
|
22367
|
+
const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
|
|
22368
|
+
delete policy.provider_priority;
|
|
22369
|
+
if (providerPriority.length) {
|
|
22370
|
+
policy.providerPriority = providerPriority;
|
|
22371
|
+
} else {
|
|
22372
|
+
delete policy.providerPriority;
|
|
22373
|
+
}
|
|
22374
|
+
}
|
|
22375
|
+
const node = updateNode2(meshId, nodeId, { policy });
|
|
22376
|
+
if (!node) return { success: false, error: "Mesh node not found" };
|
|
22377
|
+
return { success: true, node };
|
|
22378
|
+
} catch (e) {
|
|
22379
|
+
return { success: false, error: e.message };
|
|
22380
|
+
}
|
|
22381
|
+
}
|
|
22382
|
+
case "cleanup_mesh_sessions": {
|
|
22383
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22384
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22385
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22386
|
+
try {
|
|
22387
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22388
|
+
const mesh = meshRecord?.mesh;
|
|
22389
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22390
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22391
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
22392
|
+
const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
|
|
22393
|
+
const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
|
|
22394
|
+
const result = await this.cleanupMeshSessions({
|
|
22395
|
+
meshId,
|
|
22396
|
+
nodeId,
|
|
22397
|
+
node,
|
|
22398
|
+
mode,
|
|
22399
|
+
sessionIds,
|
|
22400
|
+
dryRun: args?.dryRun === true
|
|
22401
|
+
});
|
|
22402
|
+
return result;
|
|
22403
|
+
} catch (e) {
|
|
22404
|
+
return { success: false, error: e.message };
|
|
22405
|
+
}
|
|
22406
|
+
}
|
|
21598
22407
|
case "remove_mesh_node": {
|
|
21599
22408
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21600
22409
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
21601
22410
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
21602
22411
|
try {
|
|
21603
|
-
const
|
|
21604
|
-
const
|
|
21605
|
-
|
|
22412
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22413
|
+
const mesh = meshRecord?.mesh;
|
|
22414
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22415
|
+
const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
|
|
22416
|
+
args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
|
|
22417
|
+
);
|
|
22418
|
+
let sessionCleanup;
|
|
22419
|
+
if (node && sessionCleanupMode !== "preserve") {
|
|
22420
|
+
sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
|
|
22421
|
+
if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
|
|
22422
|
+
}
|
|
22423
|
+
if (node?.isLocalWorktree && node.workspace) {
|
|
22424
|
+
try {
|
|
22425
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
22426
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
22427
|
+
if (repoRoot) {
|
|
22428
|
+
const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22429
|
+
await removeWorktree2(repoRoot, node.workspace);
|
|
22430
|
+
}
|
|
22431
|
+
} catch (e) {
|
|
22432
|
+
LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
|
|
22433
|
+
}
|
|
22434
|
+
}
|
|
22435
|
+
let removed = false;
|
|
22436
|
+
if (meshRecord?.inline) {
|
|
22437
|
+
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
22438
|
+
} else {
|
|
22439
|
+
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22440
|
+
removed = removeNode3(meshId, nodeId);
|
|
22441
|
+
}
|
|
22442
|
+
return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
|
|
22443
|
+
} catch (e) {
|
|
22444
|
+
return { success: false, error: e.message };
|
|
22445
|
+
}
|
|
22446
|
+
}
|
|
22447
|
+
case "clone_mesh_node": {
|
|
22448
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22449
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
22450
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
22451
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
22452
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22453
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
22454
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
22455
|
+
try {
|
|
22456
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22457
|
+
const mesh = meshRecord?.mesh;
|
|
22458
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22459
|
+
const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
|
|
22460
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
22461
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
22462
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22463
|
+
const result = await createWorktree2({
|
|
22464
|
+
repoRoot,
|
|
22465
|
+
branch,
|
|
22466
|
+
baseBranch,
|
|
22467
|
+
meshName: mesh.name
|
|
22468
|
+
});
|
|
22469
|
+
let node;
|
|
22470
|
+
if (meshRecord.inline) {
|
|
22471
|
+
const { randomUUID: randomUUID8 } = await import("crypto");
|
|
22472
|
+
node = {
|
|
22473
|
+
id: `node_${randomUUID8().replace(/-/g, "")}`,
|
|
22474
|
+
workspace: result.worktreePath,
|
|
22475
|
+
repoRoot: result.worktreePath,
|
|
22476
|
+
daemonId: sourceNode.daemonId,
|
|
22477
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22478
|
+
policy: { ...sourceNode.policy || {} },
|
|
22479
|
+
isLocalWorktree: true,
|
|
22480
|
+
worktreeBranch: result.branch,
|
|
22481
|
+
clonedFromNodeId: sourceNodeId
|
|
22482
|
+
};
|
|
22483
|
+
this.updateInlineMeshNode(meshId, mesh, node);
|
|
22484
|
+
} else {
|
|
22485
|
+
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22486
|
+
node = addNode3(meshId, {
|
|
22487
|
+
workspace: result.worktreePath,
|
|
22488
|
+
repoRoot: result.worktreePath,
|
|
22489
|
+
daemonId: sourceNode.daemonId,
|
|
22490
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22491
|
+
isLocalWorktree: true,
|
|
22492
|
+
worktreeBranch: result.branch,
|
|
22493
|
+
clonedFromNodeId: sourceNodeId,
|
|
22494
|
+
policy: { ...sourceNode.policy || {} }
|
|
22495
|
+
});
|
|
22496
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
22497
|
+
}
|
|
22498
|
+
return {
|
|
22499
|
+
success: true,
|
|
22500
|
+
node,
|
|
22501
|
+
worktreePath: result.worktreePath,
|
|
22502
|
+
branch: result.branch
|
|
22503
|
+
};
|
|
21606
22504
|
} catch (e) {
|
|
21607
22505
|
return { success: false, error: e.message };
|
|
21608
22506
|
}
|
|
@@ -21610,7 +22508,7 @@ var DaemonCommandRouter = class {
|
|
|
21610
22508
|
// ─── Mesh Coordinator Launch ───
|
|
21611
22509
|
case "launch_mesh_coordinator": {
|
|
21612
22510
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21613
|
-
|
|
22511
|
+
let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
|
|
21614
22512
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
21615
22513
|
try {
|
|
21616
22514
|
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
@@ -21638,9 +22536,29 @@ var DaemonCommandRouter = class {
|
|
|
21638
22536
|
}
|
|
21639
22537
|
const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
|
|
21640
22538
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
22539
|
+
if (!cliType) {
|
|
22540
|
+
const resolved = await resolveProviderTypeFromPriority({
|
|
22541
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
|
|
22542
|
+
providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
|
|
22543
|
+
providerLoader: this.deps.providerLoader,
|
|
22544
|
+
onStatusChange: this.deps.onStatusChange
|
|
22545
|
+
});
|
|
22546
|
+
if (!resolved.providerType) {
|
|
22547
|
+
return {
|
|
22548
|
+
success: false,
|
|
22549
|
+
code: "mesh_coordinator_provider_priority_unusable",
|
|
22550
|
+
error: resolved.error || "No usable provider found from node providerPriority",
|
|
22551
|
+
meshId,
|
|
22552
|
+
cliType,
|
|
22553
|
+
workspace
|
|
22554
|
+
};
|
|
22555
|
+
}
|
|
22556
|
+
cliType = resolved.providerType;
|
|
22557
|
+
}
|
|
21641
22558
|
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
21642
22559
|
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
21643
22560
|
provider: providerMeta,
|
|
22561
|
+
cliType,
|
|
21644
22562
|
meshId,
|
|
21645
22563
|
workspace
|
|
21646
22564
|
});
|
|
@@ -21665,7 +22583,8 @@ var DaemonCommandRouter = class {
|
|
|
21665
22583
|
meshCoordinatorSetup: coordinatorSetup
|
|
21666
22584
|
};
|
|
21667
22585
|
}
|
|
21668
|
-
|
|
22586
|
+
const configFormat = coordinatorSetup.configFormat;
|
|
22587
|
+
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
21669
22588
|
return {
|
|
21670
22589
|
success: false,
|
|
21671
22590
|
code: "mesh_coordinator_unsupported",
|
|
@@ -21675,44 +22594,93 @@ var DaemonCommandRouter = class {
|
|
|
21675
22594
|
workspace
|
|
21676
22595
|
};
|
|
21677
22596
|
}
|
|
21678
|
-
|
|
21679
|
-
|
|
21680
|
-
|
|
21681
|
-
|
|
21682
|
-
|
|
21683
|
-
|
|
21684
|
-
|
|
21685
|
-
|
|
21686
|
-
|
|
21687
|
-
|
|
22597
|
+
let systemPrompt = "";
|
|
22598
|
+
try {
|
|
22599
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
22600
|
+
} catch (error) {
|
|
22601
|
+
const message = error?.message || String(error);
|
|
22602
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
22603
|
+
return {
|
|
22604
|
+
success: false,
|
|
22605
|
+
code: "mesh_coordinator_prompt_failed",
|
|
22606
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
22607
|
+
meshId,
|
|
22608
|
+
cliType,
|
|
22609
|
+
workspace
|
|
22610
|
+
};
|
|
21688
22611
|
}
|
|
22612
|
+
const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
|
|
22613
|
+
const { dirname: dirname9 } = await import("path");
|
|
22614
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
22615
|
+
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
22616
|
+
const returnManualFallback = (message) => ({
|
|
22617
|
+
success: false,
|
|
22618
|
+
code: "mesh_coordinator_manual_mcp_setup_required",
|
|
22619
|
+
error: message,
|
|
22620
|
+
meshId,
|
|
22621
|
+
cliType,
|
|
22622
|
+
workspace,
|
|
22623
|
+
meshCoordinatorSetup: hermesManualFallback
|
|
22624
|
+
});
|
|
21689
22625
|
const mcpServerEntry = {
|
|
21690
22626
|
command: coordinatorSetup.mcpServer.command,
|
|
21691
22627
|
args: coordinatorSetup.mcpServer.args
|
|
21692
22628
|
};
|
|
21693
22629
|
if (args?.inlineMesh) {
|
|
21694
22630
|
mcpServerEntry.env = {
|
|
21695
|
-
ADHDEV_INLINE_MESH: JSON.stringify(mesh)
|
|
22631
|
+
ADHDEV_INLINE_MESH: JSON.stringify(mesh),
|
|
22632
|
+
ADHDEV_MCP_TRANSPORT: "ipc"
|
|
21696
22633
|
};
|
|
21697
22634
|
}
|
|
22635
|
+
try {
|
|
22636
|
+
mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
|
|
22637
|
+
} catch (error) {
|
|
22638
|
+
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
22639
|
+
LOG.error("MeshCoordinator", message);
|
|
22640
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22641
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
22642
|
+
}
|
|
22643
|
+
const hadExistingMcpConfig = existsSync23(mcpConfigPath);
|
|
22644
|
+
let existingMcpConfig = {};
|
|
22645
|
+
if (hadExistingMcpConfig) {
|
|
22646
|
+
try {
|
|
22647
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
|
|
22648
|
+
copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
|
|
22649
|
+
} catch (error) {
|
|
22650
|
+
LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
22651
|
+
return {
|
|
22652
|
+
success: false,
|
|
22653
|
+
code: "mesh_coordinator_config_parse_failed",
|
|
22654
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`
|
|
22655
|
+
};
|
|
22656
|
+
}
|
|
22657
|
+
}
|
|
22658
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
22659
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
21698
22660
|
const mcpConfig = {
|
|
21699
22661
|
...existingMcpConfig,
|
|
21700
|
-
|
|
21701
|
-
...
|
|
22662
|
+
[mcpServersKey]: {
|
|
22663
|
+
...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
|
|
21702
22664
|
[coordinatorSetup.serverName]: mcpServerEntry
|
|
21703
22665
|
}
|
|
21704
22666
|
};
|
|
21705
|
-
writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
21706
|
-
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21707
|
-
let systemPrompt = "";
|
|
21708
22667
|
try {
|
|
21709
|
-
|
|
21710
|
-
} catch {
|
|
21711
|
-
|
|
22668
|
+
writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
22669
|
+
} catch (error) {
|
|
22670
|
+
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
22671
|
+
LOG.error("MeshCoordinator", message);
|
|
22672
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22673
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21712
22674
|
}
|
|
22675
|
+
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21713
22676
|
const cliArgs = [];
|
|
22677
|
+
const launchEnv = {};
|
|
21714
22678
|
if (systemPrompt) {
|
|
21715
|
-
|
|
22679
|
+
if (configFormat === "hermes_config_yaml") {
|
|
22680
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
22681
|
+
} else {
|
|
22682
|
+
cliArgs.push("--append-system-prompt", systemPrompt);
|
|
22683
|
+
}
|
|
21716
22684
|
}
|
|
21717
22685
|
if (cliType === "claude-cli") {
|
|
21718
22686
|
cliArgs.push("--mcp-config", coordinatorSetup.configPath);
|
|
@@ -21721,6 +22689,7 @@ var DaemonCommandRouter = class {
|
|
|
21721
22689
|
cliType,
|
|
21722
22690
|
dir: workspace,
|
|
21723
22691
|
cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
|
|
22692
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
21724
22693
|
settings: {
|
|
21725
22694
|
meshCoordinatorFor: meshId
|
|
21726
22695
|
}
|
|
@@ -21900,6 +22869,12 @@ var DaemonStatusReporter = class {
|
|
|
21900
22869
|
if (providerType) {
|
|
21901
22870
|
payload.providerType = providerType;
|
|
21902
22871
|
}
|
|
22872
|
+
if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
|
|
22873
|
+
payload.providerSessionId = event.providerSessionId.trim();
|
|
22874
|
+
}
|
|
22875
|
+
if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
|
|
22876
|
+
payload.workspaceName = event.workspaceName.trim();
|
|
22877
|
+
}
|
|
21903
22878
|
if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
|
|
21904
22879
|
payload.duration = event.duration;
|
|
21905
22880
|
}
|
|
@@ -23147,7 +24122,10 @@ var ProviderInstanceManager = class {
|
|
|
23147
24122
|
this.instances.get(id).dispose();
|
|
23148
24123
|
}
|
|
23149
24124
|
this.instances.set(id, instance);
|
|
23150
|
-
await instance.init(
|
|
24125
|
+
await instance.init({
|
|
24126
|
+
...context,
|
|
24127
|
+
emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
|
|
24128
|
+
});
|
|
23151
24129
|
}
|
|
23152
24130
|
/**
|
|
23153
24131
|
* Instance remove
|
|
@@ -23309,6 +24287,17 @@ var ProviderInstanceManager = class {
|
|
|
23309
24287
|
onEvent(listener) {
|
|
23310
24288
|
this.eventListeners.push(listener);
|
|
23311
24289
|
}
|
|
24290
|
+
emitProviderEvent(providerType, instanceId, event) {
|
|
24291
|
+
const payload = {
|
|
24292
|
+
...event,
|
|
24293
|
+
providerType,
|
|
24294
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
|
|
24295
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
|
|
24296
|
+
};
|
|
24297
|
+
for (const listener of this.eventListeners) {
|
|
24298
|
+
listener(payload);
|
|
24299
|
+
}
|
|
24300
|
+
}
|
|
23312
24301
|
emitPendingEvents(providerType, state, extra = {}) {
|
|
23313
24302
|
for (const event of state.pendingEvents) {
|
|
23314
24303
|
for (const listener of this.eventListeners) {
|
|
@@ -23381,11 +24370,11 @@ var ProviderInstanceManager = class {
|
|
|
23381
24370
|
|
|
23382
24371
|
// src/providers/version-archive.ts
|
|
23383
24372
|
var fs11 = __toESM(require("fs"));
|
|
23384
|
-
var
|
|
23385
|
-
var
|
|
24373
|
+
var path22 = __toESM(require("path"));
|
|
24374
|
+
var os20 = __toESM(require("os"));
|
|
23386
24375
|
var import_child_process10 = require("child_process");
|
|
23387
24376
|
var import_os3 = require("os");
|
|
23388
|
-
var ARCHIVE_PATH =
|
|
24377
|
+
var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
|
|
23389
24378
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
23390
24379
|
var VersionArchive = class {
|
|
23391
24380
|
history = {};
|
|
@@ -23432,7 +24421,7 @@ var VersionArchive = class {
|
|
|
23432
24421
|
}
|
|
23433
24422
|
save() {
|
|
23434
24423
|
try {
|
|
23435
|
-
fs11.mkdirSync(
|
|
24424
|
+
fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
|
|
23436
24425
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
23437
24426
|
} catch {
|
|
23438
24427
|
}
|
|
@@ -23488,8 +24477,8 @@ function getVersion(binary, versionCommand) {
|
|
|
23488
24477
|
function checkPathExists2(paths) {
|
|
23489
24478
|
for (const p of paths) {
|
|
23490
24479
|
if (p.includes("*")) {
|
|
23491
|
-
const home =
|
|
23492
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
24480
|
+
const home = os20.homedir();
|
|
24481
|
+
const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
|
|
23493
24482
|
if (fs11.existsSync(resolved)) return resolved;
|
|
23494
24483
|
} else {
|
|
23495
24484
|
if (fs11.existsSync(p)) return p;
|
|
@@ -23499,7 +24488,7 @@ function checkPathExists2(paths) {
|
|
|
23499
24488
|
}
|
|
23500
24489
|
function getMacAppVersion(appPath) {
|
|
23501
24490
|
if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
23502
|
-
const plistPath =
|
|
24491
|
+
const plistPath = path22.join(appPath, "Contents", "Info.plist");
|
|
23503
24492
|
if (!fs11.existsSync(plistPath)) return null;
|
|
23504
24493
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
23505
24494
|
return raw || null;
|
|
@@ -23525,7 +24514,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23525
24514
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
23526
24515
|
let resolvedBin = cliBin;
|
|
23527
24516
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
23528
|
-
const bundled =
|
|
24517
|
+
const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
23529
24518
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
23530
24519
|
}
|
|
23531
24520
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -23566,7 +24555,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23566
24555
|
// src/daemon/dev-server.ts
|
|
23567
24556
|
var http2 = __toESM(require("http"));
|
|
23568
24557
|
var fs15 = __toESM(require("fs"));
|
|
23569
|
-
var
|
|
24558
|
+
var path26 = __toESM(require("path"));
|
|
23570
24559
|
init_config();
|
|
23571
24560
|
|
|
23572
24561
|
// src/daemon/scaffold-template.ts
|
|
@@ -23917,7 +24906,7 @@ init_logger();
|
|
|
23917
24906
|
|
|
23918
24907
|
// src/daemon/dev-cdp-handlers.ts
|
|
23919
24908
|
var fs12 = __toESM(require("fs"));
|
|
23920
|
-
var
|
|
24909
|
+
var path23 = __toESM(require("path"));
|
|
23921
24910
|
init_logger();
|
|
23922
24911
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
23923
24912
|
const body = await ctx.readBody(req);
|
|
@@ -24096,17 +25085,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
24096
25085
|
return;
|
|
24097
25086
|
}
|
|
24098
25087
|
let scriptsPath = "";
|
|
24099
|
-
const directScripts =
|
|
25088
|
+
const directScripts = path23.join(dir, "scripts.js");
|
|
24100
25089
|
if (fs12.existsSync(directScripts)) {
|
|
24101
25090
|
scriptsPath = directScripts;
|
|
24102
25091
|
} else {
|
|
24103
|
-
const scriptsDir =
|
|
25092
|
+
const scriptsDir = path23.join(dir, "scripts");
|
|
24104
25093
|
if (fs12.existsSync(scriptsDir)) {
|
|
24105
25094
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
24106
|
-
return fs12.statSync(
|
|
25095
|
+
return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
|
|
24107
25096
|
}).sort().reverse();
|
|
24108
25097
|
for (const ver of versions) {
|
|
24109
|
-
const p =
|
|
25098
|
+
const p = path23.join(scriptsDir, ver, "scripts.js");
|
|
24110
25099
|
if (fs12.existsSync(p)) {
|
|
24111
25100
|
scriptsPath = p;
|
|
24112
25101
|
break;
|
|
@@ -24935,7 +25924,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
24935
25924
|
|
|
24936
25925
|
// src/daemon/dev-cli-debug.ts
|
|
24937
25926
|
var fs13 = __toESM(require("fs"));
|
|
24938
|
-
var
|
|
25927
|
+
var path24 = __toESM(require("path"));
|
|
24939
25928
|
function slugifyFixtureName(value) {
|
|
24940
25929
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24941
25930
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -24945,11 +25934,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
24945
25934
|
if (!providerDir) {
|
|
24946
25935
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
24947
25936
|
}
|
|
24948
|
-
return
|
|
25937
|
+
return path24.join(providerDir, "fixtures");
|
|
24949
25938
|
}
|
|
24950
25939
|
function readCliFixture(ctx, type, name) {
|
|
24951
25940
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
24952
|
-
const filePath =
|
|
25941
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
24953
25942
|
if (!fs13.existsSync(filePath)) {
|
|
24954
25943
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
24955
25944
|
}
|
|
@@ -25716,7 +26705,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
25716
26705
|
},
|
|
25717
26706
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
25718
26707
|
};
|
|
25719
|
-
const filePath =
|
|
26708
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
25720
26709
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
25721
26710
|
ctx.json(res, 200, {
|
|
25722
26711
|
saved: true,
|
|
@@ -25740,7 +26729,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
25740
26729
|
return;
|
|
25741
26730
|
}
|
|
25742
26731
|
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 =
|
|
26732
|
+
const fullPath = path24.join(fixtureDir, file);
|
|
25744
26733
|
try {
|
|
25745
26734
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
25746
26735
|
return {
|
|
@@ -25876,8 +26865,8 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
25876
26865
|
|
|
25877
26866
|
// src/daemon/dev-auto-implement.ts
|
|
25878
26867
|
var fs14 = __toESM(require("fs"));
|
|
25879
|
-
var
|
|
25880
|
-
var
|
|
26868
|
+
var path25 = __toESM(require("path"));
|
|
26869
|
+
var os21 = __toESM(require("os"));
|
|
25881
26870
|
function getAutoImplPid(ctx) {
|
|
25882
26871
|
const pid = ctx.autoImplProcess?.pid;
|
|
25883
26872
|
return typeof pid === "number" && pid > 0 ? pid : null;
|
|
@@ -25926,22 +26915,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
25926
26915
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
25927
26916
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
25928
26917
|
try {
|
|
25929
|
-
return fs14.statSync(
|
|
26918
|
+
return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
25930
26919
|
} catch {
|
|
25931
26920
|
return false;
|
|
25932
26921
|
}
|
|
25933
26922
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
25934
26923
|
if (versions.length === 0) return null;
|
|
25935
|
-
return
|
|
26924
|
+
return path25.join(scriptsDir, versions[0]);
|
|
25936
26925
|
}
|
|
25937
26926
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
25938
|
-
const canonicalUserDir =
|
|
25939
|
-
const desiredDir = requestedDir ?
|
|
25940
|
-
const upstreamRoot =
|
|
25941
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
26927
|
+
const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
26928
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
26929
|
+
const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
|
|
26930
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
25942
26931
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
25943
26932
|
}
|
|
25944
|
-
if (
|
|
26933
|
+
if (path25.basename(desiredDir) !== type) {
|
|
25945
26934
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
25946
26935
|
}
|
|
25947
26936
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -25949,11 +26938,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
25949
26938
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
25950
26939
|
}
|
|
25951
26940
|
if (!fs14.existsSync(desiredDir)) {
|
|
25952
|
-
fs14.mkdirSync(
|
|
26941
|
+
fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
25953
26942
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
25954
26943
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
25955
26944
|
}
|
|
25956
|
-
const providerJson =
|
|
26945
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
25957
26946
|
if (!fs14.existsSync(providerJson)) {
|
|
25958
26947
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
25959
26948
|
}
|
|
@@ -25964,13 +26953,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
25964
26953
|
const refDir = ctx.findProviderDir(referenceType);
|
|
25965
26954
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
25966
26955
|
const referenceScripts = {};
|
|
25967
|
-
const scriptsDir =
|
|
26956
|
+
const scriptsDir = path25.join(refDir, "scripts");
|
|
25968
26957
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
25969
26958
|
if (!latestDir) return referenceScripts;
|
|
25970
26959
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
25971
26960
|
if (!file.endsWith(".js")) continue;
|
|
25972
26961
|
try {
|
|
25973
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
26962
|
+
referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
|
|
25974
26963
|
} catch {
|
|
25975
26964
|
}
|
|
25976
26965
|
}
|
|
@@ -26078,9 +27067,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26078
27067
|
});
|
|
26079
27068
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
26080
27069
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
26081
|
-
const tmpDir =
|
|
27070
|
+
const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
|
|
26082
27071
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
26083
|
-
const promptFile =
|
|
27072
|
+
const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
26084
27073
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
26085
27074
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
26086
27075
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -26233,7 +27222,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26233
27222
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
26234
27223
|
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
26235
27224
|
let shellCmd;
|
|
26236
|
-
const isWin =
|
|
27225
|
+
const isWin = os21.platform() === "win32";
|
|
26237
27226
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
26238
27227
|
const promptMode = autoImpl?.promptMode ?? "stdin";
|
|
26239
27228
|
const extraArgs = autoImpl?.extraArgs ?? [];
|
|
@@ -26272,7 +27261,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26272
27261
|
try {
|
|
26273
27262
|
const pty = require("node-pty");
|
|
26274
27263
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
26275
|
-
const isWin2 =
|
|
27264
|
+
const isWin2 = os21.platform() === "win32";
|
|
26276
27265
|
child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
26277
27266
|
name: "xterm-256color",
|
|
26278
27267
|
cols: 120,
|
|
@@ -26512,7 +27501,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26512
27501
|
setMode: "set_mode.js"
|
|
26513
27502
|
};
|
|
26514
27503
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26515
|
-
const scriptsDir =
|
|
27504
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26516
27505
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26517
27506
|
if (latestScriptsDir) {
|
|
26518
27507
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26523,7 +27512,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26523
27512
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
26524
27513
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26525
27514
|
try {
|
|
26526
|
-
const content = fs14.readFileSync(
|
|
27515
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26527
27516
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26528
27517
|
lines.push("```javascript");
|
|
26529
27518
|
lines.push(content);
|
|
@@ -26540,7 +27529,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26540
27529
|
lines.push("");
|
|
26541
27530
|
for (const file of refFiles) {
|
|
26542
27531
|
try {
|
|
26543
|
-
const content = fs14.readFileSync(
|
|
27532
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26544
27533
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26545
27534
|
lines.push("```javascript");
|
|
26546
27535
|
lines.push(content);
|
|
@@ -26581,10 +27570,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26581
27570
|
lines.push("");
|
|
26582
27571
|
}
|
|
26583
27572
|
}
|
|
26584
|
-
const docsDir =
|
|
27573
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26585
27574
|
const loadGuide = (name) => {
|
|
26586
27575
|
try {
|
|
26587
|
-
const p =
|
|
27576
|
+
const p = path25.join(docsDir, name);
|
|
26588
27577
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26589
27578
|
} catch {
|
|
26590
27579
|
}
|
|
@@ -26821,7 +27810,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26821
27810
|
parseApproval: "parse_approval.js"
|
|
26822
27811
|
};
|
|
26823
27812
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26824
|
-
const scriptsDir =
|
|
27813
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26825
27814
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26826
27815
|
if (latestScriptsDir) {
|
|
26827
27816
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26833,7 +27822,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26833
27822
|
if (!file.endsWith(".js")) continue;
|
|
26834
27823
|
if (!targetFileNames.has(file)) continue;
|
|
26835
27824
|
try {
|
|
26836
|
-
const content = fs14.readFileSync(
|
|
27825
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26837
27826
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26838
27827
|
lines.push("```javascript");
|
|
26839
27828
|
lines.push(content);
|
|
@@ -26849,7 +27838,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26849
27838
|
lines.push("");
|
|
26850
27839
|
for (const file of refFiles) {
|
|
26851
27840
|
try {
|
|
26852
|
-
const content = fs14.readFileSync(
|
|
27841
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26853
27842
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26854
27843
|
lines.push("```javascript");
|
|
26855
27844
|
lines.push(content);
|
|
@@ -26882,10 +27871,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26882
27871
|
lines.push("");
|
|
26883
27872
|
}
|
|
26884
27873
|
}
|
|
26885
|
-
const docsDir =
|
|
27874
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26886
27875
|
const loadGuide = (name) => {
|
|
26887
27876
|
try {
|
|
26888
|
-
const p =
|
|
27877
|
+
const p = path25.join(docsDir, name);
|
|
26889
27878
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26890
27879
|
} catch {
|
|
26891
27880
|
}
|
|
@@ -27332,8 +28321,8 @@ var DevServer = class _DevServer {
|
|
|
27332
28321
|
}
|
|
27333
28322
|
getEndpointList() {
|
|
27334
28323
|
return this.routes.map((r) => {
|
|
27335
|
-
const
|
|
27336
|
-
return `${r.method.padEnd(5)} ${
|
|
28324
|
+
const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
28325
|
+
return `${r.method.padEnd(5)} ${path27}`;
|
|
27337
28326
|
});
|
|
27338
28327
|
}
|
|
27339
28328
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -27621,12 +28610,12 @@ var DevServer = class _DevServer {
|
|
|
27621
28610
|
// ─── DevConsole SPA ───
|
|
27622
28611
|
getConsoleDistDir() {
|
|
27623
28612
|
const candidates = [
|
|
27624
|
-
|
|
27625
|
-
|
|
27626
|
-
|
|
28613
|
+
path26.resolve(__dirname, "../../web-devconsole/dist"),
|
|
28614
|
+
path26.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
28615
|
+
path26.join(process.cwd(), "packages/web-devconsole/dist")
|
|
27627
28616
|
];
|
|
27628
28617
|
for (const dir of candidates) {
|
|
27629
|
-
if (fs15.existsSync(
|
|
28618
|
+
if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
|
|
27630
28619
|
}
|
|
27631
28620
|
return null;
|
|
27632
28621
|
}
|
|
@@ -27636,7 +28625,7 @@ var DevServer = class _DevServer {
|
|
|
27636
28625
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
27637
28626
|
return;
|
|
27638
28627
|
}
|
|
27639
|
-
const htmlPath =
|
|
28628
|
+
const htmlPath = path26.join(distDir, "index.html");
|
|
27640
28629
|
try {
|
|
27641
28630
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
27642
28631
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -27661,15 +28650,15 @@ var DevServer = class _DevServer {
|
|
|
27661
28650
|
this.json(res, 404, { error: "Not found" });
|
|
27662
28651
|
return;
|
|
27663
28652
|
}
|
|
27664
|
-
const safePath =
|
|
27665
|
-
const filePath =
|
|
28653
|
+
const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
|
|
28654
|
+
const filePath = path26.join(distDir, safePath);
|
|
27666
28655
|
if (!filePath.startsWith(distDir)) {
|
|
27667
28656
|
this.json(res, 403, { error: "Forbidden" });
|
|
27668
28657
|
return;
|
|
27669
28658
|
}
|
|
27670
28659
|
try {
|
|
27671
28660
|
const content = fs15.readFileSync(filePath);
|
|
27672
|
-
const ext =
|
|
28661
|
+
const ext = path26.extname(filePath);
|
|
27673
28662
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
27674
28663
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
27675
28664
|
res.end(content);
|
|
@@ -27782,9 +28771,9 @@ var DevServer = class _DevServer {
|
|
|
27782
28771
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27783
28772
|
if (entry.isDirectory()) {
|
|
27784
28773
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
27785
|
-
scan(
|
|
28774
|
+
scan(path26.join(d, entry.name), rel);
|
|
27786
28775
|
} else {
|
|
27787
|
-
const stat2 = fs15.statSync(
|
|
28776
|
+
const stat2 = fs15.statSync(path26.join(d, entry.name));
|
|
27788
28777
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
27789
28778
|
}
|
|
27790
28779
|
}
|
|
@@ -27807,7 +28796,7 @@ var DevServer = class _DevServer {
|
|
|
27807
28796
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27808
28797
|
return;
|
|
27809
28798
|
}
|
|
27810
|
-
const fullPath =
|
|
28799
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27811
28800
|
if (!fullPath.startsWith(dir)) {
|
|
27812
28801
|
this.json(res, 403, { error: "Forbidden" });
|
|
27813
28802
|
return;
|
|
@@ -27832,14 +28821,14 @@ var DevServer = class _DevServer {
|
|
|
27832
28821
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27833
28822
|
return;
|
|
27834
28823
|
}
|
|
27835
|
-
const fullPath =
|
|
28824
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27836
28825
|
if (!fullPath.startsWith(dir)) {
|
|
27837
28826
|
this.json(res, 403, { error: "Forbidden" });
|
|
27838
28827
|
return;
|
|
27839
28828
|
}
|
|
27840
28829
|
try {
|
|
27841
28830
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
27842
|
-
fs15.mkdirSync(
|
|
28831
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27843
28832
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27844
28833
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
27845
28834
|
this.providerLoader.reload();
|
|
@@ -27856,7 +28845,7 @@ var DevServer = class _DevServer {
|
|
|
27856
28845
|
return;
|
|
27857
28846
|
}
|
|
27858
28847
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
27859
|
-
const p =
|
|
28848
|
+
const p = path26.join(dir, name);
|
|
27860
28849
|
if (fs15.existsSync(p)) {
|
|
27861
28850
|
const source = fs15.readFileSync(p, "utf-8");
|
|
27862
28851
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -27877,8 +28866,8 @@ var DevServer = class _DevServer {
|
|
|
27877
28866
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
27878
28867
|
return;
|
|
27879
28868
|
}
|
|
27880
|
-
const target = fs15.existsSync(
|
|
27881
|
-
const targetPath =
|
|
28869
|
+
const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
28870
|
+
const targetPath = path26.join(dir, target);
|
|
27882
28871
|
try {
|
|
27883
28872
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
27884
28873
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -28025,7 +29014,7 @@ var DevServer = class _DevServer {
|
|
|
28025
29014
|
}
|
|
28026
29015
|
let targetDir;
|
|
28027
29016
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
28028
|
-
const jsonPath =
|
|
29017
|
+
const jsonPath = path26.join(targetDir, "provider.json");
|
|
28029
29018
|
if (fs15.existsSync(jsonPath)) {
|
|
28030
29019
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
28031
29020
|
return;
|
|
@@ -28037,8 +29026,8 @@ var DevServer = class _DevServer {
|
|
|
28037
29026
|
const createdFiles = ["provider.json"];
|
|
28038
29027
|
if (result.files) {
|
|
28039
29028
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
28040
|
-
const fullPath =
|
|
28041
|
-
fs15.mkdirSync(
|
|
29029
|
+
const fullPath = path26.join(targetDir, relPath);
|
|
29030
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
28042
29031
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
28043
29032
|
createdFiles.push(relPath);
|
|
28044
29033
|
}
|
|
@@ -28091,22 +29080,22 @@ var DevServer = class _DevServer {
|
|
|
28091
29080
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
28092
29081
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
28093
29082
|
try {
|
|
28094
|
-
return fs15.statSync(
|
|
29083
|
+
return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
|
|
28095
29084
|
} catch {
|
|
28096
29085
|
return false;
|
|
28097
29086
|
}
|
|
28098
29087
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
28099
29088
|
if (versions.length === 0) return null;
|
|
28100
|
-
return
|
|
29089
|
+
return path26.join(scriptsDir, versions[0]);
|
|
28101
29090
|
}
|
|
28102
29091
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
28103
|
-
const canonicalUserDir =
|
|
28104
|
-
const desiredDir = requestedDir ?
|
|
28105
|
-
const upstreamRoot =
|
|
28106
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
29092
|
+
const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
29093
|
+
const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
|
|
29094
|
+
const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
|
|
29095
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
|
|
28107
29096
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
28108
29097
|
}
|
|
28109
|
-
if (
|
|
29098
|
+
if (path26.basename(desiredDir) !== type) {
|
|
28110
29099
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
28111
29100
|
}
|
|
28112
29101
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -28114,11 +29103,11 @@ var DevServer = class _DevServer {
|
|
|
28114
29103
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
28115
29104
|
}
|
|
28116
29105
|
if (!fs15.existsSync(desiredDir)) {
|
|
28117
|
-
fs15.mkdirSync(
|
|
29106
|
+
fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
|
|
28118
29107
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
28119
29108
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
28120
29109
|
}
|
|
28121
|
-
const providerJson =
|
|
29110
|
+
const providerJson = path26.join(desiredDir, "provider.json");
|
|
28122
29111
|
if (!fs15.existsSync(providerJson)) {
|
|
28123
29112
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
28124
29113
|
}
|
|
@@ -28154,7 +29143,7 @@ var DevServer = class _DevServer {
|
|
|
28154
29143
|
setMode: "set_mode.js"
|
|
28155
29144
|
};
|
|
28156
29145
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28157
|
-
const scriptsDir =
|
|
29146
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28158
29147
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28159
29148
|
if (latestScriptsDir) {
|
|
28160
29149
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28165,7 +29154,7 @@ var DevServer = class _DevServer {
|
|
|
28165
29154
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
28166
29155
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
28167
29156
|
try {
|
|
28168
|
-
const content = fs15.readFileSync(
|
|
29157
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28169
29158
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28170
29159
|
lines.push("```javascript");
|
|
28171
29160
|
lines.push(content);
|
|
@@ -28182,7 +29171,7 @@ var DevServer = class _DevServer {
|
|
|
28182
29171
|
lines.push("");
|
|
28183
29172
|
for (const file of refFiles) {
|
|
28184
29173
|
try {
|
|
28185
|
-
const content = fs15.readFileSync(
|
|
29174
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28186
29175
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28187
29176
|
lines.push("```javascript");
|
|
28188
29177
|
lines.push(content);
|
|
@@ -28223,10 +29212,10 @@ var DevServer = class _DevServer {
|
|
|
28223
29212
|
lines.push("");
|
|
28224
29213
|
}
|
|
28225
29214
|
}
|
|
28226
|
-
const docsDir =
|
|
29215
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28227
29216
|
const loadGuide = (name) => {
|
|
28228
29217
|
try {
|
|
28229
|
-
const p =
|
|
29218
|
+
const p = path26.join(docsDir, name);
|
|
28230
29219
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28231
29220
|
} catch {
|
|
28232
29221
|
}
|
|
@@ -28400,7 +29389,7 @@ var DevServer = class _DevServer {
|
|
|
28400
29389
|
parseApproval: "parse_approval.js"
|
|
28401
29390
|
};
|
|
28402
29391
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28403
|
-
const scriptsDir =
|
|
29392
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28404
29393
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28405
29394
|
if (latestScriptsDir) {
|
|
28406
29395
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28412,7 +29401,7 @@ var DevServer = class _DevServer {
|
|
|
28412
29401
|
if (!file.endsWith(".js")) continue;
|
|
28413
29402
|
if (!targetFileNames.has(file)) continue;
|
|
28414
29403
|
try {
|
|
28415
|
-
const content = fs15.readFileSync(
|
|
29404
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28416
29405
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28417
29406
|
lines.push("```javascript");
|
|
28418
29407
|
lines.push(content);
|
|
@@ -28428,7 +29417,7 @@ var DevServer = class _DevServer {
|
|
|
28428
29417
|
lines.push("");
|
|
28429
29418
|
for (const file of refFiles) {
|
|
28430
29419
|
try {
|
|
28431
|
-
const content = fs15.readFileSync(
|
|
29420
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28432
29421
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28433
29422
|
lines.push("```javascript");
|
|
28434
29423
|
lines.push(content);
|
|
@@ -28461,10 +29450,10 @@ var DevServer = class _DevServer {
|
|
|
28461
29450
|
lines.push("");
|
|
28462
29451
|
}
|
|
28463
29452
|
}
|
|
28464
|
-
const docsDir =
|
|
29453
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28465
29454
|
const loadGuide = (name) => {
|
|
28466
29455
|
try {
|
|
28467
|
-
const p =
|
|
29456
|
+
const p = path26.join(docsDir, name);
|
|
28468
29457
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28469
29458
|
} catch {
|
|
28470
29459
|
}
|
|
@@ -29464,48 +30453,6 @@ var SessionRegistry = class {
|
|
|
29464
30453
|
// src/boot/daemon-lifecycle.ts
|
|
29465
30454
|
init_logger();
|
|
29466
30455
|
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
30456
|
async function initDaemonComponents(config) {
|
|
29510
30457
|
installGlobalInterceptor();
|
|
29511
30458
|
const appConfig = loadConfig();
|
|
@@ -29812,6 +30759,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29812
30759
|
createGitWorkspaceMonitor,
|
|
29813
30760
|
createInteractionId,
|
|
29814
30761
|
createMesh,
|
|
30762
|
+
createWorktree,
|
|
29815
30763
|
deleteMesh,
|
|
29816
30764
|
detectAllVersions,
|
|
29817
30765
|
detectCLIs,
|
|
@@ -29864,6 +30812,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29864
30812
|
launchWithCdp,
|
|
29865
30813
|
listHostedCliRuntimes,
|
|
29866
30814
|
listMeshes,
|
|
30815
|
+
listWorktrees,
|
|
29867
30816
|
loadConfig,
|
|
29868
30817
|
loadState,
|
|
29869
30818
|
logCommand,
|
|
@@ -29883,6 +30832,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29883
30832
|
normalizeSessionModalFields,
|
|
29884
30833
|
parsePorcelainV2Status,
|
|
29885
30834
|
parseProviderSourceConfigUpdate,
|
|
30835
|
+
parseWorktreeListOutput,
|
|
29886
30836
|
partitionSessionHostDiagnosticsSessions,
|
|
29887
30837
|
partitionSessionHostRecords,
|
|
29888
30838
|
prepareSessionChatTailUpdate,
|
|
@@ -29892,6 +30842,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29892
30842
|
recordDebugTrace,
|
|
29893
30843
|
registerExtensionProviders,
|
|
29894
30844
|
removeNode,
|
|
30845
|
+
removeWorktree,
|
|
29895
30846
|
resetConfig,
|
|
29896
30847
|
resetDebugRuntimeConfig,
|
|
29897
30848
|
resetState,
|
|
@@ -29901,6 +30852,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29901
30852
|
resolveGitRepository,
|
|
29902
30853
|
resolveSessionHostAppName,
|
|
29903
30854
|
resolveSessionHostAppNameResolution,
|
|
30855
|
+
resolveWorktreePath,
|
|
29904
30856
|
runAsyncBatch,
|
|
29905
30857
|
runGit,
|
|
29906
30858
|
saveConfig,
|