@adhdev/daemon-core 0.9.76-rc.3 → 0.9.76-rc.31
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 +4 -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 +1058 -384
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1085 -416
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +1 -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 +6 -0
- package/dist/shared-types.d.ts +22 -1
- package/package.json +3 -4
- package/src/cli-adapters/provider-cli-adapter.ts +6 -3
- package/src/cli-adapters/provider-cli-runtime.ts +3 -2
- package/src/commands/chat-commands.ts +50 -5
- package/src/commands/cli-manager.ts +78 -5
- package/src/commands/handler.ts +13 -4
- package/src/commands/mesh-coordinator.ts +149 -6
- package/src/commands/router.ts +319 -32
- package/src/config/mesh-config.ts +6 -0
- 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 +40 -17
- 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 +6 -0
- package/src/shared-types.ts +24 -1
- package/src/status/builders.ts +17 -12
- package/src/status/reporter.ts +6 -0
package/dist/index.mjs
CHANGED
|
@@ -41,6 +41,134 @@ var init_repo_mesh_types = __esm({
|
|
|
41
41
|
}
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
+
// src/git/git-worktree.ts
|
|
45
|
+
var git_worktree_exports = {};
|
|
46
|
+
__export(git_worktree_exports, {
|
|
47
|
+
createWorktree: () => createWorktree,
|
|
48
|
+
listWorktrees: () => listWorktrees,
|
|
49
|
+
parseWorktreeListOutput: () => parseWorktreeListOutput,
|
|
50
|
+
removeWorktree: () => removeWorktree,
|
|
51
|
+
resolveWorktreePath: () => resolveWorktreePath
|
|
52
|
+
});
|
|
53
|
+
import * as path4 from "path";
|
|
54
|
+
import { mkdir } from "fs/promises";
|
|
55
|
+
import { existsSync } from "fs";
|
|
56
|
+
import { execFile as execFile2 } from "child_process";
|
|
57
|
+
import { promisify as promisify2 } from "util";
|
|
58
|
+
function resolveWorktreePath(repoRoot, meshName, branch) {
|
|
59
|
+
const safeBranch = branch.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
|
|
60
|
+
const safeMeshName = meshName.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
|
|
61
|
+
const parentDir = path4.dirname(repoRoot);
|
|
62
|
+
return path4.join(parentDir, WORKTREE_DIR_NAME, safeMeshName, safeBranch);
|
|
63
|
+
}
|
|
64
|
+
async function createWorktree(opts) {
|
|
65
|
+
const { repoRoot, branch, baseBranch, meshName } = opts;
|
|
66
|
+
const targetDir = opts.targetDir || resolveWorktreePath(repoRoot, meshName, branch);
|
|
67
|
+
if (existsSync(targetDir)) {
|
|
68
|
+
throw new Error(`Worktree target directory already exists: ${targetDir}`);
|
|
69
|
+
}
|
|
70
|
+
await mkdir(path4.dirname(targetDir), { recursive: true });
|
|
71
|
+
const args = ["worktree", "add", targetDir, "-b", branch];
|
|
72
|
+
if (baseBranch) {
|
|
73
|
+
args.push(baseBranch);
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
await execFileAsync2("git", args, {
|
|
77
|
+
cwd: repoRoot,
|
|
78
|
+
encoding: "utf8",
|
|
79
|
+
timeout: GIT_TIMEOUT_MS,
|
|
80
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
81
|
+
windowsHide: true
|
|
82
|
+
});
|
|
83
|
+
} catch (error) {
|
|
84
|
+
const stderr = typeof error.stderr === "string" ? error.stderr : "";
|
|
85
|
+
if (/already exists/i.test(stderr)) {
|
|
86
|
+
throw new Error(`Branch '${branch}' already exists or is checked out in another worktree`);
|
|
87
|
+
}
|
|
88
|
+
throw new Error(`git worktree add failed: ${stderr.trim() || error.message}`);
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
success: true,
|
|
92
|
+
worktreePath: targetDir,
|
|
93
|
+
branch
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function removeWorktree(repoRoot, worktreePath) {
|
|
97
|
+
if (!existsSync(worktreePath)) {
|
|
98
|
+
await pruneWorktrees(repoRoot);
|
|
99
|
+
return { success: true, removedPath: worktreePath };
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
await execFileAsync2("git", ["worktree", "remove", worktreePath, "--force"], {
|
|
103
|
+
cwd: repoRoot,
|
|
104
|
+
encoding: "utf8",
|
|
105
|
+
timeout: GIT_TIMEOUT_MS,
|
|
106
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
107
|
+
windowsHide: true
|
|
108
|
+
});
|
|
109
|
+
} catch (error) {
|
|
110
|
+
const stderr = typeof error.stderr === "string" ? error.stderr : "";
|
|
111
|
+
throw new Error(`git worktree remove failed: ${stderr.trim() || error.message}`);
|
|
112
|
+
}
|
|
113
|
+
return { success: true, removedPath: worktreePath };
|
|
114
|
+
}
|
|
115
|
+
async function listWorktrees(repoRoot) {
|
|
116
|
+
const { stdout } = await execFileAsync2("git", ["worktree", "list", "--porcelain"], {
|
|
117
|
+
cwd: repoRoot,
|
|
118
|
+
encoding: "utf8",
|
|
119
|
+
timeout: GIT_TIMEOUT_MS,
|
|
120
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
121
|
+
windowsHide: true
|
|
122
|
+
});
|
|
123
|
+
return parseWorktreeListOutput(stdout);
|
|
124
|
+
}
|
|
125
|
+
function parseWorktreeListOutput(output) {
|
|
126
|
+
const entries = [];
|
|
127
|
+
const blocks = output.trim().split(/\n\n+/);
|
|
128
|
+
for (const block of blocks) {
|
|
129
|
+
if (!block.trim()) continue;
|
|
130
|
+
const lines = block.trim().split("\n");
|
|
131
|
+
const entry = { path: "", head: "", branch: null, bare: false };
|
|
132
|
+
for (const line of lines) {
|
|
133
|
+
if (line.startsWith("worktree ")) {
|
|
134
|
+
entry.path = line.slice("worktree ".length).trim();
|
|
135
|
+
} else if (line.startsWith("HEAD ")) {
|
|
136
|
+
entry.head = line.slice("HEAD ".length).trim();
|
|
137
|
+
} else if (line.startsWith("branch ")) {
|
|
138
|
+
const ref = line.slice("branch ".length).trim();
|
|
139
|
+
entry.branch = ref.replace(/^refs\/heads\//, "");
|
|
140
|
+
} else if (line === "bare") {
|
|
141
|
+
entry.bare = true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (entry.path) {
|
|
145
|
+
entries.push(entry);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return entries;
|
|
149
|
+
}
|
|
150
|
+
async function pruneWorktrees(repoRoot) {
|
|
151
|
+
try {
|
|
152
|
+
await execFileAsync2("git", ["worktree", "prune"], {
|
|
153
|
+
cwd: repoRoot,
|
|
154
|
+
encoding: "utf8",
|
|
155
|
+
timeout: GIT_TIMEOUT_MS,
|
|
156
|
+
windowsHide: true
|
|
157
|
+
});
|
|
158
|
+
} catch {
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
var execFileAsync2, WORKTREE_DIR_NAME, GIT_TIMEOUT_MS, GIT_MAX_BUFFER;
|
|
162
|
+
var init_git_worktree = __esm({
|
|
163
|
+
"src/git/git-worktree.ts"() {
|
|
164
|
+
"use strict";
|
|
165
|
+
execFileAsync2 = promisify2(execFile2);
|
|
166
|
+
WORKTREE_DIR_NAME = ".adhdev-worktrees";
|
|
167
|
+
GIT_TIMEOUT_MS = 3e4;
|
|
168
|
+
GIT_MAX_BUFFER = 4 * 1024 * 1024;
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
44
172
|
// src/config/config.ts
|
|
45
173
|
var config_exports = {};
|
|
46
174
|
__export(config_exports, {
|
|
@@ -56,8 +184,8 @@ __export(config_exports, {
|
|
|
56
184
|
updateConfig: () => updateConfig
|
|
57
185
|
});
|
|
58
186
|
import { homedir } from "os";
|
|
59
|
-
import { join } from "path";
|
|
60
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
|
|
187
|
+
import { join as join2 } from "path";
|
|
188
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
|
|
61
189
|
import { randomUUID } from "crypto";
|
|
62
190
|
function resolveProviderSourceMode(providerSourceMode, legacyDisableUpstream) {
|
|
63
191
|
if (providerSourceMode === "normal" || providerSourceMode === "no-upstream") {
|
|
@@ -151,18 +279,18 @@ function ensureMachineId(config) {
|
|
|
151
279
|
};
|
|
152
280
|
}
|
|
153
281
|
function getConfigDir() {
|
|
154
|
-
const dir =
|
|
155
|
-
if (!
|
|
282
|
+
const dir = join2(homedir(), ".adhdev");
|
|
283
|
+
if (!existsSync2(dir)) {
|
|
156
284
|
mkdirSync(dir, { recursive: true });
|
|
157
285
|
}
|
|
158
286
|
return dir;
|
|
159
287
|
}
|
|
160
288
|
function getConfigPath() {
|
|
161
|
-
return
|
|
289
|
+
return join2(getConfigDir(), "config.json");
|
|
162
290
|
}
|
|
163
291
|
function migrateStateToStateFile(raw) {
|
|
164
|
-
const statePath =
|
|
165
|
-
if (
|
|
292
|
+
const statePath = join2(getConfigDir(), "state.json");
|
|
293
|
+
if (existsSync2(statePath)) return;
|
|
166
294
|
const recentActivity = Array.isArray(raw.recentActivity) ? raw.recentActivity : [];
|
|
167
295
|
const savedProviderSessions = Array.isArray(raw.savedProviderSessions) ? raw.savedProviderSessions : [];
|
|
168
296
|
const legacySessionReads = isPlainObject(raw.recentSessionReads) ? raw.recentSessionReads : {};
|
|
@@ -186,7 +314,7 @@ function migrateStateToStateFile(raw) {
|
|
|
186
314
|
}
|
|
187
315
|
function loadConfig() {
|
|
188
316
|
const configPath = getConfigPath();
|
|
189
|
-
if (!
|
|
317
|
+
if (!existsSync2(configPath)) {
|
|
190
318
|
const initialized = ensureMachineId({ ...DEFAULT_CONFIG });
|
|
191
319
|
try {
|
|
192
320
|
saveConfig(initialized.config);
|
|
@@ -217,7 +345,7 @@ function saveConfig(config) {
|
|
|
217
345
|
const configPath = getConfigPath();
|
|
218
346
|
const dir = getConfigDir();
|
|
219
347
|
const normalized = normalizeConfig(config);
|
|
220
|
-
if (!
|
|
348
|
+
if (!existsSync2(dir)) {
|
|
221
349
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
222
350
|
}
|
|
223
351
|
writeFileSync(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
@@ -295,17 +423,17 @@ __export(mesh_config_exports, {
|
|
|
295
423
|
updateMesh: () => updateMesh,
|
|
296
424
|
updateNode: () => updateNode
|
|
297
425
|
});
|
|
298
|
-
import { existsSync as
|
|
299
|
-
import { join as
|
|
426
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
427
|
+
import { join as join4 } from "path";
|
|
300
428
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
301
429
|
function getMeshConfigPath() {
|
|
302
|
-
return
|
|
430
|
+
return join4(getConfigDir(), "meshes.json");
|
|
303
431
|
}
|
|
304
432
|
function loadMeshConfig() {
|
|
305
|
-
const
|
|
306
|
-
if (!
|
|
433
|
+
const path27 = getMeshConfigPath();
|
|
434
|
+
if (!existsSync4(path27)) return { meshes: [] };
|
|
307
435
|
try {
|
|
308
|
-
const raw = JSON.parse(readFileSync2(
|
|
436
|
+
const raw = JSON.parse(readFileSync2(path27, "utf-8"));
|
|
309
437
|
if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
|
|
310
438
|
return raw;
|
|
311
439
|
} catch {
|
|
@@ -313,16 +441,16 @@ function loadMeshConfig() {
|
|
|
313
441
|
}
|
|
314
442
|
}
|
|
315
443
|
function saveMeshConfig(config) {
|
|
316
|
-
const
|
|
317
|
-
writeFileSync2(
|
|
444
|
+
const path27 = getMeshConfigPath();
|
|
445
|
+
writeFileSync2(path27, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
|
|
318
446
|
}
|
|
319
447
|
function normalizeRepoIdentity(remoteUrl) {
|
|
320
448
|
let identity = remoteUrl.trim();
|
|
321
449
|
if (identity.startsWith("http://") || identity.startsWith("https://")) {
|
|
322
450
|
try {
|
|
323
451
|
const url = new URL(identity);
|
|
324
|
-
const
|
|
325
|
-
return `${url.hostname}/${
|
|
452
|
+
const path27 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
|
|
453
|
+
return `${url.hostname}/${path27}`;
|
|
326
454
|
} catch {
|
|
327
455
|
}
|
|
328
456
|
}
|
|
@@ -397,9 +525,12 @@ function addNode(meshId, opts) {
|
|
|
397
525
|
id: `node_${randomUUID3().replace(/-/g, "")}`,
|
|
398
526
|
workspace: opts.workspace.trim(),
|
|
399
527
|
repoRoot: opts.repoRoot,
|
|
528
|
+
daemonId: opts.daemonId,
|
|
400
529
|
userOverrides: opts.userOverrides || {},
|
|
401
530
|
policy: opts.policy || {},
|
|
402
|
-
isLocalWorktree: opts.isLocalWorktree
|
|
531
|
+
isLocalWorktree: opts.isLocalWorktree,
|
|
532
|
+
worktreeBranch: opts.worktreeBranch,
|
|
533
|
+
clonedFromNodeId: opts.clonedFromNodeId
|
|
403
534
|
};
|
|
404
535
|
mesh.nodes.push(node);
|
|
405
536
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -443,7 +574,7 @@ __export(coordinator_prompt_exports, {
|
|
|
443
574
|
buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
|
|
444
575
|
});
|
|
445
576
|
function buildCoordinatorSystemPrompt(ctx) {
|
|
446
|
-
const { mesh, status, userInstruction } = ctx;
|
|
577
|
+
const { mesh, status, userInstruction, coordinatorCliType } = ctx;
|
|
447
578
|
const sections = [];
|
|
448
579
|
sections.push(`You are a **Repo Mesh Coordinator** \u2014 a technical team lead who orchestrates work across multiple agent sessions on a shared Git repository.
|
|
449
580
|
|
|
@@ -457,15 +588,15 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
457
588
|
} else {
|
|
458
589
|
sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
|
|
459
590
|
}
|
|
460
|
-
sections.push(buildPolicySection(mesh.policy));
|
|
591
|
+
sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
|
|
461
592
|
sections.push(TOOLS_SECTION);
|
|
462
593
|
sections.push(WORKFLOW_SECTION);
|
|
463
|
-
sections.push(
|
|
594
|
+
sections.push(buildRulesSection(coordinatorCliType));
|
|
464
595
|
if (userInstruction) {
|
|
465
596
|
sections.push(`## Additional Context
|
|
466
597
|
${userInstruction}`);
|
|
467
598
|
}
|
|
468
|
-
if (mesh.coordinator
|
|
599
|
+
if (mesh.coordinator?.systemPromptSuffix) {
|
|
469
600
|
sections.push(mesh.coordinator.systemPromptSuffix);
|
|
470
601
|
}
|
|
471
602
|
return sections.join("\n\n");
|
|
@@ -510,10 +641,29 @@ function buildPolicySection(policy) {
|
|
|
510
641
|
return `## Policy
|
|
511
642
|
${rules.join("\n")}`;
|
|
512
643
|
}
|
|
513
|
-
|
|
644
|
+
function buildRulesSection(coordinatorCliType) {
|
|
645
|
+
const coordinatorNote = coordinatorCliType ? `
|
|
646
|
+
- **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.` : "";
|
|
647
|
+
return `## Rules
|
|
648
|
+
|
|
649
|
+
- **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.
|
|
650
|
+
- **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.
|
|
651
|
+
- **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.
|
|
652
|
+
- **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.
|
|
653
|
+
- **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
|
|
654
|
+
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
|
|
655
|
+
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
656
|
+
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
657
|
+
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
658
|
+
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.
|
|
659
|
+
- **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
|
|
660
|
+
- **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
|
|
661
|
+
}
|
|
662
|
+
var TOOLS_SECTION, WORKFLOW_SECTION;
|
|
514
663
|
var init_coordinator_prompt = __esm({
|
|
515
664
|
"src/mesh/coordinator-prompt.ts"() {
|
|
516
665
|
"use strict";
|
|
666
|
+
init_repo_mesh_types();
|
|
517
667
|
TOOLS_SECTION = `## Available Tools
|
|
518
668
|
|
|
519
669
|
| Tool | Purpose |
|
|
@@ -525,36 +675,29 @@ var init_coordinator_prompt = __esm({
|
|
|
525
675
|
| \`mesh_read_chat\` | Read an agent's recent messages to check progress |
|
|
526
676
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
527
677
|
| \`mesh_checkpoint\` | Create a git checkpoint on a node |
|
|
528
|
-
| \`mesh_approve\` | Approve/reject a pending agent action
|
|
678
|
+
| \`mesh_approve\` | Approve/reject a pending agent action |
|
|
679
|
+
| \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
|
|
680
|
+
| \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |`;
|
|
529
681
|
WORKFLOW_SECTION = `## Orchestration Workflow
|
|
530
682
|
|
|
531
683
|
1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
|
|
532
684
|
2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
|
|
533
685
|
3. **Delegate** \u2014 For each task:
|
|
534
686
|
a. Pick the best node (consider: health, dirty state, current workload).
|
|
535
|
-
b. If
|
|
536
|
-
c.
|
|
687
|
+
b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
|
|
688
|
+
c. If no session exists, call \`mesh_launch_session\` to start one.
|
|
689
|
+
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.
|
|
537
690
|
4. **Monitor** \u2014 Periodically call \`mesh_read_chat\` to check progress. Handle approvals via \`mesh_approve\`.
|
|
538
691
|
5. **Verify** \u2014 When a task reports completion, call \`mesh_git_status\` to verify changes were made.
|
|
539
692
|
6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
|
|
540
|
-
7. **
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
- **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
|
|
544
|
-
- **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
|
|
545
|
-
- **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
|
|
546
|
-
- **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
|
|
547
|
-
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
|
|
548
|
-
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
549
|
-
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
550
|
-
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
551
|
-
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
|
|
693
|
+
7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
|
|
694
|
+
8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
|
|
552
695
|
}
|
|
553
696
|
});
|
|
554
697
|
|
|
555
698
|
// src/logging/logger.ts
|
|
556
699
|
import * as fs2 from "fs";
|
|
557
|
-
import * as
|
|
700
|
+
import * as path10 from "path";
|
|
558
701
|
import * as os4 from "os";
|
|
559
702
|
function setLogLevel(level) {
|
|
560
703
|
currentLevel = level;
|
|
@@ -570,13 +713,13 @@ function getDaemonLogDir() {
|
|
|
570
713
|
return LOG_DIR;
|
|
571
714
|
}
|
|
572
715
|
function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
|
|
573
|
-
return
|
|
716
|
+
return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
|
|
574
717
|
}
|
|
575
718
|
function checkDateRotation() {
|
|
576
719
|
const today = getDateStr();
|
|
577
720
|
if (today !== currentDate) {
|
|
578
721
|
currentDate = today;
|
|
579
|
-
currentLogFile =
|
|
722
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
580
723
|
cleanOldLogs();
|
|
581
724
|
}
|
|
582
725
|
}
|
|
@@ -590,7 +733,7 @@ function cleanOldLogs() {
|
|
|
590
733
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
591
734
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
592
735
|
try {
|
|
593
|
-
fs2.unlinkSync(
|
|
736
|
+
fs2.unlinkSync(path10.join(LOG_DIR, file));
|
|
594
737
|
} catch {
|
|
595
738
|
}
|
|
596
739
|
}
|
|
@@ -713,7 +856,7 @@ var init_logger = __esm({
|
|
|
713
856
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
714
857
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
715
858
|
currentLevel = "info";
|
|
716
|
-
LOG_DIR = process.platform === "win32" ?
|
|
859
|
+
LOG_DIR = process.platform === "win32" ? path10.join(process.env.LOCALAPPDATA || process.env.APPDATA || path10.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path10.join(os4.homedir(), "Library", "Logs", "adhdev") : path10.join(os4.homedir(), ".local", "share", "adhdev", "logs");
|
|
717
860
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
718
861
|
MAX_LOG_DAYS = 7;
|
|
719
862
|
try {
|
|
@@ -721,16 +864,16 @@ var init_logger = __esm({
|
|
|
721
864
|
} catch {
|
|
722
865
|
}
|
|
723
866
|
currentDate = getDateStr();
|
|
724
|
-
currentLogFile =
|
|
867
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
725
868
|
cleanOldLogs();
|
|
726
869
|
try {
|
|
727
|
-
const oldLog =
|
|
870
|
+
const oldLog = path10.join(LOG_DIR, "daemon.log");
|
|
728
871
|
if (fs2.existsSync(oldLog)) {
|
|
729
872
|
const stat2 = fs2.statSync(oldLog);
|
|
730
873
|
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
731
|
-
fs2.renameSync(oldLog,
|
|
874
|
+
fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
732
875
|
}
|
|
733
|
-
const oldLogBackup =
|
|
876
|
+
const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
|
|
734
877
|
if (fs2.existsSync(oldLogBackup)) {
|
|
735
878
|
fs2.unlinkSync(oldLogBackup);
|
|
736
879
|
}
|
|
@@ -762,7 +905,7 @@ var init_logger = __esm({
|
|
|
762
905
|
}
|
|
763
906
|
};
|
|
764
907
|
interceptorInstalled = false;
|
|
765
|
-
LOG_PATH =
|
|
908
|
+
LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
766
909
|
}
|
|
767
910
|
});
|
|
768
911
|
|
|
@@ -1171,7 +1314,7 @@ var init_pty_transport = __esm({
|
|
|
1171
1314
|
|
|
1172
1315
|
// src/cli-adapters/provider-cli-shared.ts
|
|
1173
1316
|
import * as os9 from "os";
|
|
1174
|
-
import * as
|
|
1317
|
+
import * as path14 from "path";
|
|
1175
1318
|
import { execSync as execSync3 } from "child_process";
|
|
1176
1319
|
function stripAnsi(str) {
|
|
1177
1320
|
return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
|
|
@@ -1236,9 +1379,9 @@ function buildCliScreenSnapshot(text) {
|
|
|
1236
1379
|
function findBinary(name) {
|
|
1237
1380
|
const trimmed = String(name || "").trim();
|
|
1238
1381
|
if (!trimmed) return trimmed;
|
|
1239
|
-
const expanded = trimmed.startsWith("~") ?
|
|
1240
|
-
if (
|
|
1241
|
-
return
|
|
1382
|
+
const expanded = trimmed.startsWith("~") ? path14.join(os9.homedir(), trimmed.slice(1)) : trimmed;
|
|
1383
|
+
if (path14.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
|
|
1384
|
+
return path14.isAbsolute(expanded) ? expanded : path14.resolve(expanded);
|
|
1242
1385
|
}
|
|
1243
1386
|
const isWin = os9.platform() === "win32";
|
|
1244
1387
|
try {
|
|
@@ -1254,7 +1397,7 @@ function findBinary(name) {
|
|
|
1254
1397
|
}
|
|
1255
1398
|
}
|
|
1256
1399
|
function isScriptBinary(binaryPath) {
|
|
1257
|
-
if (!
|
|
1400
|
+
if (!path14.isAbsolute(binaryPath)) return false;
|
|
1258
1401
|
try {
|
|
1259
1402
|
const fs16 = __require("fs");
|
|
1260
1403
|
const resolved = fs16.realpathSync(binaryPath);
|
|
@@ -1270,7 +1413,7 @@ function isScriptBinary(binaryPath) {
|
|
|
1270
1413
|
}
|
|
1271
1414
|
}
|
|
1272
1415
|
function looksLikeMachOOrElf(filePath) {
|
|
1273
|
-
if (!
|
|
1416
|
+
if (!path14.isAbsolute(filePath)) return false;
|
|
1274
1417
|
try {
|
|
1275
1418
|
const fs16 = __require("fs");
|
|
1276
1419
|
const resolved = fs16.realpathSync(filePath);
|
|
@@ -1484,10 +1627,10 @@ var init_provider_cli_config = __esm({
|
|
|
1484
1627
|
|
|
1485
1628
|
// src/cli-adapters/provider-cli-runtime.ts
|
|
1486
1629
|
import * as os10 from "os";
|
|
1487
|
-
import * as
|
|
1630
|
+
import * as path15 from "path";
|
|
1488
1631
|
import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from "@adhdev/session-host-core";
|
|
1489
1632
|
function resolveCliSpawnPlan(options) {
|
|
1490
|
-
const { provider, runtimeSettings, workingDir, extraArgs } = options;
|
|
1633
|
+
const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
|
|
1491
1634
|
const { spawn: spawnConfig } = provider;
|
|
1492
1635
|
const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
|
|
1493
1636
|
const binaryPath = findBinary(configuredCommand);
|
|
@@ -1495,9 +1638,9 @@ function resolveCliSpawnPlan(options) {
|
|
|
1495
1638
|
const allArgs = [...spawnConfig.args, ...extraArgs];
|
|
1496
1639
|
let shellCmd;
|
|
1497
1640
|
let shellArgs;
|
|
1498
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1641
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1499
1642
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
1500
|
-
const useShellWin = !!spawnConfig.shell || isCmdShim || !
|
|
1643
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
1501
1644
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
1502
1645
|
if (useShell) {
|
|
1503
1646
|
shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
|
|
@@ -1511,7 +1654,7 @@ function resolveCliSpawnPlan(options) {
|
|
|
1511
1654
|
shellCmd = binaryPath;
|
|
1512
1655
|
shellArgs = allArgs;
|
|
1513
1656
|
}
|
|
1514
|
-
const env = buildCliSpawnEnv(process.env, spawnConfig.env);
|
|
1657
|
+
const env = buildCliSpawnEnv(process.env, { ...spawnConfig.env || {}, ...extraEnv || {} });
|
|
1515
1658
|
env.TERMINAL_CWD = workingDir;
|
|
1516
1659
|
return {
|
|
1517
1660
|
binaryPath,
|
|
@@ -1610,8 +1753,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1610
1753
|
init_provider_cli_runtime();
|
|
1611
1754
|
init_provider_cli_shared();
|
|
1612
1755
|
ProviderCliAdapter = class _ProviderCliAdapter {
|
|
1613
|
-
constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
|
|
1756
|
+
constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
|
|
1614
1757
|
this.extraArgs = extraArgs;
|
|
1758
|
+
this.extraEnv = extraEnv;
|
|
1615
1759
|
this.provider = provider;
|
|
1616
1760
|
this.transportFactory = transportFactory;
|
|
1617
1761
|
this.cliType = provider.type;
|
|
@@ -1762,8 +1906,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1762
1906
|
const currentSnapshot = normalizeScreenSnapshot(screenText);
|
|
1763
1907
|
const lastSnapshot = this.lastScreenSnapshot;
|
|
1764
1908
|
if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
|
|
1765
|
-
const
|
|
1766
|
-
const
|
|
1909
|
+
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;
|
|
1910
|
+
const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
|
|
1911
|
+
const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
|
|
1767
1912
|
if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
|
|
1768
1913
|
if (currentSnapshot.length >= lastSnapshot.length) return screenText;
|
|
1769
1914
|
return `${screenText}
|
|
@@ -1926,7 +2071,8 @@ ${lastSnapshot}`;
|
|
|
1926
2071
|
provider: this.provider,
|
|
1927
2072
|
runtimeSettings: this.runtimeSettings,
|
|
1928
2073
|
workingDir: this.workingDir,
|
|
1929
|
-
extraArgs: this.extraArgs
|
|
2074
|
+
extraArgs: this.extraArgs,
|
|
2075
|
+
extraEnv: this.extraEnv
|
|
1930
2076
|
});
|
|
1931
2077
|
LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
1932
2078
|
this.resetTraceSession();
|
|
@@ -4547,6 +4693,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
|
4547
4693
|
"dirty_index_required",
|
|
4548
4694
|
"conflict",
|
|
4549
4695
|
"invalid_args",
|
|
4696
|
+
"nothing_to_commit",
|
|
4550
4697
|
"git_command_failed"
|
|
4551
4698
|
]);
|
|
4552
4699
|
function failure(reason, error) {
|
|
@@ -4791,7 +4938,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
|
4791
4938
|
} catch (err) {
|
|
4792
4939
|
const output = (err?.stdout || "") + (err?.stderr || "");
|
|
4793
4940
|
if (/nothing to commit/i.test(output)) {
|
|
4794
|
-
throw new GitCommandError("
|
|
4941
|
+
throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
|
|
4942
|
+
stdout: err?.stdout,
|
|
4943
|
+
stderr: err?.stderr
|
|
4944
|
+
});
|
|
4795
4945
|
}
|
|
4796
4946
|
throw err;
|
|
4797
4947
|
}
|
|
@@ -4983,20 +5133,23 @@ var TurnSnapshotTracker = class {
|
|
|
4983
5133
|
}
|
|
4984
5134
|
};
|
|
4985
5135
|
|
|
5136
|
+
// src/git/index.ts
|
|
5137
|
+
init_git_worktree();
|
|
5138
|
+
|
|
4986
5139
|
// src/index.ts
|
|
4987
5140
|
init_config();
|
|
4988
5141
|
|
|
4989
5142
|
// src/config/workspaces.ts
|
|
4990
5143
|
import * as fs from "fs";
|
|
4991
5144
|
import * as os from "os";
|
|
4992
|
-
import * as
|
|
5145
|
+
import * as path5 from "path";
|
|
4993
5146
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4994
5147
|
var MAX_WORKSPACES = 50;
|
|
4995
5148
|
function expandPath(p) {
|
|
4996
5149
|
const t = (p || "").trim();
|
|
4997
5150
|
if (!t) return "";
|
|
4998
|
-
if (t.startsWith("~")) return
|
|
4999
|
-
return
|
|
5151
|
+
if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5152
|
+
return path5.resolve(t);
|
|
5000
5153
|
}
|
|
5001
5154
|
function validateWorkspacePath(absPath) {
|
|
5002
5155
|
try {
|
|
@@ -5010,7 +5163,7 @@ function validateWorkspacePath(absPath) {
|
|
|
5010
5163
|
}
|
|
5011
5164
|
}
|
|
5012
5165
|
function defaultWorkspaceLabel(absPath) {
|
|
5013
|
-
const base =
|
|
5166
|
+
const base = path5.basename(absPath) || absPath;
|
|
5014
5167
|
return base;
|
|
5015
5168
|
}
|
|
5016
5169
|
function getDefaultWorkspacePath(config) {
|
|
@@ -5101,9 +5254,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
5101
5254
|
return getDefaultWorkspacePath(config) || void 0;
|
|
5102
5255
|
}
|
|
5103
5256
|
function findWorkspaceByPath(config, rawPath) {
|
|
5104
|
-
const abs =
|
|
5257
|
+
const abs = path5.resolve(expandPath(rawPath));
|
|
5105
5258
|
if (!abs) return void 0;
|
|
5106
|
-
return (config.workspaces || []).find((w) =>
|
|
5259
|
+
return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
|
|
5107
5260
|
}
|
|
5108
5261
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
5109
5262
|
const abs = expandPath(rawPath);
|
|
@@ -5119,7 +5272,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
5119
5272
|
const v = validateWorkspacePath(abs);
|
|
5120
5273
|
if (!v.ok) return { error: v.error };
|
|
5121
5274
|
const list = [...config.workspaces || []];
|
|
5122
|
-
if (list.some((w) =>
|
|
5275
|
+
if (list.some((w) => path5.resolve(w.path) === abs)) {
|
|
5123
5276
|
return { error: "Workspace already in list" };
|
|
5124
5277
|
}
|
|
5125
5278
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -5153,7 +5306,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
5153
5306
|
}
|
|
5154
5307
|
|
|
5155
5308
|
// src/config/recent-activity.ts
|
|
5156
|
-
import * as
|
|
5309
|
+
import * as path6 from "path";
|
|
5157
5310
|
|
|
5158
5311
|
// src/providers/summary-metadata.ts
|
|
5159
5312
|
function normalizeSummaryItem(item) {
|
|
@@ -5222,9 +5375,9 @@ var MAX_ACTIVITY = 30;
|
|
|
5222
5375
|
function normalizeWorkspace(workspace) {
|
|
5223
5376
|
if (!workspace) return "";
|
|
5224
5377
|
try {
|
|
5225
|
-
return
|
|
5378
|
+
return path6.resolve(expandPath(workspace));
|
|
5226
5379
|
} catch {
|
|
5227
|
-
return
|
|
5380
|
+
return path6.resolve(workspace);
|
|
5228
5381
|
}
|
|
5229
5382
|
}
|
|
5230
5383
|
function buildRecentActivityKey(entry) {
|
|
@@ -5392,14 +5545,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5392
5545
|
}
|
|
5393
5546
|
|
|
5394
5547
|
// src/config/saved-sessions.ts
|
|
5395
|
-
import * as
|
|
5548
|
+
import * as path7 from "path";
|
|
5396
5549
|
var MAX_SAVED_SESSIONS = 500;
|
|
5397
5550
|
function normalizeWorkspace2(workspace) {
|
|
5398
5551
|
if (!workspace) return "";
|
|
5399
5552
|
try {
|
|
5400
|
-
return
|
|
5553
|
+
return path7.resolve(expandPath(workspace));
|
|
5401
5554
|
} catch {
|
|
5402
|
-
return
|
|
5555
|
+
return path7.resolve(workspace);
|
|
5403
5556
|
}
|
|
5404
5557
|
}
|
|
5405
5558
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5505,8 +5658,8 @@ async function syncMeshes(transport) {
|
|
|
5505
5658
|
|
|
5506
5659
|
// src/config/state-store.ts
|
|
5507
5660
|
init_config();
|
|
5508
|
-
import { existsSync as
|
|
5509
|
-
import { join as
|
|
5661
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5662
|
+
import { join as join5 } from "path";
|
|
5510
5663
|
var DEFAULT_STATE = {
|
|
5511
5664
|
recentActivity: [],
|
|
5512
5665
|
savedProviderSessions: [],
|
|
@@ -5519,7 +5672,7 @@ function isPlainObject2(value) {
|
|
|
5519
5672
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5520
5673
|
}
|
|
5521
5674
|
function getStatePath() {
|
|
5522
|
-
return
|
|
5675
|
+
return join5(getConfigDir(), "state.json");
|
|
5523
5676
|
}
|
|
5524
5677
|
function normalizeState(raw) {
|
|
5525
5678
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -5555,7 +5708,7 @@ function normalizeState(raw) {
|
|
|
5555
5708
|
}
|
|
5556
5709
|
function loadState() {
|
|
5557
5710
|
const statePath = getStatePath();
|
|
5558
|
-
if (!
|
|
5711
|
+
if (!existsSync5(statePath)) {
|
|
5559
5712
|
return { ...DEFAULT_STATE };
|
|
5560
5713
|
}
|
|
5561
5714
|
try {
|
|
@@ -5576,9 +5729,9 @@ function resetState() {
|
|
|
5576
5729
|
|
|
5577
5730
|
// src/detection/ide-detector.ts
|
|
5578
5731
|
import { execSync } from "child_process";
|
|
5579
|
-
import { existsSync as
|
|
5732
|
+
import { existsSync as existsSync6 } from "fs";
|
|
5580
5733
|
import { platform, homedir as homedir3 } from "os";
|
|
5581
|
-
import * as
|
|
5734
|
+
import * as path8 from "path";
|
|
5582
5735
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5583
5736
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5584
5737
|
function registerIDEDefinition(def) {
|
|
@@ -5597,10 +5750,10 @@ function getMergedDefinitions() {
|
|
|
5597
5750
|
function findCliCommand(command) {
|
|
5598
5751
|
const trimmed = String(command || "").trim();
|
|
5599
5752
|
if (!trimmed) return null;
|
|
5600
|
-
if (
|
|
5601
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5602
|
-
const resolved =
|
|
5603
|
-
return
|
|
5753
|
+
if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
5754
|
+
const candidate = trimmed.startsWith("~") ? path8.join(homedir3(), trimmed.slice(1)) : trimmed;
|
|
5755
|
+
const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
|
|
5756
|
+
return existsSync6(resolved) ? resolved : null;
|
|
5604
5757
|
}
|
|
5605
5758
|
try {
|
|
5606
5759
|
const result = execSync(
|
|
@@ -5627,31 +5780,31 @@ function getIdeVersion(cliCommand) {
|
|
|
5627
5780
|
function checkPathExists(paths) {
|
|
5628
5781
|
const home = homedir3();
|
|
5629
5782
|
for (const p of paths) {
|
|
5630
|
-
const normalized = p.startsWith("~") ?
|
|
5783
|
+
const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
|
|
5631
5784
|
if (normalized.includes("*")) {
|
|
5632
5785
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5633
5786
|
const resolved = normalized.replace("*", username);
|
|
5634
|
-
if (
|
|
5787
|
+
if (existsSync6(resolved)) return resolved;
|
|
5635
5788
|
} else {
|
|
5636
|
-
if (
|
|
5789
|
+
if (existsSync6(normalized)) return normalized;
|
|
5637
5790
|
}
|
|
5638
5791
|
}
|
|
5639
5792
|
return null;
|
|
5640
5793
|
}
|
|
5641
5794
|
async function detectIDEs(providerLoader) {
|
|
5642
|
-
const
|
|
5795
|
+
const os22 = platform();
|
|
5643
5796
|
const results = [];
|
|
5644
5797
|
for (const def of getMergedDefinitions()) {
|
|
5645
5798
|
const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
|
|
5646
|
-
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[
|
|
5799
|
+
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
|
|
5647
5800
|
let resolvedCli = cliPath;
|
|
5648
|
-
if (!resolvedCli && appPath &&
|
|
5801
|
+
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
5649
5802
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
5650
|
-
if (
|
|
5803
|
+
if (existsSync6(bundledCli)) resolvedCli = bundledCli;
|
|
5651
5804
|
}
|
|
5652
|
-
if (!resolvedCli && appPath &&
|
|
5653
|
-
const { dirname:
|
|
5654
|
-
const appDir =
|
|
5805
|
+
if (!resolvedCli && appPath && os22 === "win32") {
|
|
5806
|
+
const { dirname: dirname9 } = await import("path");
|
|
5807
|
+
const appDir = dirname9(appPath);
|
|
5655
5808
|
const candidates = [
|
|
5656
5809
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
5657
5810
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -5660,13 +5813,13 @@ async function detectIDEs(providerLoader) {
|
|
|
5660
5813
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
5661
5814
|
];
|
|
5662
5815
|
for (const c of candidates) {
|
|
5663
|
-
if (
|
|
5816
|
+
if (existsSync6(c)) {
|
|
5664
5817
|
resolvedCli = c;
|
|
5665
5818
|
break;
|
|
5666
5819
|
}
|
|
5667
5820
|
}
|
|
5668
5821
|
}
|
|
5669
|
-
const installed =
|
|
5822
|
+
const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
|
|
5670
5823
|
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
5671
5824
|
results.push({
|
|
5672
5825
|
id: def.id,
|
|
@@ -5685,8 +5838,8 @@ async function detectIDEs(providerLoader) {
|
|
|
5685
5838
|
// src/detection/cli-detector.ts
|
|
5686
5839
|
import { exec } from "child_process";
|
|
5687
5840
|
import * as os2 from "os";
|
|
5688
|
-
import * as
|
|
5689
|
-
import { existsSync as
|
|
5841
|
+
import * as path9 from "path";
|
|
5842
|
+
import { existsSync as existsSync7 } from "fs";
|
|
5690
5843
|
function parseVersion(raw) {
|
|
5691
5844
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
5692
5845
|
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
@@ -5698,19 +5851,19 @@ function shellQuote(value) {
|
|
|
5698
5851
|
function expandHome(value) {
|
|
5699
5852
|
const trimmed = value.trim();
|
|
5700
5853
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5701
|
-
return
|
|
5854
|
+
return path9.join(os2.homedir(), trimmed.slice(1));
|
|
5702
5855
|
}
|
|
5703
5856
|
function isExplicitCommandPath(command) {
|
|
5704
5857
|
const trimmed = command.trim();
|
|
5705
|
-
return
|
|
5858
|
+
return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5706
5859
|
}
|
|
5707
5860
|
function resolveCommandPath(command) {
|
|
5708
5861
|
const trimmed = command.trim();
|
|
5709
5862
|
if (!trimmed) return null;
|
|
5710
5863
|
if (isExplicitCommandPath(trimmed)) {
|
|
5711
5864
|
const expanded = expandHome(trimmed);
|
|
5712
|
-
const candidate =
|
|
5713
|
-
return
|
|
5865
|
+
const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
|
|
5866
|
+
return existsSync7(candidate) ? candidate : null;
|
|
5714
5867
|
}
|
|
5715
5868
|
return null;
|
|
5716
5869
|
}
|
|
@@ -7978,9 +8131,9 @@ ${cleanBody}`;
|
|
|
7978
8131
|
|
|
7979
8132
|
// src/config/chat-history.ts
|
|
7980
8133
|
import * as fs3 from "fs";
|
|
7981
|
-
import * as
|
|
8134
|
+
import * as path11 from "path";
|
|
7982
8135
|
import * as os5 from "os";
|
|
7983
|
-
var HISTORY_DIR =
|
|
8136
|
+
var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
|
|
7984
8137
|
var RETAIN_DAYS = 30;
|
|
7985
8138
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
7986
8139
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -8143,7 +8296,7 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
8143
8296
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
8144
8297
|
return new Map(files.map((file) => {
|
|
8145
8298
|
try {
|
|
8146
|
-
const stat2 = fs3.statSync(
|
|
8299
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8147
8300
|
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
8148
8301
|
} catch {
|
|
8149
8302
|
return [file, `${file}:missing`];
|
|
@@ -8154,7 +8307,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
8154
8307
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
8155
8308
|
}
|
|
8156
8309
|
function getSavedHistoryIndexFilePath(dir) {
|
|
8157
|
-
return
|
|
8310
|
+
return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
8158
8311
|
}
|
|
8159
8312
|
function getSavedHistoryIndexLockPath(dir) {
|
|
8160
8313
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -8256,7 +8409,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
8256
8409
|
}
|
|
8257
8410
|
for (const file of Array.from(currentEntries.keys())) {
|
|
8258
8411
|
if (incomingFiles.has(file)) continue;
|
|
8259
|
-
if (!fs3.existsSync(
|
|
8412
|
+
if (!fs3.existsSync(path11.join(dir, file))) {
|
|
8260
8413
|
currentEntries.delete(file);
|
|
8261
8414
|
}
|
|
8262
8415
|
}
|
|
@@ -8282,7 +8435,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8282
8435
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8283
8436
|
const files = listHistoryFiles(dir);
|
|
8284
8437
|
for (const file of files) {
|
|
8285
|
-
const stat2 = fs3.statSync(
|
|
8438
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8286
8439
|
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
8287
8440
|
}
|
|
8288
8441
|
return false;
|
|
@@ -8292,14 +8445,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8292
8445
|
}
|
|
8293
8446
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
8294
8447
|
try {
|
|
8295
|
-
const stat2 = fs3.statSync(
|
|
8448
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8296
8449
|
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
8297
8450
|
} catch {
|
|
8298
8451
|
return `${file}:missing`;
|
|
8299
8452
|
}
|
|
8300
8453
|
}
|
|
8301
8454
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
8302
|
-
const filePath =
|
|
8455
|
+
const filePath = path11.join(dir, file);
|
|
8303
8456
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
8304
8457
|
const currentEntry = entries.get(file) || null;
|
|
8305
8458
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -8372,7 +8525,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
8372
8525
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
8373
8526
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
8374
8527
|
if (!historySessionId) return null;
|
|
8375
|
-
const filePath =
|
|
8528
|
+
const filePath = path11.join(dir, file);
|
|
8376
8529
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8377
8530
|
const lines = content.split("\n").filter(Boolean);
|
|
8378
8531
|
let messageCount = 0;
|
|
@@ -8459,7 +8612,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
8459
8612
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
8460
8613
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
8461
8614
|
for (const file of files.slice().sort()) {
|
|
8462
|
-
const filePath =
|
|
8615
|
+
const filePath = path11.join(dir, file);
|
|
8463
8616
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
8464
8617
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
8465
8618
|
const persisted = persistedEntries.get(file);
|
|
@@ -8579,12 +8732,12 @@ var ChatHistoryWriter = class {
|
|
|
8579
8732
|
});
|
|
8580
8733
|
}
|
|
8581
8734
|
if (newMessages.length === 0) return;
|
|
8582
|
-
const dir =
|
|
8735
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8583
8736
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8584
8737
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8585
8738
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
8586
8739
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
8587
|
-
const filePath =
|
|
8740
|
+
const filePath = path11.join(dir, fileName);
|
|
8588
8741
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
8589
8742
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
8590
8743
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -8675,11 +8828,11 @@ var ChatHistoryWriter = class {
|
|
|
8675
8828
|
const ws = String(workspace || "").trim();
|
|
8676
8829
|
if (!id || !ws) return;
|
|
8677
8830
|
try {
|
|
8678
|
-
const dir =
|
|
8831
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8679
8832
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8680
8833
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8681
8834
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
8682
|
-
const filePath =
|
|
8835
|
+
const filePath = path11.join(dir, fileName);
|
|
8683
8836
|
const record = {
|
|
8684
8837
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8685
8838
|
receivedAt: Date.now(),
|
|
@@ -8725,14 +8878,14 @@ var ChatHistoryWriter = class {
|
|
|
8725
8878
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8726
8879
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8727
8880
|
}
|
|
8728
|
-
const dir =
|
|
8881
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8729
8882
|
if (!fs3.existsSync(dir)) return;
|
|
8730
8883
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8731
8884
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8732
8885
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8733
8886
|
for (const file of files) {
|
|
8734
|
-
const sourcePath =
|
|
8735
|
-
const targetPath =
|
|
8887
|
+
const sourcePath = path11.join(dir, file);
|
|
8888
|
+
const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8736
8889
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8737
8890
|
const rewritten = sourceLines.map((line) => {
|
|
8738
8891
|
try {
|
|
@@ -8766,13 +8919,13 @@ var ChatHistoryWriter = class {
|
|
|
8766
8919
|
const sessionId = String(historySessionId || "").trim();
|
|
8767
8920
|
if (!sessionId) return;
|
|
8768
8921
|
try {
|
|
8769
|
-
const dir =
|
|
8922
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8770
8923
|
if (!fs3.existsSync(dir)) return;
|
|
8771
8924
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8772
8925
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8773
8926
|
const seen = /* @__PURE__ */ new Set();
|
|
8774
8927
|
for (const file of files) {
|
|
8775
|
-
const filePath =
|
|
8928
|
+
const filePath = path11.join(dir, file);
|
|
8776
8929
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8777
8930
|
const next = [];
|
|
8778
8931
|
for (const line of lines) {
|
|
@@ -8826,11 +8979,11 @@ var ChatHistoryWriter = class {
|
|
|
8826
8979
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
8827
8980
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
8828
8981
|
for (const dir of agentDirs) {
|
|
8829
|
-
const dirPath =
|
|
8982
|
+
const dirPath = path11.join(HISTORY_DIR, dir.name);
|
|
8830
8983
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
8831
8984
|
let removedAny = false;
|
|
8832
8985
|
for (const file of files) {
|
|
8833
|
-
const filePath =
|
|
8986
|
+
const filePath = path11.join(dirPath, file);
|
|
8834
8987
|
const stat2 = fs3.statSync(filePath);
|
|
8835
8988
|
if (stat2.mtimeMs < cutoff) {
|
|
8836
8989
|
fs3.unlinkSync(filePath);
|
|
@@ -8880,13 +9033,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8880
9033
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8881
9034
|
try {
|
|
8882
9035
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8883
|
-
const dir =
|
|
9036
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8884
9037
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
8885
9038
|
const files = listHistoryFiles(dir, historySessionId);
|
|
8886
9039
|
const allMessages = [];
|
|
8887
9040
|
const seen = /* @__PURE__ */ new Set();
|
|
8888
9041
|
for (const file of files) {
|
|
8889
|
-
const filePath =
|
|
9042
|
+
const filePath = path11.join(dir, file);
|
|
8890
9043
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8891
9044
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
8892
9045
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8910,7 +9063,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8910
9063
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
8911
9064
|
try {
|
|
8912
9065
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8913
|
-
const dir =
|
|
9066
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8914
9067
|
if (!fs3.existsSync(dir)) {
|
|
8915
9068
|
savedHistorySessionCache.delete(sanitized);
|
|
8916
9069
|
return { sessions: [], hasMore: false };
|
|
@@ -8971,11 +9124,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8971
9124
|
}
|
|
8972
9125
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8973
9126
|
try {
|
|
8974
|
-
const dir =
|
|
9127
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8975
9128
|
if (!fs3.existsSync(dir)) return null;
|
|
8976
9129
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
8977
9130
|
for (const file of files) {
|
|
8978
|
-
const lines = fs3.readFileSync(
|
|
9131
|
+
const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
8979
9132
|
for (const line of lines) {
|
|
8980
9133
|
try {
|
|
8981
9134
|
const parsed = JSON.parse(line);
|
|
@@ -8995,16 +9148,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
8995
9148
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
8996
9149
|
if (records.length === 0) return false;
|
|
8997
9150
|
try {
|
|
8998
|
-
const dir =
|
|
9151
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8999
9152
|
fs3.mkdirSync(dir, { recursive: true });
|
|
9000
9153
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
9001
9154
|
for (const file of fs3.readdirSync(dir)) {
|
|
9002
9155
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
9003
|
-
fs3.unlinkSync(
|
|
9156
|
+
fs3.unlinkSync(path11.join(dir, file));
|
|
9004
9157
|
}
|
|
9005
9158
|
}
|
|
9006
9159
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
9007
|
-
const filePath =
|
|
9160
|
+
const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
9008
9161
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
9009
9162
|
`, "utf-8");
|
|
9010
9163
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -10999,6 +11152,14 @@ function getActiveChatOptions(profile) {
|
|
|
10999
11152
|
if (profile === "full") return {};
|
|
11000
11153
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
11001
11154
|
}
|
|
11155
|
+
function resolveSessionStatus(activeChat, providerStatus) {
|
|
11156
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
11157
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
11158
|
+
if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
|
|
11159
|
+
if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
|
|
11160
|
+
if (topLevelStatus !== "idle") return topLevelStatus;
|
|
11161
|
+
return chatStatus;
|
|
11162
|
+
}
|
|
11002
11163
|
function shouldIncludeSessionControls(profile) {
|
|
11003
11164
|
return profile !== "live";
|
|
11004
11165
|
}
|
|
@@ -11077,9 +11238,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11077
11238
|
providerName: state.name,
|
|
11078
11239
|
kind: "workspace",
|
|
11079
11240
|
transport: "cdp-page",
|
|
11080
|
-
status:
|
|
11081
|
-
activeModal: activeChat?.activeModal || null
|
|
11082
|
-
}),
|
|
11241
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11083
11242
|
title,
|
|
11084
11243
|
workspace,
|
|
11085
11244
|
...git && { git },
|
|
@@ -11114,9 +11273,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11114
11273
|
providerSessionId: ext.providerSessionId,
|
|
11115
11274
|
kind: "agent",
|
|
11116
11275
|
transport: "cdp-webview",
|
|
11117
|
-
status:
|
|
11118
|
-
activeModal: activeChat?.activeModal || null
|
|
11119
|
-
}),
|
|
11276
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
11120
11277
|
title: activeChat?.title || ext.name,
|
|
11121
11278
|
workspace,
|
|
11122
11279
|
...git && { git },
|
|
@@ -11166,9 +11323,7 @@ function buildCliSession(state, options) {
|
|
|
11166
11323
|
providerSessionId: state.providerSessionId,
|
|
11167
11324
|
kind: "agent",
|
|
11168
11325
|
transport: "pty",
|
|
11169
|
-
status:
|
|
11170
|
-
activeModal: activeChat?.activeModal || null
|
|
11171
|
-
}),
|
|
11326
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11172
11327
|
title: activeChat?.title || state.name,
|
|
11173
11328
|
workspace,
|
|
11174
11329
|
...git && { git },
|
|
@@ -11216,9 +11371,7 @@ function buildAcpSession(state, options) {
|
|
|
11216
11371
|
providerName: state.name,
|
|
11217
11372
|
kind: "agent",
|
|
11218
11373
|
transport: "acp",
|
|
11219
|
-
status:
|
|
11220
|
-
activeModal: activeChat?.activeModal || null
|
|
11221
|
-
}),
|
|
11374
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11222
11375
|
title: activeChat?.title || state.name,
|
|
11223
11376
|
workspace,
|
|
11224
11377
|
...git && { git },
|
|
@@ -11341,7 +11494,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
11341
11494
|
// src/commands/chat-commands.ts
|
|
11342
11495
|
import * as fs4 from "fs";
|
|
11343
11496
|
import * as os6 from "os";
|
|
11344
|
-
import * as
|
|
11497
|
+
import * as path12 from "path";
|
|
11345
11498
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
11346
11499
|
|
|
11347
11500
|
// src/providers/provider-input-support.ts
|
|
@@ -11704,6 +11857,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
11704
11857
|
return raw;
|
|
11705
11858
|
}
|
|
11706
11859
|
}
|
|
11860
|
+
function isGeneratingLikeStatus(status) {
|
|
11861
|
+
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
11862
|
+
}
|
|
11863
|
+
function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
11864
|
+
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
11865
|
+
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
11866
|
+
const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
|
|
11867
|
+
if (adapterRawStatus !== "idle") return false;
|
|
11868
|
+
if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
|
|
11869
|
+
return true;
|
|
11870
|
+
}
|
|
11871
|
+
function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
11872
|
+
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
11873
|
+
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
11874
|
+
}
|
|
11875
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
11876
|
+
if (status !== "idle") return messages;
|
|
11877
|
+
return messages.map((message) => {
|
|
11878
|
+
const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
11879
|
+
const hasStreamingMeta = meta?.streaming === true;
|
|
11880
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
11881
|
+
return {
|
|
11882
|
+
...message,
|
|
11883
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
11884
|
+
...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
|
|
11885
|
+
};
|
|
11886
|
+
});
|
|
11887
|
+
}
|
|
11707
11888
|
function buildReadChatCommandResult(payload, args) {
|
|
11708
11889
|
let validatedPayload;
|
|
11709
11890
|
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
@@ -11852,7 +12033,7 @@ function buildDebugBundleText(bundle) {
|
|
|
11852
12033
|
}
|
|
11853
12034
|
function getChatDebugBundleDir() {
|
|
11854
12035
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
11855
|
-
return override ||
|
|
12036
|
+
return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
11856
12037
|
}
|
|
11857
12038
|
function safeBundleIdSegment(value, fallback) {
|
|
11858
12039
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -11885,7 +12066,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
11885
12066
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
11886
12067
|
const dir = getChatDebugBundleDir();
|
|
11887
12068
|
fs4.mkdirSync(dir, { recursive: true });
|
|
11888
|
-
const savedPath =
|
|
12069
|
+
const savedPath = path12.join(dir, `${bundleId}.json`);
|
|
11889
12070
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
11890
12071
|
`;
|
|
11891
12072
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -12115,7 +12296,7 @@ async function handleChatHistory(h, args) {
|
|
|
12115
12296
|
}
|
|
12116
12297
|
}
|
|
12117
12298
|
async function handleReadChat(h, args) {
|
|
12118
|
-
const provider = h.getProvider(args?.agentType);
|
|
12299
|
+
const provider = h.getProvider(args?.agentType || args?.providerType);
|
|
12119
12300
|
const transport = getTargetTransport(h, provider);
|
|
12120
12301
|
const historySessionId = getHistorySessionId(h, args);
|
|
12121
12302
|
const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
|
|
@@ -12142,10 +12323,13 @@ async function handleReadChat(h, args) {
|
|
|
12142
12323
|
const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
12143
12324
|
const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
12144
12325
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
12145
|
-
const returnedStatus = parsedRecord.status
|
|
12146
|
-
|
|
12326
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
12327
|
+
const runtimeMessageMerger = getTargetInstance(h, args);
|
|
12328
|
+
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
|
|
12329
|
+
const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
|
|
12330
|
+
LOG.debug("Command", `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord.status || "")} parsedMsgCount=${parsedRecord.messages.length} returnedMsgCount=${returnedMessages.length}`);
|
|
12147
12331
|
return buildReadChatCommandResult({
|
|
12148
|
-
messages:
|
|
12332
|
+
messages: returnedMessages,
|
|
12149
12333
|
status: returnedStatus,
|
|
12150
12334
|
activeModal,
|
|
12151
12335
|
debugReadChat: {
|
|
@@ -12156,7 +12340,7 @@ async function handleReadChat(h, args) {
|
|
|
12156
12340
|
returnedStatus: String(returnedStatus || ""),
|
|
12157
12341
|
shouldPreferAdapterMessages: false,
|
|
12158
12342
|
parsedMsgCount: parsedRecord.messages.length,
|
|
12159
|
-
returnedMsgCount:
|
|
12343
|
+
returnedMsgCount: returnedMessages.length
|
|
12160
12344
|
},
|
|
12161
12345
|
...title ? { title } : {},
|
|
12162
12346
|
...providerSessionId ? { providerSessionId } : {},
|
|
@@ -13029,7 +13213,7 @@ async function handleResolveAction(h, args) {
|
|
|
13029
13213
|
|
|
13030
13214
|
// src/commands/cdp-commands.ts
|
|
13031
13215
|
import * as fs5 from "fs";
|
|
13032
|
-
import * as
|
|
13216
|
+
import * as path13 from "path";
|
|
13033
13217
|
import * as os7 from "os";
|
|
13034
13218
|
var KEY_TO_VK = {
|
|
13035
13219
|
Backspace: 8,
|
|
@@ -13286,25 +13470,25 @@ function resolveSafePath(requestedPath) {
|
|
|
13286
13470
|
const inputPath = rawPath || ".";
|
|
13287
13471
|
const home = os7.homedir();
|
|
13288
13472
|
if (inputPath.startsWith("~")) {
|
|
13289
|
-
return
|
|
13473
|
+
return path13.resolve(path13.join(home, inputPath.slice(1)));
|
|
13290
13474
|
}
|
|
13291
13475
|
if (process.platform === "win32") {
|
|
13292
13476
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
13293
|
-
if (
|
|
13294
|
-
return
|
|
13477
|
+
if (path13.win32.isAbsolute(normalized)) {
|
|
13478
|
+
return path13.win32.normalize(normalized);
|
|
13295
13479
|
}
|
|
13296
|
-
return
|
|
13480
|
+
return path13.win32.resolve(normalized);
|
|
13297
13481
|
}
|
|
13298
|
-
if (
|
|
13299
|
-
return
|
|
13482
|
+
if (path13.isAbsolute(inputPath)) {
|
|
13483
|
+
return path13.normalize(inputPath);
|
|
13300
13484
|
}
|
|
13301
|
-
return
|
|
13485
|
+
return path13.resolve(inputPath);
|
|
13302
13486
|
}
|
|
13303
13487
|
function listDirectoryEntriesSafe(dirPath) {
|
|
13304
13488
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
13305
13489
|
const files = [];
|
|
13306
13490
|
for (const entry of entries) {
|
|
13307
|
-
const entryPath =
|
|
13491
|
+
const entryPath = path13.join(dirPath, entry.name);
|
|
13308
13492
|
try {
|
|
13309
13493
|
if (entry.isDirectory()) {
|
|
13310
13494
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -13358,7 +13542,7 @@ async function handleFileRead(h, args) {
|
|
|
13358
13542
|
async function handleFileWrite(h, args) {
|
|
13359
13543
|
try {
|
|
13360
13544
|
const filePath = resolveSafePath(args?.path);
|
|
13361
|
-
fs5.mkdirSync(
|
|
13545
|
+
fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
13362
13546
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
13363
13547
|
return { success: true, path: filePath };
|
|
13364
13548
|
} catch (e) {
|
|
@@ -14142,9 +14326,11 @@ var DaemonCommandHandler = class {
|
|
|
14142
14326
|
}
|
|
14143
14327
|
const sessionLookupFailed = !!targetSessionId && !session;
|
|
14144
14328
|
const managerKey = this.extractIdeType(args, sessionLookupFailed);
|
|
14145
|
-
let providerType;
|
|
14329
|
+
let providerType = args?.agentType || args?.providerType;
|
|
14146
14330
|
if (!sessionLookupFailed) {
|
|
14147
|
-
providerType = session?.providerType ||
|
|
14331
|
+
providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
|
|
14332
|
+
} else if (!providerType) {
|
|
14333
|
+
providerType = this.inferProviderType(managerKey);
|
|
14148
14334
|
}
|
|
14149
14335
|
return { session, managerKey, providerType, sessionLookupFailed };
|
|
14150
14336
|
}
|
|
@@ -14224,7 +14410,8 @@ var DaemonCommandHandler = class {
|
|
|
14224
14410
|
"pty_resize",
|
|
14225
14411
|
"invoke_provider_script"
|
|
14226
14412
|
]);
|
|
14227
|
-
|
|
14413
|
+
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);
|
|
14414
|
+
if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
|
|
14228
14415
|
const result2 = {
|
|
14229
14416
|
success: false,
|
|
14230
14417
|
error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
|
|
@@ -14478,16 +14665,16 @@ var DaemonCommandHandler = class {
|
|
|
14478
14665
|
// src/commands/cli-manager.ts
|
|
14479
14666
|
init_provider_cli_adapter();
|
|
14480
14667
|
import * as os13 from "os";
|
|
14481
|
-
import * as
|
|
14668
|
+
import * as path17 from "path";
|
|
14482
14669
|
import * as crypto4 from "crypto";
|
|
14483
|
-
import { existsSync as
|
|
14670
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
14484
14671
|
import { execFileSync } from "child_process";
|
|
14485
14672
|
import chalk from "chalk";
|
|
14486
14673
|
init_config();
|
|
14487
14674
|
|
|
14488
14675
|
// src/providers/cli-provider-instance.ts
|
|
14489
14676
|
import * as os12 from "os";
|
|
14490
|
-
import * as
|
|
14677
|
+
import * as path16 from "path";
|
|
14491
14678
|
import * as crypto3 from "crypto";
|
|
14492
14679
|
import * as fs6 from "fs";
|
|
14493
14680
|
import { createRequire } from "module";
|
|
@@ -14546,7 +14733,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
14546
14733
|
var CachedDatabaseSync = null;
|
|
14547
14734
|
function getDatabaseSync() {
|
|
14548
14735
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
14549
|
-
const requireFn = typeof __require === "function" ? __require : createRequire(
|
|
14736
|
+
const requireFn = typeof __require === "function" ? __require : createRequire(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
14550
14737
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
14551
14738
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
14552
14739
|
if (!CachedDatabaseSync) {
|
|
@@ -14599,7 +14786,7 @@ var CliProviderInstance = class {
|
|
|
14599
14786
|
this.providerSessionId = options?.providerSessionId;
|
|
14600
14787
|
this.launchMode = options?.launchMode || "new";
|
|
14601
14788
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
14602
|
-
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
|
|
14789
|
+
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
14603
14790
|
this.monitor = new StatusMonitor();
|
|
14604
14791
|
this.historyWriter = new ChatHistoryWriter();
|
|
14605
14792
|
}
|
|
@@ -15076,7 +15263,19 @@ var CliProviderInstance = class {
|
|
|
15076
15263
|
}
|
|
15077
15264
|
}
|
|
15078
15265
|
pushEvent(event) {
|
|
15079
|
-
|
|
15266
|
+
const enrichedEvent = {
|
|
15267
|
+
...event,
|
|
15268
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
|
|
15269
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
|
|
15270
|
+
providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
|
|
15271
|
+
workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
|
|
15272
|
+
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
15273
|
+
};
|
|
15274
|
+
if (this.context?.emitProviderEvent) {
|
|
15275
|
+
this.context.emitProviderEvent(enrichedEvent);
|
|
15276
|
+
return;
|
|
15277
|
+
}
|
|
15278
|
+
this.events.push(enrichedEvent);
|
|
15080
15279
|
}
|
|
15081
15280
|
flushEvents() {
|
|
15082
15281
|
const events = [...this.events];
|
|
@@ -15283,12 +15482,31 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15283
15482
|
);
|
|
15284
15483
|
}
|
|
15285
15484
|
}
|
|
15485
|
+
mergeRuntimeChatMessages(parsedMessages) {
|
|
15486
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
15487
|
+
}
|
|
15286
15488
|
mergeConversationMessages(parsedMessages) {
|
|
15287
15489
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15490
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
15491
|
+
message,
|
|
15492
|
+
index,
|
|
15493
|
+
source: "parsed"
|
|
15494
|
+
}));
|
|
15495
|
+
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
15496
|
+
message: entry.message,
|
|
15497
|
+
index: parsedMessages.length + index,
|
|
15498
|
+
source: "runtime"
|
|
15499
|
+
}));
|
|
15500
|
+
const getTime = (message) => {
|
|
15501
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
15502
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
15503
|
+
};
|
|
15504
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
15505
|
+
const aTime = getTime(a.message);
|
|
15506
|
+
const bTime = getTime(b.message);
|
|
15507
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
15508
|
+
if (aTime && !bTime && a.source === "runtime" && b.source === "parsed") return -1;
|
|
15509
|
+
if (!aTime && bTime && a.source === "parsed" && b.source === "runtime") return 1;
|
|
15292
15510
|
return a.index - b.index;
|
|
15293
15511
|
}).map((entry) => entry.message));
|
|
15294
15512
|
}
|
|
@@ -16617,17 +16835,17 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
16617
16835
|
// src/commands/cli-manager.ts
|
|
16618
16836
|
function isExplicitCommand(command) {
|
|
16619
16837
|
const trimmed = command.trim();
|
|
16620
|
-
return
|
|
16838
|
+
return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
16621
16839
|
}
|
|
16622
16840
|
function expandExecutable(command) {
|
|
16623
16841
|
const trimmed = command.trim();
|
|
16624
|
-
return trimmed.startsWith("~") ?
|
|
16842
|
+
return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
16625
16843
|
}
|
|
16626
16844
|
function commandExists(command) {
|
|
16627
16845
|
const trimmed = command.trim();
|
|
16628
16846
|
if (!trimmed) return false;
|
|
16629
16847
|
if (isExplicitCommand(trimmed)) {
|
|
16630
|
-
return
|
|
16848
|
+
return existsSync12(expandExecutable(trimmed));
|
|
16631
16849
|
}
|
|
16632
16850
|
try {
|
|
16633
16851
|
execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -16645,6 +16863,35 @@ function colorize(color, text) {
|
|
|
16645
16863
|
const fn = chalkApi?.[color];
|
|
16646
16864
|
return typeof fn === "function" ? fn(text) : text;
|
|
16647
16865
|
}
|
|
16866
|
+
var COORDINATOR_DELEGATED_ENV_UNSETS = {
|
|
16867
|
+
ADHDEV_INLINE_MESH: "",
|
|
16868
|
+
ADHDEV_MCP_TRANSPORT: "",
|
|
16869
|
+
ADHDEV_MESH_ID: "",
|
|
16870
|
+
HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
|
|
16871
|
+
};
|
|
16872
|
+
function hasCliArg(args, flag) {
|
|
16873
|
+
return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
16874
|
+
}
|
|
16875
|
+
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
16876
|
+
const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
16877
|
+
mkdirSync7(baseDir, { recursive: true });
|
|
16878
|
+
const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
16879
|
+
const filePath = path17.join(baseDir, `${workspaceHash}.json`);
|
|
16880
|
+
writeFileSync7(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
16881
|
+
return filePath;
|
|
16882
|
+
}
|
|
16883
|
+
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
16884
|
+
const cliType = String(input.cliType || "").trim();
|
|
16885
|
+
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
16886
|
+
const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
|
|
16887
|
+
if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
|
|
16888
|
+
cliArgs.unshift("--ignore-user-config");
|
|
16889
|
+
}
|
|
16890
|
+
if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
|
|
16891
|
+
cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
16892
|
+
}
|
|
16893
|
+
return { cliArgs, env };
|
|
16894
|
+
}
|
|
16648
16895
|
function isUuid(value) {
|
|
16649
16896
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
16650
16897
|
}
|
|
@@ -16815,7 +17062,7 @@ var DaemonCliManager = class {
|
|
|
16815
17062
|
attachExisting
|
|
16816
17063
|
}) || void 0;
|
|
16817
17064
|
}
|
|
16818
|
-
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
|
|
17065
|
+
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
|
|
16819
17066
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16820
17067
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
16821
17068
|
if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
|
|
@@ -16829,7 +17076,7 @@ var DaemonCliManager = class {
|
|
|
16829
17076
|
providerSessionId,
|
|
16830
17077
|
attachExisting
|
|
16831
17078
|
);
|
|
16832
|
-
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
|
|
17079
|
+
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
16833
17080
|
}
|
|
16834
17081
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
16835
17082
|
}
|
|
@@ -16902,7 +17149,7 @@ var DaemonCliManager = class {
|
|
|
16902
17149
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
16903
17150
|
const trimmed = (workingDir || "").trim();
|
|
16904
17151
|
if (!trimmed) throw new Error("working directory required");
|
|
16905
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17152
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
|
|
16906
17153
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16907
17154
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
16908
17155
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -17032,6 +17279,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17032
17279
|
{
|
|
17033
17280
|
providerSessionId: sessionBinding.providerSessionId,
|
|
17034
17281
|
launchMode: sessionBinding.launchMode,
|
|
17282
|
+
extraEnv: options?.extraEnv,
|
|
17035
17283
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
17036
17284
|
this.persistRecentActivity({
|
|
17037
17285
|
kind: "cli",
|
|
@@ -17052,7 +17300,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17052
17300
|
resolvedCliArgs,
|
|
17053
17301
|
key,
|
|
17054
17302
|
sessionBinding.providerSessionId,
|
|
17055
|
-
false
|
|
17303
|
+
false,
|
|
17304
|
+
options?.extraEnv
|
|
17056
17305
|
);
|
|
17057
17306
|
try {
|
|
17058
17307
|
await adapter.spawn();
|
|
@@ -17276,12 +17525,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17276
17525
|
const dir = resolved.path;
|
|
17277
17526
|
const launchSource = resolved.source;
|
|
17278
17527
|
if (!cliType) throw new Error("cliType required");
|
|
17528
|
+
const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
|
|
17529
|
+
const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
|
|
17530
|
+
cliType,
|
|
17531
|
+
workspace: dir,
|
|
17532
|
+
cliArgs: args?.cliArgs,
|
|
17533
|
+
env: args?.env
|
|
17534
|
+
}) : null;
|
|
17279
17535
|
const started = await this.startSession(
|
|
17280
17536
|
cliType,
|
|
17281
17537
|
dir,
|
|
17282
|
-
args?.cliArgs,
|
|
17538
|
+
delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
|
|
17283
17539
|
args?.initialModel,
|
|
17284
|
-
{
|
|
17540
|
+
{
|
|
17541
|
+
resumeSessionId: args?.resumeSessionId,
|
|
17542
|
+
settingsOverride,
|
|
17543
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
17544
|
+
}
|
|
17285
17545
|
);
|
|
17286
17546
|
return {
|
|
17287
17547
|
success: true,
|
|
@@ -17403,11 +17663,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17403
17663
|
import { execSync as execSync4, spawn as spawn2 } from "child_process";
|
|
17404
17664
|
import * as net from "net";
|
|
17405
17665
|
import * as os15 from "os";
|
|
17406
|
-
import * as
|
|
17666
|
+
import * as path19 from "path";
|
|
17407
17667
|
|
|
17408
17668
|
// src/providers/provider-loader.ts
|
|
17409
17669
|
import * as fs7 from "fs";
|
|
17410
|
-
import * as
|
|
17670
|
+
import * as path18 from "path";
|
|
17411
17671
|
import * as os14 from "os";
|
|
17412
17672
|
import * as chokidar from "chokidar";
|
|
17413
17673
|
init_logger();
|
|
@@ -17731,7 +17991,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17731
17991
|
try {
|
|
17732
17992
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
17733
17993
|
return ["ide", "extension", "cli", "acp"].some(
|
|
17734
|
-
(category) => fs7.existsSync(
|
|
17994
|
+
(category) => fs7.existsSync(path18.join(candidate, category))
|
|
17735
17995
|
);
|
|
17736
17996
|
} catch {
|
|
17737
17997
|
return false;
|
|
@@ -17739,20 +17999,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17739
17999
|
}
|
|
17740
18000
|
static hasProviderRootMarker(candidate) {
|
|
17741
18001
|
try {
|
|
17742
|
-
return fs7.existsSync(
|
|
18002
|
+
return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
17743
18003
|
} catch {
|
|
17744
18004
|
return false;
|
|
17745
18005
|
}
|
|
17746
18006
|
}
|
|
17747
18007
|
detectDefaultUserDir() {
|
|
17748
|
-
const fallback =
|
|
18008
|
+
const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17749
18009
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17750
18010
|
const visited = /* @__PURE__ */ new Set();
|
|
17751
18011
|
for (const start of this.probeStarts) {
|
|
17752
|
-
let current =
|
|
18012
|
+
let current = path18.resolve(start);
|
|
17753
18013
|
while (!visited.has(current)) {
|
|
17754
18014
|
visited.add(current);
|
|
17755
|
-
const siblingCandidate =
|
|
18015
|
+
const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17756
18016
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17757
18017
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17758
18018
|
if (envOptIn || hasMarker) {
|
|
@@ -17774,7 +18034,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17774
18034
|
return { path: siblingCandidate, source };
|
|
17775
18035
|
}
|
|
17776
18036
|
}
|
|
17777
|
-
const parent =
|
|
18037
|
+
const parent = path18.dirname(current);
|
|
17778
18038
|
if (parent === current) break;
|
|
17779
18039
|
current = parent;
|
|
17780
18040
|
}
|
|
@@ -17784,11 +18044,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17784
18044
|
constructor(options) {
|
|
17785
18045
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17786
18046
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17787
|
-
this.defaultProvidersDir =
|
|
18047
|
+
this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17788
18048
|
const detected = this.detectDefaultUserDir();
|
|
17789
18049
|
this.userDir = detected.path;
|
|
17790
18050
|
this.userDirSource = detected.source;
|
|
17791
|
-
this.upstreamDir =
|
|
18051
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17792
18052
|
this.disableUpstream = false;
|
|
17793
18053
|
this.applySourceConfig({
|
|
17794
18054
|
userDir: options?.userDir,
|
|
@@ -17847,7 +18107,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17847
18107
|
this.userDir = detected.path;
|
|
17848
18108
|
this.userDirSource = detected.source;
|
|
17849
18109
|
}
|
|
17850
|
-
this.upstreamDir =
|
|
18110
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17851
18111
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
17852
18112
|
if (this.explicitProviderDir) {
|
|
17853
18113
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -17861,7 +18121,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17861
18121
|
* Canonical provider directory shape for a given root.
|
|
17862
18122
|
*/
|
|
17863
18123
|
getProviderDir(root, category, type) {
|
|
17864
|
-
return
|
|
18124
|
+
return path18.join(root, category, type);
|
|
17865
18125
|
}
|
|
17866
18126
|
/**
|
|
17867
18127
|
* Canonical user override directory for a provider.
|
|
@@ -17888,7 +18148,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17888
18148
|
resolveProviderFile(type, ...segments) {
|
|
17889
18149
|
const dir = this.findProviderDirInternal(type);
|
|
17890
18150
|
if (!dir) return null;
|
|
17891
|
-
return
|
|
18151
|
+
return path18.join(dir, ...segments);
|
|
17892
18152
|
}
|
|
17893
18153
|
/**
|
|
17894
18154
|
* Load all providers (3-tier priority)
|
|
@@ -17927,7 +18187,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17927
18187
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
17928
18188
|
try {
|
|
17929
18189
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
17930
|
-
(d) => fs7.statSync(
|
|
18190
|
+
(d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
|
|
17931
18191
|
);
|
|
17932
18192
|
} catch {
|
|
17933
18193
|
return false;
|
|
@@ -18424,8 +18684,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18424
18684
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
18425
18685
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
18426
18686
|
if (providerDir) {
|
|
18427
|
-
const fullDir =
|
|
18428
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18687
|
+
const fullDir = path18.join(providerDir, entry.scriptDir);
|
|
18688
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18429
18689
|
}
|
|
18430
18690
|
matched = true;
|
|
18431
18691
|
}
|
|
@@ -18440,8 +18700,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18440
18700
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18441
18701
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
18442
18702
|
if (providerDir) {
|
|
18443
|
-
const fullDir =
|
|
18444
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18703
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18704
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18445
18705
|
}
|
|
18446
18706
|
}
|
|
18447
18707
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -18458,8 +18718,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18458
18718
|
resolved._resolvedScriptDir = dirOverride;
|
|
18459
18719
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
18460
18720
|
if (providerDir) {
|
|
18461
|
-
const fullDir =
|
|
18462
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18721
|
+
const fullDir = path18.join(providerDir, dirOverride);
|
|
18722
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18463
18723
|
}
|
|
18464
18724
|
}
|
|
18465
18725
|
} else if (override.scripts) {
|
|
@@ -18475,8 +18735,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18475
18735
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18476
18736
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
18477
18737
|
if (providerDir) {
|
|
18478
|
-
const fullDir =
|
|
18479
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18738
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18739
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18480
18740
|
}
|
|
18481
18741
|
}
|
|
18482
18742
|
}
|
|
@@ -18508,14 +18768,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18508
18768
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
18509
18769
|
return null;
|
|
18510
18770
|
}
|
|
18511
|
-
const dir =
|
|
18771
|
+
const dir = path18.join(providerDir, scriptDir);
|
|
18512
18772
|
if (!fs7.existsSync(dir)) {
|
|
18513
18773
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
18514
18774
|
return null;
|
|
18515
18775
|
}
|
|
18516
18776
|
const cached = this.scriptsCache.get(dir);
|
|
18517
18777
|
if (cached) return cached;
|
|
18518
|
-
const scriptsJs =
|
|
18778
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
18519
18779
|
if (fs7.existsSync(scriptsJs)) {
|
|
18520
18780
|
try {
|
|
18521
18781
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -18557,7 +18817,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18557
18817
|
return;
|
|
18558
18818
|
}
|
|
18559
18819
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
18560
|
-
this.log(`File changed: ${
|
|
18820
|
+
this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
|
|
18561
18821
|
this.reload();
|
|
18562
18822
|
}
|
|
18563
18823
|
};
|
|
@@ -18612,7 +18872,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18612
18872
|
}
|
|
18613
18873
|
const https = __require("https");
|
|
18614
18874
|
const { execSync: execSync7 } = __require("child_process");
|
|
18615
|
-
const metaPath =
|
|
18875
|
+
const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
18616
18876
|
let prevEtag = "";
|
|
18617
18877
|
let prevTimestamp = 0;
|
|
18618
18878
|
try {
|
|
@@ -18672,17 +18932,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18672
18932
|
return { updated: false };
|
|
18673
18933
|
}
|
|
18674
18934
|
this.log("Downloading latest providers from GitHub...");
|
|
18675
|
-
const tmpTar =
|
|
18676
|
-
const tmpExtract =
|
|
18935
|
+
const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
18936
|
+
const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
18677
18937
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
18678
18938
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
18679
18939
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
18680
18940
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
18681
18941
|
const rootDir = extracted.find(
|
|
18682
|
-
(d) => fs7.statSync(
|
|
18942
|
+
(d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
18683
18943
|
);
|
|
18684
18944
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
18685
|
-
const sourceDir =
|
|
18945
|
+
const sourceDir = path18.join(tmpExtract, rootDir);
|
|
18686
18946
|
const backupDir = this.upstreamDir + ".bak";
|
|
18687
18947
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
18688
18948
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -18757,8 +19017,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18757
19017
|
copyDirRecursive(src, dest) {
|
|
18758
19018
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18759
19019
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18760
|
-
const srcPath =
|
|
18761
|
-
const destPath =
|
|
19020
|
+
const srcPath = path18.join(src, entry.name);
|
|
19021
|
+
const destPath = path18.join(dest, entry.name);
|
|
18762
19022
|
if (entry.isDirectory()) {
|
|
18763
19023
|
this.copyDirRecursive(srcPath, destPath);
|
|
18764
19024
|
} else {
|
|
@@ -18769,7 +19029,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18769
19029
|
/** .meta.json save */
|
|
18770
19030
|
writeMeta(metaPath, etag, timestamp) {
|
|
18771
19031
|
try {
|
|
18772
|
-
fs7.mkdirSync(
|
|
19032
|
+
fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
|
|
18773
19033
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18774
19034
|
etag,
|
|
18775
19035
|
timestamp,
|
|
@@ -18786,7 +19046,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18786
19046
|
const scan = (d) => {
|
|
18787
19047
|
try {
|
|
18788
19048
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18789
|
-
if (entry.isDirectory()) scan(
|
|
19049
|
+
if (entry.isDirectory()) scan(path18.join(d, entry.name));
|
|
18790
19050
|
else if (entry.name === "provider.json") count++;
|
|
18791
19051
|
}
|
|
18792
19052
|
} catch {
|
|
@@ -19014,17 +19274,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19014
19274
|
for (const root of searchRoots) {
|
|
19015
19275
|
if (!fs7.existsSync(root)) continue;
|
|
19016
19276
|
const candidate = this.getProviderDir(root, cat, type);
|
|
19017
|
-
if (fs7.existsSync(
|
|
19018
|
-
const catDir =
|
|
19277
|
+
if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
|
|
19278
|
+
const catDir = path18.join(root, cat);
|
|
19019
19279
|
if (fs7.existsSync(catDir)) {
|
|
19020
19280
|
try {
|
|
19021
19281
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
19022
19282
|
if (!entry.isDirectory()) continue;
|
|
19023
|
-
const jsonPath =
|
|
19283
|
+
const jsonPath = path18.join(catDir, entry.name, "provider.json");
|
|
19024
19284
|
if (fs7.existsSync(jsonPath)) {
|
|
19025
19285
|
try {
|
|
19026
19286
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
19027
|
-
if (data.type === type) return
|
|
19287
|
+
if (data.type === type) return path18.join(catDir, entry.name);
|
|
19028
19288
|
} catch {
|
|
19029
19289
|
}
|
|
19030
19290
|
}
|
|
@@ -19041,7 +19301,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19041
19301
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
19042
19302
|
*/
|
|
19043
19303
|
buildScriptWrappersFromDir(dir) {
|
|
19044
|
-
const scriptsJs =
|
|
19304
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
19045
19305
|
if (fs7.existsSync(scriptsJs)) {
|
|
19046
19306
|
try {
|
|
19047
19307
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -19055,7 +19315,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19055
19315
|
for (const file of fs7.readdirSync(dir)) {
|
|
19056
19316
|
if (!file.endsWith(".js")) continue;
|
|
19057
19317
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
19058
|
-
const filePath =
|
|
19318
|
+
const filePath = path18.join(dir, file);
|
|
19059
19319
|
result[scriptName] = (...args) => {
|
|
19060
19320
|
try {
|
|
19061
19321
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -19115,7 +19375,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19115
19375
|
}
|
|
19116
19376
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
19117
19377
|
if (hasJson) {
|
|
19118
|
-
const jsonPath =
|
|
19378
|
+
const jsonPath = path18.join(d, "provider.json");
|
|
19119
19379
|
try {
|
|
19120
19380
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
19121
19381
|
const mod = JSON.parse(raw);
|
|
@@ -19136,7 +19396,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19136
19396
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
19137
19397
|
} else {
|
|
19138
19398
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
19139
|
-
const scriptsPath =
|
|
19399
|
+
const scriptsPath = path18.join(d, "scripts.js");
|
|
19140
19400
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
19141
19401
|
try {
|
|
19142
19402
|
delete __require.cache[__require.resolve(scriptsPath)];
|
|
@@ -19162,7 +19422,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19162
19422
|
if (!entry.isDirectory()) continue;
|
|
19163
19423
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
19164
19424
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
19165
|
-
scan(
|
|
19425
|
+
scan(path18.join(d, entry.name));
|
|
19166
19426
|
}
|
|
19167
19427
|
}
|
|
19168
19428
|
};
|
|
@@ -19487,8 +19747,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
19487
19747
|
const appNameMap = getMacAppIdentifiers();
|
|
19488
19748
|
const appName = appNameMap[ideId];
|
|
19489
19749
|
if (appName) {
|
|
19490
|
-
const storagePath =
|
|
19491
|
-
process.env.APPDATA ||
|
|
19750
|
+
const storagePath = path19.join(
|
|
19751
|
+
process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
|
|
19492
19752
|
appName,
|
|
19493
19753
|
"storage.json"
|
|
19494
19754
|
);
|
|
@@ -19677,9 +19937,9 @@ init_logger();
|
|
|
19677
19937
|
|
|
19678
19938
|
// src/logging/command-log.ts
|
|
19679
19939
|
import * as fs8 from "fs";
|
|
19680
|
-
import * as
|
|
19940
|
+
import * as path20 from "path";
|
|
19681
19941
|
import * as os16 from "os";
|
|
19682
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
19942
|
+
var LOG_DIR2 = process.platform === "win32" ? path20.join(process.env.LOCALAPPDATA || process.env.APPDATA || path20.join(os16.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path20.join(os16.homedir(), "Library", "Logs", "adhdev") : path20.join(os16.homedir(), ".local", "share", "adhdev", "logs");
|
|
19683
19943
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
19684
19944
|
var MAX_DAYS = 7;
|
|
19685
19945
|
try {
|
|
@@ -19717,13 +19977,13 @@ function getDateStr2() {
|
|
|
19717
19977
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19718
19978
|
}
|
|
19719
19979
|
var currentDate2 = getDateStr2();
|
|
19720
|
-
var currentFile =
|
|
19980
|
+
var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19721
19981
|
var writeCount2 = 0;
|
|
19722
19982
|
function checkRotation() {
|
|
19723
19983
|
const today = getDateStr2();
|
|
19724
19984
|
if (today !== currentDate2) {
|
|
19725
19985
|
currentDate2 = today;
|
|
19726
|
-
currentFile =
|
|
19986
|
+
currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19727
19987
|
cleanOldFiles();
|
|
19728
19988
|
}
|
|
19729
19989
|
}
|
|
@@ -19737,7 +19997,7 @@ function cleanOldFiles() {
|
|
|
19737
19997
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
19738
19998
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
19739
19999
|
try {
|
|
19740
|
-
fs8.unlinkSync(
|
|
20000
|
+
fs8.unlinkSync(path20.join(LOG_DIR2, file));
|
|
19741
20001
|
} catch {
|
|
19742
20002
|
}
|
|
19743
20003
|
}
|
|
@@ -19821,13 +20081,65 @@ cleanOldFiles();
|
|
|
19821
20081
|
|
|
19822
20082
|
// src/commands/router.ts
|
|
19823
20083
|
init_logger();
|
|
20084
|
+
import * as yaml from "js-yaml";
|
|
19824
20085
|
|
|
19825
20086
|
// src/commands/mesh-coordinator.ts
|
|
19826
|
-
import {
|
|
20087
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
20088
|
+
import { existsSync as existsSync15, readdirSync as readdirSync6, realpathSync as realpathSync2 } from "fs";
|
|
19827
20089
|
import { createRequire as createRequire2 } from "module";
|
|
19828
|
-
import
|
|
20090
|
+
import * as os17 from "os";
|
|
20091
|
+
import { dirname as dirname4, isAbsolute as isAbsolute10, join as join18, resolve as resolve13 } from "path";
|
|
19829
20092
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
19830
20093
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20094
|
+
var HERMES_CLI_TYPE = "hermes-cli";
|
|
20095
|
+
var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
|
|
20096
|
+
function isHermesProvider(provider, cliType) {
|
|
20097
|
+
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
20098
|
+
return type === HERMES_CLI_TYPE;
|
|
20099
|
+
}
|
|
20100
|
+
function resolveHermesMeshCoordinatorSetup(options) {
|
|
20101
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
20102
|
+
meshId: options.meshId,
|
|
20103
|
+
nodeExecutable: options.nodeExecutable,
|
|
20104
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath
|
|
20105
|
+
});
|
|
20106
|
+
if (!mcpServer) {
|
|
20107
|
+
return {
|
|
20108
|
+
kind: "unsupported",
|
|
20109
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20110
|
+
};
|
|
20111
|
+
}
|
|
20112
|
+
const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
|
|
20113
|
+
if (!configPath.trim()) {
|
|
20114
|
+
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20115
|
+
}
|
|
20116
|
+
return {
|
|
20117
|
+
kind: "auto_import",
|
|
20118
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20119
|
+
configPath,
|
|
20120
|
+
configFormat: "hermes_config_yaml",
|
|
20121
|
+
mcpServer
|
|
20122
|
+
};
|
|
20123
|
+
}
|
|
20124
|
+
function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
|
|
20125
|
+
return {
|
|
20126
|
+
kind: "manual",
|
|
20127
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20128
|
+
configFormat: "hermes_config_yaml",
|
|
20129
|
+
configPathCommand: HERMES_MCP_CONFIG_PATH,
|
|
20130
|
+
requiresRestart: true,
|
|
20131
|
+
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.",
|
|
20132
|
+
template: renderMeshCoordinatorTemplate(
|
|
20133
|
+
"mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
|
|
20134
|
+
{
|
|
20135
|
+
meshId,
|
|
20136
|
+
workspace,
|
|
20137
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20138
|
+
adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
|
|
20139
|
+
}
|
|
20140
|
+
)
|
|
20141
|
+
};
|
|
20142
|
+
}
|
|
19831
20143
|
function resolveMeshCoordinatorSetup(options) {
|
|
19832
20144
|
const { provider, meshId, workspace } = options;
|
|
19833
20145
|
const config = provider?.meshCoordinator;
|
|
@@ -19837,6 +20149,9 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19837
20149
|
reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
|
|
19838
20150
|
};
|
|
19839
20151
|
}
|
|
20152
|
+
if (isHermesProvider(provider, options.cliType)) {
|
|
20153
|
+
return resolveHermesMeshCoordinatorSetup(options);
|
|
20154
|
+
}
|
|
19840
20155
|
const mcpConfig = config.mcpConfig;
|
|
19841
20156
|
if (!mcpConfig || mcpConfig.mode === "none") {
|
|
19842
20157
|
return {
|
|
@@ -19846,8 +20161,8 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19846
20161
|
}
|
|
19847
20162
|
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
|
|
19848
20163
|
if (mcpConfig.mode === "auto_import") {
|
|
19849
|
-
const
|
|
19850
|
-
if (!
|
|
20164
|
+
const path27 = mcpConfig.path?.trim();
|
|
20165
|
+
if (!path27) {
|
|
19851
20166
|
return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
|
|
19852
20167
|
}
|
|
19853
20168
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
@@ -19858,13 +20173,13 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19858
20173
|
if (!mcpServer) {
|
|
19859
20174
|
return {
|
|
19860
20175
|
kind: "unsupported",
|
|
19861
|
-
reason: "Could not resolve the ADHDev MCP server entrypoint
|
|
20176
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
19862
20177
|
};
|
|
19863
20178
|
}
|
|
19864
20179
|
return {
|
|
19865
20180
|
kind: "auto_import",
|
|
19866
20181
|
serverName,
|
|
19867
|
-
configPath:
|
|
20182
|
+
configPath: resolveMcpConfigPath(path27, workspace),
|
|
19868
20183
|
configFormat: mcpConfig.format,
|
|
19869
20184
|
mcpServer
|
|
19870
20185
|
};
|
|
@@ -19898,13 +20213,84 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19898
20213
|
function renderMeshCoordinatorTemplate(template, values) {
|
|
19899
20214
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
|
|
19900
20215
|
}
|
|
20216
|
+
function resolveMcpConfigPath(configPath, workspace) {
|
|
20217
|
+
const trimmed = configPath.trim();
|
|
20218
|
+
if (trimmed === "~") return os17.homedir();
|
|
20219
|
+
if (trimmed.startsWith("~/")) return join18(os17.homedir(), trimmed.slice(2));
|
|
20220
|
+
if (isAbsolute10(trimmed)) return trimmed;
|
|
20221
|
+
return join18(workspace, trimmed);
|
|
20222
|
+
}
|
|
19901
20223
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
19902
20224
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
19903
20225
|
if (!entryPath) return null;
|
|
20226
|
+
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
|
|
20227
|
+
if (!nodeExecutable) return null;
|
|
19904
20228
|
return {
|
|
19905
|
-
command:
|
|
19906
|
-
args: [entryPath, "--repo-mesh", options.meshId]
|
|
20229
|
+
command: nodeExecutable,
|
|
20230
|
+
args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
|
|
20231
|
+
};
|
|
20232
|
+
}
|
|
20233
|
+
function resolveMcpNodeExecutable(explicitExecutable) {
|
|
20234
|
+
const explicit = explicitExecutable?.trim();
|
|
20235
|
+
if (explicit) return explicit;
|
|
20236
|
+
const candidates = [];
|
|
20237
|
+
const addCandidate = (candidate) => {
|
|
20238
|
+
const trimmed = candidate?.trim();
|
|
20239
|
+
if (!trimmed) return;
|
|
20240
|
+
const normalized = normalizeExistingPath(trimmed) || trimmed;
|
|
20241
|
+
if (!candidates.includes(normalized)) candidates.push(normalized);
|
|
19907
20242
|
};
|
|
20243
|
+
addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
|
|
20244
|
+
addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
|
|
20245
|
+
addCandidate(process.env.npm_node_execpath);
|
|
20246
|
+
addNodeCandidatesFromPath(process.env.PATH, addCandidate);
|
|
20247
|
+
addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
|
|
20248
|
+
addCandidate("/opt/homebrew/bin/node");
|
|
20249
|
+
addCandidate("/usr/local/bin/node");
|
|
20250
|
+
addCandidate("/usr/bin/node");
|
|
20251
|
+
addCandidate(process.execPath);
|
|
20252
|
+
for (const candidate of candidates) {
|
|
20253
|
+
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
|
|
20254
|
+
}
|
|
20255
|
+
return null;
|
|
20256
|
+
}
|
|
20257
|
+
function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
20258
|
+
for (const entry of (pathValue || "").split(":")) {
|
|
20259
|
+
const dir = entry.trim();
|
|
20260
|
+
if (!dir) continue;
|
|
20261
|
+
addCandidate(join18(dir, "node"));
|
|
20262
|
+
}
|
|
20263
|
+
}
|
|
20264
|
+
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
20265
|
+
const versionsDir = join18(homeDir, ".nvm", "versions", "node");
|
|
20266
|
+
try {
|
|
20267
|
+
const versionDirs = readdirSync6(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
20268
|
+
for (const versionDir of versionDirs) {
|
|
20269
|
+
addCandidate(join18(versionsDir, versionDir, "bin", "node"));
|
|
20270
|
+
}
|
|
20271
|
+
} catch {
|
|
20272
|
+
}
|
|
20273
|
+
}
|
|
20274
|
+
function compareNodeVersionNamesDescending(a, b) {
|
|
20275
|
+
const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
20276
|
+
const left = parse(a);
|
|
20277
|
+
const right = parse(b);
|
|
20278
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
20279
|
+
const diff = (right[i] || 0) - (left[i] || 0);
|
|
20280
|
+
if (diff !== 0) return diff;
|
|
20281
|
+
}
|
|
20282
|
+
return b.localeCompare(a);
|
|
20283
|
+
}
|
|
20284
|
+
function nodeRuntimeSupportsWebSocket(nodeExecutable) {
|
|
20285
|
+
try {
|
|
20286
|
+
execFileSync2(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
|
|
20287
|
+
stdio: "ignore",
|
|
20288
|
+
timeout: 3e3
|
|
20289
|
+
});
|
|
20290
|
+
return true;
|
|
20291
|
+
} catch {
|
|
20292
|
+
return false;
|
|
20293
|
+
}
|
|
19908
20294
|
}
|
|
19909
20295
|
function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
19910
20296
|
const explicit = explicitPath?.trim();
|
|
@@ -19918,7 +20304,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19918
20304
|
const addPackagedCandidates = (baseFile) => {
|
|
19919
20305
|
if (!baseFile) return;
|
|
19920
20306
|
const realBase = normalizeExistingPath(baseFile) || baseFile;
|
|
19921
|
-
const dir =
|
|
20307
|
+
const dir = dirname4(realBase);
|
|
19922
20308
|
addCandidate(resolve13(dir, "../vendor/mcp-server/index.js"));
|
|
19923
20309
|
addCandidate(resolve13(dir, "../../vendor/mcp-server/index.js"));
|
|
19924
20310
|
addCandidate(resolve13(dir, "../../../vendor/mcp-server/index.js"));
|
|
@@ -19931,7 +20317,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19931
20317
|
if (normalized) return normalized;
|
|
19932
20318
|
}
|
|
19933
20319
|
try {
|
|
19934
|
-
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] :
|
|
20320
|
+
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join18(process.cwd(), "adhdev-daemon.js");
|
|
19935
20321
|
const req = createRequire2(requireBase);
|
|
19936
20322
|
const resolvedModule = req.resolve("@adhdev/mcp-server");
|
|
19937
20323
|
return normalizeExistingPath(resolvedModule) || resolvedModule;
|
|
@@ -19941,7 +20327,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19941
20327
|
}
|
|
19942
20328
|
function normalizeExistingPath(filePath) {
|
|
19943
20329
|
try {
|
|
19944
|
-
if (!
|
|
20330
|
+
if (!existsSync15(filePath)) return null;
|
|
19945
20331
|
return realpathSync2.native(filePath);
|
|
19946
20332
|
} catch {
|
|
19947
20333
|
return null;
|
|
@@ -19950,7 +20336,7 @@ function normalizeExistingPath(filePath) {
|
|
|
19950
20336
|
|
|
19951
20337
|
// src/status/snapshot.ts
|
|
19952
20338
|
init_config();
|
|
19953
|
-
import * as
|
|
20339
|
+
import * as os18 from "os";
|
|
19954
20340
|
init_terminal_screen();
|
|
19955
20341
|
init_logger();
|
|
19956
20342
|
var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
|
|
@@ -20005,8 +20391,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20005
20391
|
}
|
|
20006
20392
|
function buildMachineInfo(profile = "full") {
|
|
20007
20393
|
const base = {
|
|
20008
|
-
hostname:
|
|
20009
|
-
platform:
|
|
20394
|
+
hostname: os18.hostname(),
|
|
20395
|
+
platform: os18.platform()
|
|
20010
20396
|
};
|
|
20011
20397
|
if (profile === "live") {
|
|
20012
20398
|
return base;
|
|
@@ -20015,23 +20401,23 @@ function buildMachineInfo(profile = "full") {
|
|
|
20015
20401
|
const memSnap2 = getHostMemorySnapshot();
|
|
20016
20402
|
return {
|
|
20017
20403
|
...base,
|
|
20018
|
-
arch:
|
|
20019
|
-
cpus:
|
|
20404
|
+
arch: os18.arch(),
|
|
20405
|
+
cpus: os18.cpus().length,
|
|
20020
20406
|
totalMem: memSnap2.totalMem,
|
|
20021
|
-
release:
|
|
20407
|
+
release: os18.release()
|
|
20022
20408
|
};
|
|
20023
20409
|
}
|
|
20024
20410
|
const memSnap = getHostMemorySnapshot();
|
|
20025
20411
|
return {
|
|
20026
20412
|
...base,
|
|
20027
|
-
arch:
|
|
20028
|
-
cpus:
|
|
20413
|
+
arch: os18.arch(),
|
|
20414
|
+
cpus: os18.cpus().length,
|
|
20029
20415
|
totalMem: memSnap.totalMem,
|
|
20030
20416
|
freeMem: memSnap.freeMem,
|
|
20031
20417
|
availableMem: memSnap.availableMem,
|
|
20032
|
-
loadavg:
|
|
20033
|
-
uptime:
|
|
20034
|
-
release:
|
|
20418
|
+
loadavg: os18.loadavg(),
|
|
20419
|
+
uptime: os18.uptime(),
|
|
20420
|
+
release: os18.release()
|
|
20035
20421
|
};
|
|
20036
20422
|
}
|
|
20037
20423
|
function parseMessageTime(value) {
|
|
@@ -20262,17 +20648,17 @@ function buildStatusSnapshot(options) {
|
|
|
20262
20648
|
}
|
|
20263
20649
|
|
|
20264
20650
|
// src/commands/upgrade-helper.ts
|
|
20265
|
-
import { execFileSync as
|
|
20651
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
20266
20652
|
import { spawn as spawn3 } from "child_process";
|
|
20267
20653
|
import * as fs9 from "fs";
|
|
20268
|
-
import * as
|
|
20269
|
-
import * as
|
|
20654
|
+
import * as os19 from "os";
|
|
20655
|
+
import * as path21 from "path";
|
|
20270
20656
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
20271
20657
|
function getUpgradeLogPath() {
|
|
20272
|
-
const home =
|
|
20273
|
-
const dir =
|
|
20658
|
+
const home = os19.homedir();
|
|
20659
|
+
const dir = path21.join(home, ".adhdev");
|
|
20274
20660
|
fs9.mkdirSync(dir, { recursive: true });
|
|
20275
|
-
return
|
|
20661
|
+
return path21.join(dir, "daemon-upgrade.log");
|
|
20276
20662
|
}
|
|
20277
20663
|
function appendUpgradeLog(message) {
|
|
20278
20664
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -20283,14 +20669,14 @@ function appendUpgradeLog(message) {
|
|
|
20283
20669
|
}
|
|
20284
20670
|
}
|
|
20285
20671
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
20286
|
-
const binDir =
|
|
20672
|
+
const binDir = path21.dirname(nodeExecutable);
|
|
20287
20673
|
if (platform10 === "win32") {
|
|
20288
|
-
const npmCliPath =
|
|
20674
|
+
const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
20289
20675
|
if (fs9.existsSync(npmCliPath)) {
|
|
20290
20676
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20291
20677
|
}
|
|
20292
20678
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
20293
|
-
const candidatePath =
|
|
20679
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20294
20680
|
if (fs9.existsSync(candidatePath)) {
|
|
20295
20681
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20296
20682
|
}
|
|
@@ -20298,7 +20684,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
20298
20684
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20299
20685
|
}
|
|
20300
20686
|
for (const candidate of ["npm"]) {
|
|
20301
|
-
const candidatePath =
|
|
20687
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20302
20688
|
if (fs9.existsSync(candidatePath)) {
|
|
20303
20689
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20304
20690
|
}
|
|
@@ -20315,13 +20701,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20315
20701
|
let currentDir = resolvedPath;
|
|
20316
20702
|
try {
|
|
20317
20703
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
20318
|
-
currentDir =
|
|
20704
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20319
20705
|
}
|
|
20320
20706
|
} catch {
|
|
20321
|
-
currentDir =
|
|
20707
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20322
20708
|
}
|
|
20323
20709
|
while (true) {
|
|
20324
|
-
const packageJsonPath =
|
|
20710
|
+
const packageJsonPath = path21.join(currentDir, "package.json");
|
|
20325
20711
|
try {
|
|
20326
20712
|
if (fs9.existsSync(packageJsonPath)) {
|
|
20327
20713
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -20332,7 +20718,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20332
20718
|
}
|
|
20333
20719
|
} catch {
|
|
20334
20720
|
}
|
|
20335
|
-
const parentDir =
|
|
20721
|
+
const parentDir = path21.dirname(currentDir);
|
|
20336
20722
|
if (parentDir === currentDir) {
|
|
20337
20723
|
return null;
|
|
20338
20724
|
}
|
|
@@ -20340,13 +20726,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20340
20726
|
}
|
|
20341
20727
|
}
|
|
20342
20728
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
20343
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
20344
|
-
if (
|
|
20729
|
+
const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
|
|
20730
|
+
if (path21.basename(nodeModulesDir) !== "node_modules") {
|
|
20345
20731
|
return null;
|
|
20346
20732
|
}
|
|
20347
|
-
const maybeLibDir =
|
|
20348
|
-
if (
|
|
20349
|
-
return
|
|
20733
|
+
const maybeLibDir = path21.dirname(nodeModulesDir);
|
|
20734
|
+
if (path21.basename(maybeLibDir) === "lib") {
|
|
20735
|
+
return path21.dirname(maybeLibDir);
|
|
20350
20736
|
}
|
|
20351
20737
|
return maybeLibDir;
|
|
20352
20738
|
}
|
|
@@ -20382,7 +20768,7 @@ function getNpmExecOptions(platform10 = process.platform) {
|
|
|
20382
20768
|
}
|
|
20383
20769
|
function execNpmCommandSync(args, options = {}, surface) {
|
|
20384
20770
|
const execOptions = surface?.execOptions || getNpmExecOptions();
|
|
20385
|
-
return
|
|
20771
|
+
return execFileSync3(
|
|
20386
20772
|
surface?.npmExecutable || "npm",
|
|
20387
20773
|
[...surface?.npmArgsPrefix || [], ...args],
|
|
20388
20774
|
{
|
|
@@ -20395,7 +20781,7 @@ function execNpmCommandSync(args, options = {}, surface) {
|
|
|
20395
20781
|
function killPid(pid) {
|
|
20396
20782
|
try {
|
|
20397
20783
|
if (process.platform === "win32") {
|
|
20398
|
-
|
|
20784
|
+
execFileSync3("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
|
|
20399
20785
|
} else {
|
|
20400
20786
|
process.kill(pid, "SIGTERM");
|
|
20401
20787
|
}
|
|
@@ -20407,7 +20793,7 @@ function killPid(pid) {
|
|
|
20407
20793
|
function getWindowsProcessCommandLine(pid) {
|
|
20408
20794
|
const pidFilter = `ProcessId=${pid}`;
|
|
20409
20795
|
try {
|
|
20410
|
-
const psOut =
|
|
20796
|
+
const psOut = execFileSync3("powershell.exe", [
|
|
20411
20797
|
"-NoProfile",
|
|
20412
20798
|
"-NonInteractive",
|
|
20413
20799
|
"-ExecutionPolicy",
|
|
@@ -20419,7 +20805,7 @@ function getWindowsProcessCommandLine(pid) {
|
|
|
20419
20805
|
} catch {
|
|
20420
20806
|
}
|
|
20421
20807
|
try {
|
|
20422
|
-
const wmicOut =
|
|
20808
|
+
const wmicOut = execFileSync3("wmic", [
|
|
20423
20809
|
"process",
|
|
20424
20810
|
"where",
|
|
20425
20811
|
pidFilter,
|
|
@@ -20435,7 +20821,7 @@ function getProcessCommandLine(pid) {
|
|
|
20435
20821
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
20436
20822
|
if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
|
|
20437
20823
|
try {
|
|
20438
|
-
const text =
|
|
20824
|
+
const text = execFileSync3("ps", ["-o", "command=", "-p", String(pid)], {
|
|
20439
20825
|
encoding: "utf8",
|
|
20440
20826
|
timeout: 3e3,
|
|
20441
20827
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -20461,7 +20847,7 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
20461
20847
|
}
|
|
20462
20848
|
}
|
|
20463
20849
|
function stopSessionHostProcesses(appName) {
|
|
20464
|
-
const pidFile =
|
|
20850
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
20465
20851
|
try {
|
|
20466
20852
|
if (fs9.existsSync(pidFile)) {
|
|
20467
20853
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -20478,7 +20864,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
20478
20864
|
}
|
|
20479
20865
|
}
|
|
20480
20866
|
function removeDaemonPidFile() {
|
|
20481
|
-
const pidFile =
|
|
20867
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
20482
20868
|
try {
|
|
20483
20869
|
fs9.unlinkSync(pidFile);
|
|
20484
20870
|
} catch {
|
|
@@ -20489,7 +20875,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20489
20875
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20490
20876
|
if (!npmRoot) return;
|
|
20491
20877
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20492
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
20878
|
+
const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
|
|
20493
20879
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
20494
20880
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
20495
20881
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -20497,25 +20883,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20497
20883
|
}
|
|
20498
20884
|
if (pkgName.startsWith("@")) {
|
|
20499
20885
|
const [scope, name] = pkgName.split("/");
|
|
20500
|
-
const scopeDir =
|
|
20886
|
+
const scopeDir = path21.join(npmRoot, scope);
|
|
20501
20887
|
if (!fs9.existsSync(scopeDir)) return;
|
|
20502
20888
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
20503
20889
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
20504
|
-
fs9.rmSync(
|
|
20505
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
20890
|
+
fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
|
|
20891
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
|
|
20506
20892
|
}
|
|
20507
20893
|
} else {
|
|
20508
20894
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
20509
20895
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
20510
|
-
fs9.rmSync(
|
|
20511
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
20896
|
+
fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
|
|
20897
|
+
appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
|
|
20512
20898
|
}
|
|
20513
20899
|
}
|
|
20514
20900
|
if (fs9.existsSync(binDir)) {
|
|
20515
20901
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
20516
20902
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
20517
|
-
fs9.rmSync(
|
|
20518
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
20903
|
+
fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
|
|
20904
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
|
|
20519
20905
|
}
|
|
20520
20906
|
}
|
|
20521
20907
|
}
|
|
@@ -20551,7 +20937,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
20551
20937
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
20552
20938
|
const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
|
|
20553
20939
|
appendUpgradeLog(`Installing ${spec}`);
|
|
20554
|
-
const installOutput =
|
|
20940
|
+
const installOutput = execFileSync3(
|
|
20555
20941
|
installCommand.command,
|
|
20556
20942
|
installCommand.args,
|
|
20557
20943
|
{
|
|
@@ -20616,6 +21002,56 @@ function normalizeReleaseChannel(value) {
|
|
|
20616
21002
|
function resolveUpgradeChannel(args) {
|
|
20617
21003
|
return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
|
|
20618
21004
|
}
|
|
21005
|
+
function readProviderPriorityFromPolicy(policy) {
|
|
21006
|
+
const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
|
|
21007
|
+
const raw = record.providerPriority;
|
|
21008
|
+
if (!Array.isArray(raw)) return [];
|
|
21009
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21010
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
21011
|
+
if (seen.has(type)) return false;
|
|
21012
|
+
seen.add(type);
|
|
21013
|
+
return true;
|
|
21014
|
+
});
|
|
21015
|
+
}
|
|
21016
|
+
async function resolveProviderTypeFromPriority(args) {
|
|
21017
|
+
if (!args.providerPriority.length) {
|
|
21018
|
+
return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
|
|
21019
|
+
}
|
|
21020
|
+
const failed = [];
|
|
21021
|
+
for (const requestedType of args.providerPriority) {
|
|
21022
|
+
const normalizedType = args.providerLoader.resolveAlias(requestedType);
|
|
21023
|
+
if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
21024
|
+
failed.push(`${requestedType}: disabled`);
|
|
21025
|
+
continue;
|
|
21026
|
+
}
|
|
21027
|
+
const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
|
|
21028
|
+
args.providerLoader.setCliDetectionResults([{
|
|
21029
|
+
id: normalizedType,
|
|
21030
|
+
installed: !!detected,
|
|
21031
|
+
path: detected?.path
|
|
21032
|
+
}], false);
|
|
21033
|
+
args.onStatusChange?.();
|
|
21034
|
+
if (detected) return { providerType: normalizedType };
|
|
21035
|
+
failed.push(`${requestedType}: not detected`);
|
|
21036
|
+
}
|
|
21037
|
+
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
21038
|
+
}
|
|
21039
|
+
function loadYamlModule() {
|
|
21040
|
+
return yaml;
|
|
21041
|
+
}
|
|
21042
|
+
function getMcpServersKey(format) {
|
|
21043
|
+
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
21044
|
+
}
|
|
21045
|
+
function parseMeshCoordinatorMcpConfig(text, format) {
|
|
21046
|
+
if (!text.trim()) return {};
|
|
21047
|
+
if (format === "claude_mcp_json") return JSON.parse(text);
|
|
21048
|
+
const parsed = loadYamlModule().load(text);
|
|
21049
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
21050
|
+
}
|
|
21051
|
+
function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
21052
|
+
if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
|
|
21053
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
21054
|
+
}
|
|
20619
21055
|
var CHAT_COMMANDS = [
|
|
20620
21056
|
"send_chat",
|
|
20621
21057
|
"new_chat",
|
|
@@ -20714,6 +21150,40 @@ var DaemonCommandRouter = class {
|
|
|
20714
21150
|
constructor(deps) {
|
|
20715
21151
|
this.deps = deps;
|
|
20716
21152
|
}
|
|
21153
|
+
getCachedInlineMesh(meshId, inlineMesh) {
|
|
21154
|
+
if (inlineMesh && typeof inlineMesh === "object") {
|
|
21155
|
+
this.inlineMeshCache.set(meshId, inlineMesh);
|
|
21156
|
+
return inlineMesh;
|
|
21157
|
+
}
|
|
21158
|
+
return this.inlineMeshCache.get(meshId);
|
|
21159
|
+
}
|
|
21160
|
+
async getMeshForCommand(meshId, inlineMesh) {
|
|
21161
|
+
try {
|
|
21162
|
+
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21163
|
+
const mesh = getMesh3(meshId);
|
|
21164
|
+
if (mesh) return { mesh, inline: false };
|
|
21165
|
+
} catch {
|
|
21166
|
+
}
|
|
21167
|
+
const cached = this.getCachedInlineMesh(meshId, inlineMesh);
|
|
21168
|
+
return cached ? { mesh: cached, inline: true } : null;
|
|
21169
|
+
}
|
|
21170
|
+
updateInlineMeshNode(meshId, mesh, node) {
|
|
21171
|
+
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
21172
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
21173
|
+
if (idx >= 0) mesh.nodes[idx] = node;
|
|
21174
|
+
else mesh.nodes.push(node);
|
|
21175
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21176
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21177
|
+
}
|
|
21178
|
+
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
21179
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
21180
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
|
|
21181
|
+
if (idx === -1) return false;
|
|
21182
|
+
mesh.nodes.splice(idx, 1);
|
|
21183
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21184
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21185
|
+
return true;
|
|
21186
|
+
}
|
|
20717
21187
|
async traceSessionHostAction(action, args, run, summarizeResult) {
|
|
20718
21188
|
const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
|
|
20719
21189
|
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -21401,7 +21871,13 @@ var DaemonCommandRouter = class {
|
|
|
21401
21871
|
if (!workspace) return { success: false, error: "workspace required" };
|
|
21402
21872
|
try {
|
|
21403
21873
|
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21404
|
-
const
|
|
21874
|
+
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
21875
|
+
const readOnly = args?.readOnly === true;
|
|
21876
|
+
const policy = {
|
|
21877
|
+
...readOnly ? { readOnly: true } : {},
|
|
21878
|
+
...providerPriority.length ? { providerPriority } : {}
|
|
21879
|
+
};
|
|
21880
|
+
const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
|
|
21405
21881
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
21406
21882
|
return { success: true, node };
|
|
21407
21883
|
} catch (e) {
|
|
@@ -21413,17 +21889,98 @@ var DaemonCommandRouter = class {
|
|
|
21413
21889
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
21414
21890
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
21415
21891
|
try {
|
|
21416
|
-
const
|
|
21417
|
-
const
|
|
21892
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
21893
|
+
const mesh = meshRecord?.mesh;
|
|
21894
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
21895
|
+
if (node?.isLocalWorktree && node.workspace) {
|
|
21896
|
+
try {
|
|
21897
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
21898
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
21899
|
+
if (repoRoot) {
|
|
21900
|
+
const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
21901
|
+
await removeWorktree2(repoRoot, node.workspace);
|
|
21902
|
+
}
|
|
21903
|
+
} catch (e) {
|
|
21904
|
+
LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
|
|
21905
|
+
}
|
|
21906
|
+
}
|
|
21907
|
+
let removed = false;
|
|
21908
|
+
if (meshRecord?.inline) {
|
|
21909
|
+
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
21910
|
+
} else {
|
|
21911
|
+
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21912
|
+
removed = removeNode3(meshId, nodeId);
|
|
21913
|
+
}
|
|
21418
21914
|
return { success: true, removed };
|
|
21419
21915
|
} catch (e) {
|
|
21420
21916
|
return { success: false, error: e.message };
|
|
21421
21917
|
}
|
|
21422
21918
|
}
|
|
21919
|
+
case "clone_mesh_node": {
|
|
21920
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21921
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
21922
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
21923
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
21924
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
21925
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
21926
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
21927
|
+
try {
|
|
21928
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
21929
|
+
const mesh = meshRecord?.mesh;
|
|
21930
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
21931
|
+
const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
|
|
21932
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
21933
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
21934
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
21935
|
+
const result = await createWorktree2({
|
|
21936
|
+
repoRoot,
|
|
21937
|
+
branch,
|
|
21938
|
+
baseBranch,
|
|
21939
|
+
meshName: mesh.name
|
|
21940
|
+
});
|
|
21941
|
+
let node;
|
|
21942
|
+
if (meshRecord.inline) {
|
|
21943
|
+
const { randomUUID: randomUUID8 } = await import("crypto");
|
|
21944
|
+
node = {
|
|
21945
|
+
id: `node_${randomUUID8().replace(/-/g, "")}`,
|
|
21946
|
+
workspace: result.worktreePath,
|
|
21947
|
+
repoRoot: result.worktreePath,
|
|
21948
|
+
daemonId: sourceNode.daemonId,
|
|
21949
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
21950
|
+
policy: { ...sourceNode.policy || {} },
|
|
21951
|
+
isLocalWorktree: true,
|
|
21952
|
+
worktreeBranch: result.branch,
|
|
21953
|
+
clonedFromNodeId: sourceNodeId
|
|
21954
|
+
};
|
|
21955
|
+
this.updateInlineMeshNode(meshId, mesh, node);
|
|
21956
|
+
} else {
|
|
21957
|
+
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21958
|
+
node = addNode3(meshId, {
|
|
21959
|
+
workspace: result.worktreePath,
|
|
21960
|
+
repoRoot: result.worktreePath,
|
|
21961
|
+
daemonId: sourceNode.daemonId,
|
|
21962
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
21963
|
+
isLocalWorktree: true,
|
|
21964
|
+
worktreeBranch: result.branch,
|
|
21965
|
+
clonedFromNodeId: sourceNodeId,
|
|
21966
|
+
policy: { ...sourceNode.policy || {} }
|
|
21967
|
+
});
|
|
21968
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
21969
|
+
}
|
|
21970
|
+
return {
|
|
21971
|
+
success: true,
|
|
21972
|
+
node,
|
|
21973
|
+
worktreePath: result.worktreePath,
|
|
21974
|
+
branch: result.branch
|
|
21975
|
+
};
|
|
21976
|
+
} catch (e) {
|
|
21977
|
+
return { success: false, error: e.message };
|
|
21978
|
+
}
|
|
21979
|
+
}
|
|
21423
21980
|
// ─── Mesh Coordinator Launch ───
|
|
21424
21981
|
case "launch_mesh_coordinator": {
|
|
21425
21982
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21426
|
-
|
|
21983
|
+
let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
|
|
21427
21984
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
21428
21985
|
try {
|
|
21429
21986
|
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
@@ -21451,9 +22008,29 @@ var DaemonCommandRouter = class {
|
|
|
21451
22008
|
}
|
|
21452
22009
|
const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
|
|
21453
22010
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
22011
|
+
if (!cliType) {
|
|
22012
|
+
const resolved = await resolveProviderTypeFromPriority({
|
|
22013
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
|
|
22014
|
+
providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
|
|
22015
|
+
providerLoader: this.deps.providerLoader,
|
|
22016
|
+
onStatusChange: this.deps.onStatusChange
|
|
22017
|
+
});
|
|
22018
|
+
if (!resolved.providerType) {
|
|
22019
|
+
return {
|
|
22020
|
+
success: false,
|
|
22021
|
+
code: "mesh_coordinator_provider_priority_unusable",
|
|
22022
|
+
error: resolved.error || "No usable provider found from node providerPriority",
|
|
22023
|
+
meshId,
|
|
22024
|
+
cliType,
|
|
22025
|
+
workspace
|
|
22026
|
+
};
|
|
22027
|
+
}
|
|
22028
|
+
cliType = resolved.providerType;
|
|
22029
|
+
}
|
|
21454
22030
|
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
21455
22031
|
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
21456
22032
|
provider: providerMeta,
|
|
22033
|
+
cliType,
|
|
21457
22034
|
meshId,
|
|
21458
22035
|
workspace
|
|
21459
22036
|
});
|
|
@@ -21478,7 +22055,8 @@ var DaemonCommandRouter = class {
|
|
|
21478
22055
|
meshCoordinatorSetup: coordinatorSetup
|
|
21479
22056
|
};
|
|
21480
22057
|
}
|
|
21481
|
-
|
|
22058
|
+
const configFormat = coordinatorSetup.configFormat;
|
|
22059
|
+
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
21482
22060
|
return {
|
|
21483
22061
|
success: false,
|
|
21484
22062
|
code: "mesh_coordinator_unsupported",
|
|
@@ -21488,44 +22066,93 @@ var DaemonCommandRouter = class {
|
|
|
21488
22066
|
workspace
|
|
21489
22067
|
};
|
|
21490
22068
|
}
|
|
21491
|
-
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
|
|
22069
|
+
let systemPrompt = "";
|
|
22070
|
+
try {
|
|
22071
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
22072
|
+
} catch (error) {
|
|
22073
|
+
const message = error?.message || String(error);
|
|
22074
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
22075
|
+
return {
|
|
22076
|
+
success: false,
|
|
22077
|
+
code: "mesh_coordinator_prompt_failed",
|
|
22078
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
22079
|
+
meshId,
|
|
22080
|
+
cliType,
|
|
22081
|
+
workspace
|
|
22082
|
+
};
|
|
21501
22083
|
}
|
|
22084
|
+
const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
|
|
22085
|
+
const { dirname: dirname9 } = await import("path");
|
|
22086
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
22087
|
+
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
22088
|
+
const returnManualFallback = (message) => ({
|
|
22089
|
+
success: false,
|
|
22090
|
+
code: "mesh_coordinator_manual_mcp_setup_required",
|
|
22091
|
+
error: message,
|
|
22092
|
+
meshId,
|
|
22093
|
+
cliType,
|
|
22094
|
+
workspace,
|
|
22095
|
+
meshCoordinatorSetup: hermesManualFallback
|
|
22096
|
+
});
|
|
21502
22097
|
const mcpServerEntry = {
|
|
21503
22098
|
command: coordinatorSetup.mcpServer.command,
|
|
21504
22099
|
args: coordinatorSetup.mcpServer.args
|
|
21505
22100
|
};
|
|
21506
22101
|
if (args?.inlineMesh) {
|
|
21507
22102
|
mcpServerEntry.env = {
|
|
21508
|
-
ADHDEV_INLINE_MESH: JSON.stringify(mesh)
|
|
22103
|
+
ADHDEV_INLINE_MESH: JSON.stringify(mesh),
|
|
22104
|
+
ADHDEV_MCP_TRANSPORT: "ipc"
|
|
21509
22105
|
};
|
|
21510
22106
|
}
|
|
22107
|
+
try {
|
|
22108
|
+
mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
|
|
22109
|
+
} catch (error) {
|
|
22110
|
+
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
22111
|
+
LOG.error("MeshCoordinator", message);
|
|
22112
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22113
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
22114
|
+
}
|
|
22115
|
+
const hadExistingMcpConfig = existsSync23(mcpConfigPath);
|
|
22116
|
+
let existingMcpConfig = {};
|
|
22117
|
+
if (hadExistingMcpConfig) {
|
|
22118
|
+
try {
|
|
22119
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
|
|
22120
|
+
copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
|
|
22121
|
+
} catch (error) {
|
|
22122
|
+
LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
22123
|
+
return {
|
|
22124
|
+
success: false,
|
|
22125
|
+
code: "mesh_coordinator_config_parse_failed",
|
|
22126
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`
|
|
22127
|
+
};
|
|
22128
|
+
}
|
|
22129
|
+
}
|
|
22130
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
22131
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
21511
22132
|
const mcpConfig = {
|
|
21512
22133
|
...existingMcpConfig,
|
|
21513
|
-
|
|
21514
|
-
...
|
|
22134
|
+
[mcpServersKey]: {
|
|
22135
|
+
...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
|
|
21515
22136
|
[coordinatorSetup.serverName]: mcpServerEntry
|
|
21516
22137
|
}
|
|
21517
22138
|
};
|
|
21518
|
-
writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
21519
|
-
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21520
|
-
let systemPrompt = "";
|
|
21521
22139
|
try {
|
|
21522
|
-
|
|
21523
|
-
} catch {
|
|
21524
|
-
|
|
22140
|
+
writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
22141
|
+
} catch (error) {
|
|
22142
|
+
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
22143
|
+
LOG.error("MeshCoordinator", message);
|
|
22144
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22145
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21525
22146
|
}
|
|
22147
|
+
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21526
22148
|
const cliArgs = [];
|
|
22149
|
+
const launchEnv = {};
|
|
21527
22150
|
if (systemPrompt) {
|
|
21528
|
-
|
|
22151
|
+
if (configFormat === "hermes_config_yaml") {
|
|
22152
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
22153
|
+
} else {
|
|
22154
|
+
cliArgs.push("--append-system-prompt", systemPrompt);
|
|
22155
|
+
}
|
|
21529
22156
|
}
|
|
21530
22157
|
if (cliType === "claude-cli") {
|
|
21531
22158
|
cliArgs.push("--mcp-config", coordinatorSetup.configPath);
|
|
@@ -21534,6 +22161,7 @@ var DaemonCommandRouter = class {
|
|
|
21534
22161
|
cliType,
|
|
21535
22162
|
dir: workspace,
|
|
21536
22163
|
cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
|
|
22164
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
21537
22165
|
settings: {
|
|
21538
22166
|
meshCoordinatorFor: meshId
|
|
21539
22167
|
}
|
|
@@ -21713,6 +22341,12 @@ var DaemonStatusReporter = class {
|
|
|
21713
22341
|
if (providerType) {
|
|
21714
22342
|
payload.providerType = providerType;
|
|
21715
22343
|
}
|
|
22344
|
+
if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
|
|
22345
|
+
payload.providerSessionId = event.providerSessionId.trim();
|
|
22346
|
+
}
|
|
22347
|
+
if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
|
|
22348
|
+
payload.workspaceName = event.workspaceName.trim();
|
|
22349
|
+
}
|
|
21716
22350
|
if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
|
|
21717
22351
|
payload.duration = event.duration;
|
|
21718
22352
|
}
|
|
@@ -22960,7 +23594,10 @@ var ProviderInstanceManager = class {
|
|
|
22960
23594
|
this.instances.get(id).dispose();
|
|
22961
23595
|
}
|
|
22962
23596
|
this.instances.set(id, instance);
|
|
22963
|
-
await instance.init(
|
|
23597
|
+
await instance.init({
|
|
23598
|
+
...context,
|
|
23599
|
+
emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
|
|
23600
|
+
});
|
|
22964
23601
|
}
|
|
22965
23602
|
/**
|
|
22966
23603
|
* Instance remove
|
|
@@ -23122,6 +23759,17 @@ var ProviderInstanceManager = class {
|
|
|
23122
23759
|
onEvent(listener) {
|
|
23123
23760
|
this.eventListeners.push(listener);
|
|
23124
23761
|
}
|
|
23762
|
+
emitProviderEvent(providerType, instanceId, event) {
|
|
23763
|
+
const payload = {
|
|
23764
|
+
...event,
|
|
23765
|
+
providerType,
|
|
23766
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
|
|
23767
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
|
|
23768
|
+
};
|
|
23769
|
+
for (const listener of this.eventListeners) {
|
|
23770
|
+
listener(payload);
|
|
23771
|
+
}
|
|
23772
|
+
}
|
|
23125
23773
|
emitPendingEvents(providerType, state, extra = {}) {
|
|
23126
23774
|
for (const event of state.pendingEvents) {
|
|
23127
23775
|
for (const listener of this.eventListeners) {
|
|
@@ -23194,11 +23842,11 @@ var ProviderInstanceManager = class {
|
|
|
23194
23842
|
|
|
23195
23843
|
// src/providers/version-archive.ts
|
|
23196
23844
|
import * as fs11 from "fs";
|
|
23197
|
-
import * as
|
|
23198
|
-
import * as
|
|
23845
|
+
import * as path22 from "path";
|
|
23846
|
+
import * as os20 from "os";
|
|
23199
23847
|
import { execSync as execSync5 } from "child_process";
|
|
23200
23848
|
import { platform as platform8 } from "os";
|
|
23201
|
-
var ARCHIVE_PATH =
|
|
23849
|
+
var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
|
|
23202
23850
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
23203
23851
|
var VersionArchive = class {
|
|
23204
23852
|
history = {};
|
|
@@ -23245,7 +23893,7 @@ var VersionArchive = class {
|
|
|
23245
23893
|
}
|
|
23246
23894
|
save() {
|
|
23247
23895
|
try {
|
|
23248
|
-
fs11.mkdirSync(
|
|
23896
|
+
fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
|
|
23249
23897
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
23250
23898
|
} catch {
|
|
23251
23899
|
}
|
|
@@ -23301,8 +23949,8 @@ function getVersion(binary, versionCommand) {
|
|
|
23301
23949
|
function checkPathExists2(paths) {
|
|
23302
23950
|
for (const p of paths) {
|
|
23303
23951
|
if (p.includes("*")) {
|
|
23304
|
-
const home =
|
|
23305
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
23952
|
+
const home = os20.homedir();
|
|
23953
|
+
const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
|
|
23306
23954
|
if (fs11.existsSync(resolved)) return resolved;
|
|
23307
23955
|
} else {
|
|
23308
23956
|
if (fs11.existsSync(p)) return p;
|
|
@@ -23312,7 +23960,7 @@ function checkPathExists2(paths) {
|
|
|
23312
23960
|
}
|
|
23313
23961
|
function getMacAppVersion(appPath) {
|
|
23314
23962
|
if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
23315
|
-
const plistPath =
|
|
23963
|
+
const plistPath = path22.join(appPath, "Contents", "Info.plist");
|
|
23316
23964
|
if (!fs11.existsSync(plistPath)) return null;
|
|
23317
23965
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
23318
23966
|
return raw || null;
|
|
@@ -23338,7 +23986,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23338
23986
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
23339
23987
|
let resolvedBin = cliBin;
|
|
23340
23988
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
23341
|
-
const bundled =
|
|
23989
|
+
const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
23342
23990
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
23343
23991
|
}
|
|
23344
23992
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -23379,7 +24027,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23379
24027
|
// src/daemon/dev-server.ts
|
|
23380
24028
|
import * as http2 from "http";
|
|
23381
24029
|
import * as fs15 from "fs";
|
|
23382
|
-
import * as
|
|
24030
|
+
import * as path26 from "path";
|
|
23383
24031
|
init_config();
|
|
23384
24032
|
|
|
23385
24033
|
// src/daemon/scaffold-template.ts
|
|
@@ -23731,7 +24379,7 @@ init_logger();
|
|
|
23731
24379
|
// src/daemon/dev-cdp-handlers.ts
|
|
23732
24380
|
init_logger();
|
|
23733
24381
|
import * as fs12 from "fs";
|
|
23734
|
-
import * as
|
|
24382
|
+
import * as path23 from "path";
|
|
23735
24383
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
23736
24384
|
const body = await ctx.readBody(req);
|
|
23737
24385
|
const { expression, timeout, ideType } = body;
|
|
@@ -23909,17 +24557,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
23909
24557
|
return;
|
|
23910
24558
|
}
|
|
23911
24559
|
let scriptsPath = "";
|
|
23912
|
-
const directScripts =
|
|
24560
|
+
const directScripts = path23.join(dir, "scripts.js");
|
|
23913
24561
|
if (fs12.existsSync(directScripts)) {
|
|
23914
24562
|
scriptsPath = directScripts;
|
|
23915
24563
|
} else {
|
|
23916
|
-
const scriptsDir =
|
|
24564
|
+
const scriptsDir = path23.join(dir, "scripts");
|
|
23917
24565
|
if (fs12.existsSync(scriptsDir)) {
|
|
23918
24566
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
23919
|
-
return fs12.statSync(
|
|
24567
|
+
return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
|
|
23920
24568
|
}).sort().reverse();
|
|
23921
24569
|
for (const ver of versions) {
|
|
23922
|
-
const p =
|
|
24570
|
+
const p = path23.join(scriptsDir, ver, "scripts.js");
|
|
23923
24571
|
if (fs12.existsSync(p)) {
|
|
23924
24572
|
scriptsPath = p;
|
|
23925
24573
|
break;
|
|
@@ -24748,7 +25396,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
24748
25396
|
|
|
24749
25397
|
// src/daemon/dev-cli-debug.ts
|
|
24750
25398
|
import * as fs13 from "fs";
|
|
24751
|
-
import * as
|
|
25399
|
+
import * as path24 from "path";
|
|
24752
25400
|
function slugifyFixtureName(value) {
|
|
24753
25401
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24754
25402
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -24758,11 +25406,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
24758
25406
|
if (!providerDir) {
|
|
24759
25407
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
24760
25408
|
}
|
|
24761
|
-
return
|
|
25409
|
+
return path24.join(providerDir, "fixtures");
|
|
24762
25410
|
}
|
|
24763
25411
|
function readCliFixture(ctx, type, name) {
|
|
24764
25412
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
24765
|
-
const filePath =
|
|
25413
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
24766
25414
|
if (!fs13.existsSync(filePath)) {
|
|
24767
25415
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
24768
25416
|
}
|
|
@@ -25529,7 +26177,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
25529
26177
|
},
|
|
25530
26178
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
25531
26179
|
};
|
|
25532
|
-
const filePath =
|
|
26180
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
25533
26181
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
25534
26182
|
ctx.json(res, 200, {
|
|
25535
26183
|
saved: true,
|
|
@@ -25553,7 +26201,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
25553
26201
|
return;
|
|
25554
26202
|
}
|
|
25555
26203
|
const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
25556
|
-
const fullPath =
|
|
26204
|
+
const fullPath = path24.join(fixtureDir, file);
|
|
25557
26205
|
try {
|
|
25558
26206
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
25559
26207
|
return {
|
|
@@ -25689,8 +26337,8 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
25689
26337
|
|
|
25690
26338
|
// src/daemon/dev-auto-implement.ts
|
|
25691
26339
|
import * as fs14 from "fs";
|
|
25692
|
-
import * as
|
|
25693
|
-
import * as
|
|
26340
|
+
import * as path25 from "path";
|
|
26341
|
+
import * as os21 from "os";
|
|
25694
26342
|
function getAutoImplPid(ctx) {
|
|
25695
26343
|
const pid = ctx.autoImplProcess?.pid;
|
|
25696
26344
|
return typeof pid === "number" && pid > 0 ? pid : null;
|
|
@@ -25739,22 +26387,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
25739
26387
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
25740
26388
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
25741
26389
|
try {
|
|
25742
|
-
return fs14.statSync(
|
|
26390
|
+
return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
25743
26391
|
} catch {
|
|
25744
26392
|
return false;
|
|
25745
26393
|
}
|
|
25746
26394
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
25747
26395
|
if (versions.length === 0) return null;
|
|
25748
|
-
return
|
|
26396
|
+
return path25.join(scriptsDir, versions[0]);
|
|
25749
26397
|
}
|
|
25750
26398
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
25751
|
-
const canonicalUserDir =
|
|
25752
|
-
const desiredDir = requestedDir ?
|
|
25753
|
-
const upstreamRoot =
|
|
25754
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
26399
|
+
const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
26400
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
26401
|
+
const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
|
|
26402
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
25755
26403
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
25756
26404
|
}
|
|
25757
|
-
if (
|
|
26405
|
+
if (path25.basename(desiredDir) !== type) {
|
|
25758
26406
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
25759
26407
|
}
|
|
25760
26408
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -25762,11 +26410,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
25762
26410
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
25763
26411
|
}
|
|
25764
26412
|
if (!fs14.existsSync(desiredDir)) {
|
|
25765
|
-
fs14.mkdirSync(
|
|
26413
|
+
fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
25766
26414
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
25767
26415
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
25768
26416
|
}
|
|
25769
|
-
const providerJson =
|
|
26417
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
25770
26418
|
if (!fs14.existsSync(providerJson)) {
|
|
25771
26419
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
25772
26420
|
}
|
|
@@ -25777,13 +26425,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
25777
26425
|
const refDir = ctx.findProviderDir(referenceType);
|
|
25778
26426
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
25779
26427
|
const referenceScripts = {};
|
|
25780
|
-
const scriptsDir =
|
|
26428
|
+
const scriptsDir = path25.join(refDir, "scripts");
|
|
25781
26429
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
25782
26430
|
if (!latestDir) return referenceScripts;
|
|
25783
26431
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
25784
26432
|
if (!file.endsWith(".js")) continue;
|
|
25785
26433
|
try {
|
|
25786
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
26434
|
+
referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
|
|
25787
26435
|
} catch {
|
|
25788
26436
|
}
|
|
25789
26437
|
}
|
|
@@ -25891,9 +26539,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
25891
26539
|
});
|
|
25892
26540
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
25893
26541
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
25894
|
-
const tmpDir =
|
|
26542
|
+
const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
|
|
25895
26543
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
25896
|
-
const promptFile =
|
|
26544
|
+
const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
25897
26545
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
25898
26546
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
25899
26547
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -26046,7 +26694,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26046
26694
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
26047
26695
|
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
26048
26696
|
let shellCmd;
|
|
26049
|
-
const isWin =
|
|
26697
|
+
const isWin = os21.platform() === "win32";
|
|
26050
26698
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
26051
26699
|
const promptMode = autoImpl?.promptMode ?? "stdin";
|
|
26052
26700
|
const extraArgs = autoImpl?.extraArgs ?? [];
|
|
@@ -26085,7 +26733,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26085
26733
|
try {
|
|
26086
26734
|
const pty = __require("node-pty");
|
|
26087
26735
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
26088
|
-
const isWin2 =
|
|
26736
|
+
const isWin2 = os21.platform() === "win32";
|
|
26089
26737
|
child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
26090
26738
|
name: "xterm-256color",
|
|
26091
26739
|
cols: 120,
|
|
@@ -26325,7 +26973,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26325
26973
|
setMode: "set_mode.js"
|
|
26326
26974
|
};
|
|
26327
26975
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26328
|
-
const scriptsDir =
|
|
26976
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26329
26977
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26330
26978
|
if (latestScriptsDir) {
|
|
26331
26979
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26336,7 +26984,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26336
26984
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
26337
26985
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26338
26986
|
try {
|
|
26339
|
-
const content = fs14.readFileSync(
|
|
26987
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26340
26988
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26341
26989
|
lines.push("```javascript");
|
|
26342
26990
|
lines.push(content);
|
|
@@ -26353,7 +27001,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26353
27001
|
lines.push("");
|
|
26354
27002
|
for (const file of refFiles) {
|
|
26355
27003
|
try {
|
|
26356
|
-
const content = fs14.readFileSync(
|
|
27004
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26357
27005
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26358
27006
|
lines.push("```javascript");
|
|
26359
27007
|
lines.push(content);
|
|
@@ -26394,10 +27042,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26394
27042
|
lines.push("");
|
|
26395
27043
|
}
|
|
26396
27044
|
}
|
|
26397
|
-
const docsDir =
|
|
27045
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26398
27046
|
const loadGuide = (name) => {
|
|
26399
27047
|
try {
|
|
26400
|
-
const p =
|
|
27048
|
+
const p = path25.join(docsDir, name);
|
|
26401
27049
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26402
27050
|
} catch {
|
|
26403
27051
|
}
|
|
@@ -26634,7 +27282,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26634
27282
|
parseApproval: "parse_approval.js"
|
|
26635
27283
|
};
|
|
26636
27284
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26637
|
-
const scriptsDir =
|
|
27285
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26638
27286
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26639
27287
|
if (latestScriptsDir) {
|
|
26640
27288
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26646,7 +27294,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26646
27294
|
if (!file.endsWith(".js")) continue;
|
|
26647
27295
|
if (!targetFileNames.has(file)) continue;
|
|
26648
27296
|
try {
|
|
26649
|
-
const content = fs14.readFileSync(
|
|
27297
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26650
27298
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26651
27299
|
lines.push("```javascript");
|
|
26652
27300
|
lines.push(content);
|
|
@@ -26662,7 +27310,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26662
27310
|
lines.push("");
|
|
26663
27311
|
for (const file of refFiles) {
|
|
26664
27312
|
try {
|
|
26665
|
-
const content = fs14.readFileSync(
|
|
27313
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26666
27314
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26667
27315
|
lines.push("```javascript");
|
|
26668
27316
|
lines.push(content);
|
|
@@ -26695,10 +27343,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26695
27343
|
lines.push("");
|
|
26696
27344
|
}
|
|
26697
27345
|
}
|
|
26698
|
-
const docsDir =
|
|
27346
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26699
27347
|
const loadGuide = (name) => {
|
|
26700
27348
|
try {
|
|
26701
|
-
const p =
|
|
27349
|
+
const p = path25.join(docsDir, name);
|
|
26702
27350
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26703
27351
|
} catch {
|
|
26704
27352
|
}
|
|
@@ -27145,8 +27793,8 @@ var DevServer = class _DevServer {
|
|
|
27145
27793
|
}
|
|
27146
27794
|
getEndpointList() {
|
|
27147
27795
|
return this.routes.map((r) => {
|
|
27148
|
-
const
|
|
27149
|
-
return `${r.method.padEnd(5)} ${
|
|
27796
|
+
const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
27797
|
+
return `${r.method.padEnd(5)} ${path27}`;
|
|
27150
27798
|
});
|
|
27151
27799
|
}
|
|
27152
27800
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -27434,12 +28082,12 @@ var DevServer = class _DevServer {
|
|
|
27434
28082
|
// ─── DevConsole SPA ───
|
|
27435
28083
|
getConsoleDistDir() {
|
|
27436
28084
|
const candidates = [
|
|
27437
|
-
|
|
27438
|
-
|
|
27439
|
-
|
|
28085
|
+
path26.resolve(__dirname, "../../web-devconsole/dist"),
|
|
28086
|
+
path26.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
28087
|
+
path26.join(process.cwd(), "packages/web-devconsole/dist")
|
|
27440
28088
|
];
|
|
27441
28089
|
for (const dir of candidates) {
|
|
27442
|
-
if (fs15.existsSync(
|
|
28090
|
+
if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
|
|
27443
28091
|
}
|
|
27444
28092
|
return null;
|
|
27445
28093
|
}
|
|
@@ -27449,7 +28097,7 @@ var DevServer = class _DevServer {
|
|
|
27449
28097
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
27450
28098
|
return;
|
|
27451
28099
|
}
|
|
27452
|
-
const htmlPath =
|
|
28100
|
+
const htmlPath = path26.join(distDir, "index.html");
|
|
27453
28101
|
try {
|
|
27454
28102
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
27455
28103
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -27474,15 +28122,15 @@ var DevServer = class _DevServer {
|
|
|
27474
28122
|
this.json(res, 404, { error: "Not found" });
|
|
27475
28123
|
return;
|
|
27476
28124
|
}
|
|
27477
|
-
const safePath =
|
|
27478
|
-
const filePath =
|
|
28125
|
+
const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
|
|
28126
|
+
const filePath = path26.join(distDir, safePath);
|
|
27479
28127
|
if (!filePath.startsWith(distDir)) {
|
|
27480
28128
|
this.json(res, 403, { error: "Forbidden" });
|
|
27481
28129
|
return;
|
|
27482
28130
|
}
|
|
27483
28131
|
try {
|
|
27484
28132
|
const content = fs15.readFileSync(filePath);
|
|
27485
|
-
const ext =
|
|
28133
|
+
const ext = path26.extname(filePath);
|
|
27486
28134
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
27487
28135
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
27488
28136
|
res.end(content);
|
|
@@ -27595,9 +28243,9 @@ var DevServer = class _DevServer {
|
|
|
27595
28243
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27596
28244
|
if (entry.isDirectory()) {
|
|
27597
28245
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
27598
|
-
scan(
|
|
28246
|
+
scan(path26.join(d, entry.name), rel);
|
|
27599
28247
|
} else {
|
|
27600
|
-
const stat2 = fs15.statSync(
|
|
28248
|
+
const stat2 = fs15.statSync(path26.join(d, entry.name));
|
|
27601
28249
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
27602
28250
|
}
|
|
27603
28251
|
}
|
|
@@ -27620,7 +28268,7 @@ var DevServer = class _DevServer {
|
|
|
27620
28268
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27621
28269
|
return;
|
|
27622
28270
|
}
|
|
27623
|
-
const fullPath =
|
|
28271
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27624
28272
|
if (!fullPath.startsWith(dir)) {
|
|
27625
28273
|
this.json(res, 403, { error: "Forbidden" });
|
|
27626
28274
|
return;
|
|
@@ -27645,14 +28293,14 @@ var DevServer = class _DevServer {
|
|
|
27645
28293
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27646
28294
|
return;
|
|
27647
28295
|
}
|
|
27648
|
-
const fullPath =
|
|
28296
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27649
28297
|
if (!fullPath.startsWith(dir)) {
|
|
27650
28298
|
this.json(res, 403, { error: "Forbidden" });
|
|
27651
28299
|
return;
|
|
27652
28300
|
}
|
|
27653
28301
|
try {
|
|
27654
28302
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
27655
|
-
fs15.mkdirSync(
|
|
28303
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27656
28304
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27657
28305
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
27658
28306
|
this.providerLoader.reload();
|
|
@@ -27669,7 +28317,7 @@ var DevServer = class _DevServer {
|
|
|
27669
28317
|
return;
|
|
27670
28318
|
}
|
|
27671
28319
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
27672
|
-
const p =
|
|
28320
|
+
const p = path26.join(dir, name);
|
|
27673
28321
|
if (fs15.existsSync(p)) {
|
|
27674
28322
|
const source = fs15.readFileSync(p, "utf-8");
|
|
27675
28323
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -27690,8 +28338,8 @@ var DevServer = class _DevServer {
|
|
|
27690
28338
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
27691
28339
|
return;
|
|
27692
28340
|
}
|
|
27693
|
-
const target = fs15.existsSync(
|
|
27694
|
-
const targetPath =
|
|
28341
|
+
const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
28342
|
+
const targetPath = path26.join(dir, target);
|
|
27695
28343
|
try {
|
|
27696
28344
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
27697
28345
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -27838,7 +28486,7 @@ var DevServer = class _DevServer {
|
|
|
27838
28486
|
}
|
|
27839
28487
|
let targetDir;
|
|
27840
28488
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
27841
|
-
const jsonPath =
|
|
28489
|
+
const jsonPath = path26.join(targetDir, "provider.json");
|
|
27842
28490
|
if (fs15.existsSync(jsonPath)) {
|
|
27843
28491
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
27844
28492
|
return;
|
|
@@ -27850,8 +28498,8 @@ var DevServer = class _DevServer {
|
|
|
27850
28498
|
const createdFiles = ["provider.json"];
|
|
27851
28499
|
if (result.files) {
|
|
27852
28500
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
27853
|
-
const fullPath =
|
|
27854
|
-
fs15.mkdirSync(
|
|
28501
|
+
const fullPath = path26.join(targetDir, relPath);
|
|
28502
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27855
28503
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27856
28504
|
createdFiles.push(relPath);
|
|
27857
28505
|
}
|
|
@@ -27904,22 +28552,22 @@ var DevServer = class _DevServer {
|
|
|
27904
28552
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
27905
28553
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
27906
28554
|
try {
|
|
27907
|
-
return fs15.statSync(
|
|
28555
|
+
return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
|
|
27908
28556
|
} catch {
|
|
27909
28557
|
return false;
|
|
27910
28558
|
}
|
|
27911
28559
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
27912
28560
|
if (versions.length === 0) return null;
|
|
27913
|
-
return
|
|
28561
|
+
return path26.join(scriptsDir, versions[0]);
|
|
27914
28562
|
}
|
|
27915
28563
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
27916
|
-
const canonicalUserDir =
|
|
27917
|
-
const desiredDir = requestedDir ?
|
|
27918
|
-
const upstreamRoot =
|
|
27919
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
28564
|
+
const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
28565
|
+
const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
|
|
28566
|
+
const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
|
|
28567
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
|
|
27920
28568
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
27921
28569
|
}
|
|
27922
|
-
if (
|
|
28570
|
+
if (path26.basename(desiredDir) !== type) {
|
|
27923
28571
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
27924
28572
|
}
|
|
27925
28573
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -27927,11 +28575,11 @@ var DevServer = class _DevServer {
|
|
|
27927
28575
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
27928
28576
|
}
|
|
27929
28577
|
if (!fs15.existsSync(desiredDir)) {
|
|
27930
|
-
fs15.mkdirSync(
|
|
28578
|
+
fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
|
|
27931
28579
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
27932
28580
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
27933
28581
|
}
|
|
27934
|
-
const providerJson =
|
|
28582
|
+
const providerJson = path26.join(desiredDir, "provider.json");
|
|
27935
28583
|
if (!fs15.existsSync(providerJson)) {
|
|
27936
28584
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
27937
28585
|
}
|
|
@@ -27967,7 +28615,7 @@ var DevServer = class _DevServer {
|
|
|
27967
28615
|
setMode: "set_mode.js"
|
|
27968
28616
|
};
|
|
27969
28617
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
27970
|
-
const scriptsDir =
|
|
28618
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
27971
28619
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
27972
28620
|
if (latestScriptsDir) {
|
|
27973
28621
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -27978,7 +28626,7 @@ var DevServer = class _DevServer {
|
|
|
27978
28626
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
27979
28627
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
27980
28628
|
try {
|
|
27981
|
-
const content = fs15.readFileSync(
|
|
28629
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
27982
28630
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
27983
28631
|
lines.push("```javascript");
|
|
27984
28632
|
lines.push(content);
|
|
@@ -27995,7 +28643,7 @@ var DevServer = class _DevServer {
|
|
|
27995
28643
|
lines.push("");
|
|
27996
28644
|
for (const file of refFiles) {
|
|
27997
28645
|
try {
|
|
27998
|
-
const content = fs15.readFileSync(
|
|
28646
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
27999
28647
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28000
28648
|
lines.push("```javascript");
|
|
28001
28649
|
lines.push(content);
|
|
@@ -28036,10 +28684,10 @@ var DevServer = class _DevServer {
|
|
|
28036
28684
|
lines.push("");
|
|
28037
28685
|
}
|
|
28038
28686
|
}
|
|
28039
|
-
const docsDir =
|
|
28687
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28040
28688
|
const loadGuide = (name) => {
|
|
28041
28689
|
try {
|
|
28042
|
-
const p =
|
|
28690
|
+
const p = path26.join(docsDir, name);
|
|
28043
28691
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28044
28692
|
} catch {
|
|
28045
28693
|
}
|
|
@@ -28213,7 +28861,7 @@ var DevServer = class _DevServer {
|
|
|
28213
28861
|
parseApproval: "parse_approval.js"
|
|
28214
28862
|
};
|
|
28215
28863
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28216
|
-
const scriptsDir =
|
|
28864
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28217
28865
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28218
28866
|
if (latestScriptsDir) {
|
|
28219
28867
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28225,7 +28873,7 @@ var DevServer = class _DevServer {
|
|
|
28225
28873
|
if (!file.endsWith(".js")) continue;
|
|
28226
28874
|
if (!targetFileNames.has(file)) continue;
|
|
28227
28875
|
try {
|
|
28228
|
-
const content = fs15.readFileSync(
|
|
28876
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28229
28877
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28230
28878
|
lines.push("```javascript");
|
|
28231
28879
|
lines.push(content);
|
|
@@ -28241,7 +28889,7 @@ var DevServer = class _DevServer {
|
|
|
28241
28889
|
lines.push("");
|
|
28242
28890
|
for (const file of refFiles) {
|
|
28243
28891
|
try {
|
|
28244
|
-
const content = fs15.readFileSync(
|
|
28892
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28245
28893
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28246
28894
|
lines.push("```javascript");
|
|
28247
28895
|
lines.push(content);
|
|
@@ -28274,10 +28922,10 @@ var DevServer = class _DevServer {
|
|
|
28274
28922
|
lines.push("");
|
|
28275
28923
|
}
|
|
28276
28924
|
}
|
|
28277
|
-
const docsDir =
|
|
28925
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28278
28926
|
const loadGuide = (name) => {
|
|
28279
28927
|
try {
|
|
28280
|
-
const p =
|
|
28928
|
+
const p = path26.join(docsDir, name);
|
|
28281
28929
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28282
28930
|
} catch {
|
|
28283
28931
|
}
|
|
@@ -29286,33 +29934,49 @@ init_config();
|
|
|
29286
29934
|
// src/mesh/mesh-events.ts
|
|
29287
29935
|
init_mesh_config();
|
|
29288
29936
|
init_logger();
|
|
29937
|
+
function readNonEmptyString(value) {
|
|
29938
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
29939
|
+
}
|
|
29940
|
+
function formatCompletionMetadata(event) {
|
|
29941
|
+
const parts = [
|
|
29942
|
+
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
29943
|
+
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
29944
|
+
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
29945
|
+
].filter(Boolean);
|
|
29946
|
+
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
29947
|
+
}
|
|
29289
29948
|
function setupMeshEventForwarding(components) {
|
|
29290
29949
|
components.instanceManager.onEvent((event) => {
|
|
29291
29950
|
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
29292
|
-
const instanceId = event.instanceId;
|
|
29951
|
+
const instanceId = readNonEmptyString(event.instanceId);
|
|
29293
29952
|
if (!instanceId) return;
|
|
29294
29953
|
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
29295
29954
|
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
29296
29955
|
const state = sourceInstance.getState();
|
|
29297
|
-
const workspace = state.workspace;
|
|
29956
|
+
const workspace = readNonEmptyString(state.workspace);
|
|
29298
29957
|
if (!workspace) return;
|
|
29299
|
-
const
|
|
29300
|
-
|
|
29958
|
+
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
29959
|
+
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
29960
|
+
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
29961
|
+
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
29962
|
+
if (!meshId) return;
|
|
29301
29963
|
const allInstances = components.instanceManager.getByCategory("cli");
|
|
29302
29964
|
const coordinatorInstances = allInstances.filter((inst) => {
|
|
29303
29965
|
const instState = inst.getState();
|
|
29304
|
-
if (instState.settings?.meshCoordinatorFor !==
|
|
29966
|
+
if (instState.settings?.meshCoordinatorFor !== meshId) return false;
|
|
29305
29967
|
if (instState.instanceId === instanceId) return false;
|
|
29306
29968
|
return true;
|
|
29307
29969
|
});
|
|
29308
29970
|
if (coordinatorInstances.length === 0) return;
|
|
29309
|
-
const targetNode = mesh
|
|
29310
|
-
const
|
|
29971
|
+
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
29972
|
+
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
29973
|
+
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
29974
|
+
const metadata = formatCompletionMetadata(event);
|
|
29311
29975
|
let messageText = "";
|
|
29312
29976
|
if (event.event === "agent:generating_completed") {
|
|
29313
|
-
messageText = `[System] ${nodeLabel} has completed its task and is now idle. You may use mesh_read_chat to review its progress.`;
|
|
29977
|
+
messageText = `[System] ${nodeLabel} has completed its task and is now idle${metadata}. You may use mesh_read_chat to review its progress.`;
|
|
29314
29978
|
} else if (event.event === "agent:waiting_approval") {
|
|
29315
|
-
messageText = `[System] ${nodeLabel} is waiting for approval to proceed. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
29979
|
+
messageText = `[System] ${nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
29316
29980
|
}
|
|
29317
29981
|
if (!messageText) return;
|
|
29318
29982
|
for (const coord of coordinatorInstances) {
|
|
@@ -29629,6 +30293,7 @@ export {
|
|
|
29629
30293
|
createGitWorkspaceMonitor,
|
|
29630
30294
|
createInteractionId,
|
|
29631
30295
|
createMesh,
|
|
30296
|
+
createWorktree,
|
|
29632
30297
|
deleteMesh,
|
|
29633
30298
|
detectAllVersions,
|
|
29634
30299
|
detectCLIs,
|
|
@@ -29681,6 +30346,7 @@ export {
|
|
|
29681
30346
|
launchWithCdp,
|
|
29682
30347
|
listHostedCliRuntimes,
|
|
29683
30348
|
listMeshes,
|
|
30349
|
+
listWorktrees,
|
|
29684
30350
|
loadConfig,
|
|
29685
30351
|
loadState,
|
|
29686
30352
|
logCommand,
|
|
@@ -29700,6 +30366,7 @@ export {
|
|
|
29700
30366
|
normalizeSessionModalFields,
|
|
29701
30367
|
parsePorcelainV2Status,
|
|
29702
30368
|
parseProviderSourceConfigUpdate,
|
|
30369
|
+
parseWorktreeListOutput,
|
|
29703
30370
|
partitionSessionHostDiagnosticsSessions,
|
|
29704
30371
|
partitionSessionHostRecords,
|
|
29705
30372
|
prepareSessionChatTailUpdate,
|
|
@@ -29709,6 +30376,7 @@ export {
|
|
|
29709
30376
|
recordDebugTrace,
|
|
29710
30377
|
registerExtensionProviders,
|
|
29711
30378
|
removeNode,
|
|
30379
|
+
removeWorktree,
|
|
29712
30380
|
resetConfig,
|
|
29713
30381
|
resetDebugRuntimeConfig,
|
|
29714
30382
|
resetState,
|
|
@@ -29718,6 +30386,7 @@ export {
|
|
|
29718
30386
|
resolveGitRepository,
|
|
29719
30387
|
resolveSessionHostAppName,
|
|
29720
30388
|
resolveSessionHostAppNameResolution,
|
|
30389
|
+
resolveWorktreePath,
|
|
29721
30390
|
runAsyncBatch,
|
|
29722
30391
|
runGit,
|
|
29723
30392
|
saveConfig,
|