@adhdev/daemon-core 0.9.76-rc.2 → 0.9.76-rc.20
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 +6 -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-worktree.d.ts +64 -0
- package/dist/git/index.d.ts +2 -0
- package/dist/index.js +870 -361
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +897 -393
- 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/repo-mesh-types.d.ts +4 -0
- package/dist/shared-types.d.ts +18 -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 +49 -4
- package/src/commands/cli-manager.ts +13 -3
- package/src/commands/mesh-coordinator.ts +149 -6
- package/src/commands/router.ts +247 -30
- package/src/config/mesh-config.ts +6 -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/providers/cli-provider-instance.d.ts +2 -0
- package/src/providers/cli-provider-instance.ts +6 -1
- package/src/repo-mesh-types.ts +4 -0
- package/src/shared-types.ts +20 -1
- package/src/status/builders.ts +17 -12
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();
|
|
@@ -4983,20 +5129,23 @@ var TurnSnapshotTracker = class {
|
|
|
4983
5129
|
}
|
|
4984
5130
|
};
|
|
4985
5131
|
|
|
5132
|
+
// src/git/index.ts
|
|
5133
|
+
init_git_worktree();
|
|
5134
|
+
|
|
4986
5135
|
// src/index.ts
|
|
4987
5136
|
init_config();
|
|
4988
5137
|
|
|
4989
5138
|
// src/config/workspaces.ts
|
|
4990
5139
|
import * as fs from "fs";
|
|
4991
5140
|
import * as os from "os";
|
|
4992
|
-
import * as
|
|
5141
|
+
import * as path5 from "path";
|
|
4993
5142
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4994
5143
|
var MAX_WORKSPACES = 50;
|
|
4995
5144
|
function expandPath(p) {
|
|
4996
5145
|
const t = (p || "").trim();
|
|
4997
5146
|
if (!t) return "";
|
|
4998
|
-
if (t.startsWith("~")) return
|
|
4999
|
-
return
|
|
5147
|
+
if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5148
|
+
return path5.resolve(t);
|
|
5000
5149
|
}
|
|
5001
5150
|
function validateWorkspacePath(absPath) {
|
|
5002
5151
|
try {
|
|
@@ -5010,7 +5159,7 @@ function validateWorkspacePath(absPath) {
|
|
|
5010
5159
|
}
|
|
5011
5160
|
}
|
|
5012
5161
|
function defaultWorkspaceLabel(absPath) {
|
|
5013
|
-
const base =
|
|
5162
|
+
const base = path5.basename(absPath) || absPath;
|
|
5014
5163
|
return base;
|
|
5015
5164
|
}
|
|
5016
5165
|
function getDefaultWorkspacePath(config) {
|
|
@@ -5101,9 +5250,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
5101
5250
|
return getDefaultWorkspacePath(config) || void 0;
|
|
5102
5251
|
}
|
|
5103
5252
|
function findWorkspaceByPath(config, rawPath) {
|
|
5104
|
-
const abs =
|
|
5253
|
+
const abs = path5.resolve(expandPath(rawPath));
|
|
5105
5254
|
if (!abs) return void 0;
|
|
5106
|
-
return (config.workspaces || []).find((w) =>
|
|
5255
|
+
return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
|
|
5107
5256
|
}
|
|
5108
5257
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
5109
5258
|
const abs = expandPath(rawPath);
|
|
@@ -5119,7 +5268,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
5119
5268
|
const v = validateWorkspacePath(abs);
|
|
5120
5269
|
if (!v.ok) return { error: v.error };
|
|
5121
5270
|
const list = [...config.workspaces || []];
|
|
5122
|
-
if (list.some((w) =>
|
|
5271
|
+
if (list.some((w) => path5.resolve(w.path) === abs)) {
|
|
5123
5272
|
return { error: "Workspace already in list" };
|
|
5124
5273
|
}
|
|
5125
5274
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -5153,7 +5302,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
5153
5302
|
}
|
|
5154
5303
|
|
|
5155
5304
|
// src/config/recent-activity.ts
|
|
5156
|
-
import * as
|
|
5305
|
+
import * as path6 from "path";
|
|
5157
5306
|
|
|
5158
5307
|
// src/providers/summary-metadata.ts
|
|
5159
5308
|
function normalizeSummaryItem(item) {
|
|
@@ -5222,9 +5371,9 @@ var MAX_ACTIVITY = 30;
|
|
|
5222
5371
|
function normalizeWorkspace(workspace) {
|
|
5223
5372
|
if (!workspace) return "";
|
|
5224
5373
|
try {
|
|
5225
|
-
return
|
|
5374
|
+
return path6.resolve(expandPath(workspace));
|
|
5226
5375
|
} catch {
|
|
5227
|
-
return
|
|
5376
|
+
return path6.resolve(workspace);
|
|
5228
5377
|
}
|
|
5229
5378
|
}
|
|
5230
5379
|
function buildRecentActivityKey(entry) {
|
|
@@ -5392,14 +5541,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5392
5541
|
}
|
|
5393
5542
|
|
|
5394
5543
|
// src/config/saved-sessions.ts
|
|
5395
|
-
import * as
|
|
5544
|
+
import * as path7 from "path";
|
|
5396
5545
|
var MAX_SAVED_SESSIONS = 500;
|
|
5397
5546
|
function normalizeWorkspace2(workspace) {
|
|
5398
5547
|
if (!workspace) return "";
|
|
5399
5548
|
try {
|
|
5400
|
-
return
|
|
5549
|
+
return path7.resolve(expandPath(workspace));
|
|
5401
5550
|
} catch {
|
|
5402
|
-
return
|
|
5551
|
+
return path7.resolve(workspace);
|
|
5403
5552
|
}
|
|
5404
5553
|
}
|
|
5405
5554
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5505,8 +5654,8 @@ async function syncMeshes(transport) {
|
|
|
5505
5654
|
|
|
5506
5655
|
// src/config/state-store.ts
|
|
5507
5656
|
init_config();
|
|
5508
|
-
import { existsSync as
|
|
5509
|
-
import { join as
|
|
5657
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5658
|
+
import { join as join5 } from "path";
|
|
5510
5659
|
var DEFAULT_STATE = {
|
|
5511
5660
|
recentActivity: [],
|
|
5512
5661
|
savedProviderSessions: [],
|
|
@@ -5519,7 +5668,7 @@ function isPlainObject2(value) {
|
|
|
5519
5668
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5520
5669
|
}
|
|
5521
5670
|
function getStatePath() {
|
|
5522
|
-
return
|
|
5671
|
+
return join5(getConfigDir(), "state.json");
|
|
5523
5672
|
}
|
|
5524
5673
|
function normalizeState(raw) {
|
|
5525
5674
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -5555,7 +5704,7 @@ function normalizeState(raw) {
|
|
|
5555
5704
|
}
|
|
5556
5705
|
function loadState() {
|
|
5557
5706
|
const statePath = getStatePath();
|
|
5558
|
-
if (!
|
|
5707
|
+
if (!existsSync5(statePath)) {
|
|
5559
5708
|
return { ...DEFAULT_STATE };
|
|
5560
5709
|
}
|
|
5561
5710
|
try {
|
|
@@ -5576,9 +5725,9 @@ function resetState() {
|
|
|
5576
5725
|
|
|
5577
5726
|
// src/detection/ide-detector.ts
|
|
5578
5727
|
import { execSync } from "child_process";
|
|
5579
|
-
import { existsSync as
|
|
5728
|
+
import { existsSync as existsSync6 } from "fs";
|
|
5580
5729
|
import { platform, homedir as homedir3 } from "os";
|
|
5581
|
-
import * as
|
|
5730
|
+
import * as path8 from "path";
|
|
5582
5731
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5583
5732
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5584
5733
|
function registerIDEDefinition(def) {
|
|
@@ -5597,10 +5746,10 @@ function getMergedDefinitions() {
|
|
|
5597
5746
|
function findCliCommand(command) {
|
|
5598
5747
|
const trimmed = String(command || "").trim();
|
|
5599
5748
|
if (!trimmed) return null;
|
|
5600
|
-
if (
|
|
5601
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5602
|
-
const resolved =
|
|
5603
|
-
return
|
|
5749
|
+
if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
5750
|
+
const candidate = trimmed.startsWith("~") ? path8.join(homedir3(), trimmed.slice(1)) : trimmed;
|
|
5751
|
+
const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
|
|
5752
|
+
return existsSync6(resolved) ? resolved : null;
|
|
5604
5753
|
}
|
|
5605
5754
|
try {
|
|
5606
5755
|
const result = execSync(
|
|
@@ -5627,31 +5776,31 @@ function getIdeVersion(cliCommand) {
|
|
|
5627
5776
|
function checkPathExists(paths) {
|
|
5628
5777
|
const home = homedir3();
|
|
5629
5778
|
for (const p of paths) {
|
|
5630
|
-
const normalized = p.startsWith("~") ?
|
|
5779
|
+
const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
|
|
5631
5780
|
if (normalized.includes("*")) {
|
|
5632
5781
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5633
5782
|
const resolved = normalized.replace("*", username);
|
|
5634
|
-
if (
|
|
5783
|
+
if (existsSync6(resolved)) return resolved;
|
|
5635
5784
|
} else {
|
|
5636
|
-
if (
|
|
5785
|
+
if (existsSync6(normalized)) return normalized;
|
|
5637
5786
|
}
|
|
5638
5787
|
}
|
|
5639
5788
|
return null;
|
|
5640
5789
|
}
|
|
5641
5790
|
async function detectIDEs(providerLoader) {
|
|
5642
|
-
const
|
|
5791
|
+
const os22 = platform();
|
|
5643
5792
|
const results = [];
|
|
5644
5793
|
for (const def of getMergedDefinitions()) {
|
|
5645
5794
|
const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
|
|
5646
|
-
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[
|
|
5795
|
+
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
|
|
5647
5796
|
let resolvedCli = cliPath;
|
|
5648
|
-
if (!resolvedCli && appPath &&
|
|
5797
|
+
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
5649
5798
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
5650
|
-
if (
|
|
5799
|
+
if (existsSync6(bundledCli)) resolvedCli = bundledCli;
|
|
5651
5800
|
}
|
|
5652
|
-
if (!resolvedCli && appPath &&
|
|
5653
|
-
const { dirname:
|
|
5654
|
-
const appDir =
|
|
5801
|
+
if (!resolvedCli && appPath && os22 === "win32") {
|
|
5802
|
+
const { dirname: dirname9 } = await import("path");
|
|
5803
|
+
const appDir = dirname9(appPath);
|
|
5655
5804
|
const candidates = [
|
|
5656
5805
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
5657
5806
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -5660,13 +5809,13 @@ async function detectIDEs(providerLoader) {
|
|
|
5660
5809
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
5661
5810
|
];
|
|
5662
5811
|
for (const c of candidates) {
|
|
5663
|
-
if (
|
|
5812
|
+
if (existsSync6(c)) {
|
|
5664
5813
|
resolvedCli = c;
|
|
5665
5814
|
break;
|
|
5666
5815
|
}
|
|
5667
5816
|
}
|
|
5668
5817
|
}
|
|
5669
|
-
const installed =
|
|
5818
|
+
const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
|
|
5670
5819
|
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
5671
5820
|
results.push({
|
|
5672
5821
|
id: def.id,
|
|
@@ -5685,8 +5834,8 @@ async function detectIDEs(providerLoader) {
|
|
|
5685
5834
|
// src/detection/cli-detector.ts
|
|
5686
5835
|
import { exec } from "child_process";
|
|
5687
5836
|
import * as os2 from "os";
|
|
5688
|
-
import * as
|
|
5689
|
-
import { existsSync as
|
|
5837
|
+
import * as path9 from "path";
|
|
5838
|
+
import { existsSync as existsSync7 } from "fs";
|
|
5690
5839
|
function parseVersion(raw) {
|
|
5691
5840
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
5692
5841
|
return match ? match[1] : raw.split("\n")[0].slice(0, 100);
|
|
@@ -5698,19 +5847,19 @@ function shellQuote(value) {
|
|
|
5698
5847
|
function expandHome(value) {
|
|
5699
5848
|
const trimmed = value.trim();
|
|
5700
5849
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5701
|
-
return
|
|
5850
|
+
return path9.join(os2.homedir(), trimmed.slice(1));
|
|
5702
5851
|
}
|
|
5703
5852
|
function isExplicitCommandPath(command) {
|
|
5704
5853
|
const trimmed = command.trim();
|
|
5705
|
-
return
|
|
5854
|
+
return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5706
5855
|
}
|
|
5707
5856
|
function resolveCommandPath(command) {
|
|
5708
5857
|
const trimmed = command.trim();
|
|
5709
5858
|
if (!trimmed) return null;
|
|
5710
5859
|
if (isExplicitCommandPath(trimmed)) {
|
|
5711
5860
|
const expanded = expandHome(trimmed);
|
|
5712
|
-
const candidate =
|
|
5713
|
-
return
|
|
5861
|
+
const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
|
|
5862
|
+
return existsSync7(candidate) ? candidate : null;
|
|
5714
5863
|
}
|
|
5715
5864
|
return null;
|
|
5716
5865
|
}
|
|
@@ -7978,9 +8127,9 @@ ${cleanBody}`;
|
|
|
7978
8127
|
|
|
7979
8128
|
// src/config/chat-history.ts
|
|
7980
8129
|
import * as fs3 from "fs";
|
|
7981
|
-
import * as
|
|
8130
|
+
import * as path11 from "path";
|
|
7982
8131
|
import * as os5 from "os";
|
|
7983
|
-
var HISTORY_DIR =
|
|
8132
|
+
var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
|
|
7984
8133
|
var RETAIN_DAYS = 30;
|
|
7985
8134
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
7986
8135
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -8143,7 +8292,7 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
8143
8292
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
8144
8293
|
return new Map(files.map((file) => {
|
|
8145
8294
|
try {
|
|
8146
|
-
const stat2 = fs3.statSync(
|
|
8295
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8147
8296
|
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
8148
8297
|
} catch {
|
|
8149
8298
|
return [file, `${file}:missing`];
|
|
@@ -8154,7 +8303,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
8154
8303
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
8155
8304
|
}
|
|
8156
8305
|
function getSavedHistoryIndexFilePath(dir) {
|
|
8157
|
-
return
|
|
8306
|
+
return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
8158
8307
|
}
|
|
8159
8308
|
function getSavedHistoryIndexLockPath(dir) {
|
|
8160
8309
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -8256,7 +8405,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
8256
8405
|
}
|
|
8257
8406
|
for (const file of Array.from(currentEntries.keys())) {
|
|
8258
8407
|
if (incomingFiles.has(file)) continue;
|
|
8259
|
-
if (!fs3.existsSync(
|
|
8408
|
+
if (!fs3.existsSync(path11.join(dir, file))) {
|
|
8260
8409
|
currentEntries.delete(file);
|
|
8261
8410
|
}
|
|
8262
8411
|
}
|
|
@@ -8282,7 +8431,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8282
8431
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8283
8432
|
const files = listHistoryFiles(dir);
|
|
8284
8433
|
for (const file of files) {
|
|
8285
|
-
const stat2 = fs3.statSync(
|
|
8434
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8286
8435
|
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
8287
8436
|
}
|
|
8288
8437
|
return false;
|
|
@@ -8292,14 +8441,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8292
8441
|
}
|
|
8293
8442
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
8294
8443
|
try {
|
|
8295
|
-
const stat2 = fs3.statSync(
|
|
8444
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8296
8445
|
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
8297
8446
|
} catch {
|
|
8298
8447
|
return `${file}:missing`;
|
|
8299
8448
|
}
|
|
8300
8449
|
}
|
|
8301
8450
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
8302
|
-
const filePath =
|
|
8451
|
+
const filePath = path11.join(dir, file);
|
|
8303
8452
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
8304
8453
|
const currentEntry = entries.get(file) || null;
|
|
8305
8454
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -8372,7 +8521,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
8372
8521
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
8373
8522
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
8374
8523
|
if (!historySessionId) return null;
|
|
8375
|
-
const filePath =
|
|
8524
|
+
const filePath = path11.join(dir, file);
|
|
8376
8525
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8377
8526
|
const lines = content.split("\n").filter(Boolean);
|
|
8378
8527
|
let messageCount = 0;
|
|
@@ -8459,7 +8608,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
8459
8608
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
8460
8609
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
8461
8610
|
for (const file of files.slice().sort()) {
|
|
8462
|
-
const filePath =
|
|
8611
|
+
const filePath = path11.join(dir, file);
|
|
8463
8612
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
8464
8613
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
8465
8614
|
const persisted = persistedEntries.get(file);
|
|
@@ -8579,12 +8728,12 @@ var ChatHistoryWriter = class {
|
|
|
8579
8728
|
});
|
|
8580
8729
|
}
|
|
8581
8730
|
if (newMessages.length === 0) return;
|
|
8582
|
-
const dir =
|
|
8731
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8583
8732
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8584
8733
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8585
8734
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
8586
8735
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
8587
|
-
const filePath =
|
|
8736
|
+
const filePath = path11.join(dir, fileName);
|
|
8588
8737
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
8589
8738
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
8590
8739
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -8675,11 +8824,11 @@ var ChatHistoryWriter = class {
|
|
|
8675
8824
|
const ws = String(workspace || "").trim();
|
|
8676
8825
|
if (!id || !ws) return;
|
|
8677
8826
|
try {
|
|
8678
|
-
const dir =
|
|
8827
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8679
8828
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8680
8829
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8681
8830
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
8682
|
-
const filePath =
|
|
8831
|
+
const filePath = path11.join(dir, fileName);
|
|
8683
8832
|
const record = {
|
|
8684
8833
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8685
8834
|
receivedAt: Date.now(),
|
|
@@ -8725,14 +8874,14 @@ var ChatHistoryWriter = class {
|
|
|
8725
8874
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8726
8875
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8727
8876
|
}
|
|
8728
|
-
const dir =
|
|
8877
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8729
8878
|
if (!fs3.existsSync(dir)) return;
|
|
8730
8879
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8731
8880
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8732
8881
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8733
8882
|
for (const file of files) {
|
|
8734
|
-
const sourcePath =
|
|
8735
|
-
const targetPath =
|
|
8883
|
+
const sourcePath = path11.join(dir, file);
|
|
8884
|
+
const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8736
8885
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8737
8886
|
const rewritten = sourceLines.map((line) => {
|
|
8738
8887
|
try {
|
|
@@ -8766,13 +8915,13 @@ var ChatHistoryWriter = class {
|
|
|
8766
8915
|
const sessionId = String(historySessionId || "").trim();
|
|
8767
8916
|
if (!sessionId) return;
|
|
8768
8917
|
try {
|
|
8769
|
-
const dir =
|
|
8918
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8770
8919
|
if (!fs3.existsSync(dir)) return;
|
|
8771
8920
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8772
8921
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8773
8922
|
const seen = /* @__PURE__ */ new Set();
|
|
8774
8923
|
for (const file of files) {
|
|
8775
|
-
const filePath =
|
|
8924
|
+
const filePath = path11.join(dir, file);
|
|
8776
8925
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8777
8926
|
const next = [];
|
|
8778
8927
|
for (const line of lines) {
|
|
@@ -8826,11 +8975,11 @@ var ChatHistoryWriter = class {
|
|
|
8826
8975
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
8827
8976
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
8828
8977
|
for (const dir of agentDirs) {
|
|
8829
|
-
const dirPath =
|
|
8978
|
+
const dirPath = path11.join(HISTORY_DIR, dir.name);
|
|
8830
8979
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
8831
8980
|
let removedAny = false;
|
|
8832
8981
|
for (const file of files) {
|
|
8833
|
-
const filePath =
|
|
8982
|
+
const filePath = path11.join(dirPath, file);
|
|
8834
8983
|
const stat2 = fs3.statSync(filePath);
|
|
8835
8984
|
if (stat2.mtimeMs < cutoff) {
|
|
8836
8985
|
fs3.unlinkSync(filePath);
|
|
@@ -8880,13 +9029,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8880
9029
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8881
9030
|
try {
|
|
8882
9031
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8883
|
-
const dir =
|
|
9032
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8884
9033
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
8885
9034
|
const files = listHistoryFiles(dir, historySessionId);
|
|
8886
9035
|
const allMessages = [];
|
|
8887
9036
|
const seen = /* @__PURE__ */ new Set();
|
|
8888
9037
|
for (const file of files) {
|
|
8889
|
-
const filePath =
|
|
9038
|
+
const filePath = path11.join(dir, file);
|
|
8890
9039
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8891
9040
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
8892
9041
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8910,7 +9059,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8910
9059
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
8911
9060
|
try {
|
|
8912
9061
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8913
|
-
const dir =
|
|
9062
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
8914
9063
|
if (!fs3.existsSync(dir)) {
|
|
8915
9064
|
savedHistorySessionCache.delete(sanitized);
|
|
8916
9065
|
return { sessions: [], hasMore: false };
|
|
@@ -8971,11 +9120,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8971
9120
|
}
|
|
8972
9121
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8973
9122
|
try {
|
|
8974
|
-
const dir =
|
|
9123
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8975
9124
|
if (!fs3.existsSync(dir)) return null;
|
|
8976
9125
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
8977
9126
|
for (const file of files) {
|
|
8978
|
-
const lines = fs3.readFileSync(
|
|
9127
|
+
const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
8979
9128
|
for (const line of lines) {
|
|
8980
9129
|
try {
|
|
8981
9130
|
const parsed = JSON.parse(line);
|
|
@@ -8995,16 +9144,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
8995
9144
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
8996
9145
|
if (records.length === 0) return false;
|
|
8997
9146
|
try {
|
|
8998
|
-
const dir =
|
|
9147
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
8999
9148
|
fs3.mkdirSync(dir, { recursive: true });
|
|
9000
9149
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
9001
9150
|
for (const file of fs3.readdirSync(dir)) {
|
|
9002
9151
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
9003
|
-
fs3.unlinkSync(
|
|
9152
|
+
fs3.unlinkSync(path11.join(dir, file));
|
|
9004
9153
|
}
|
|
9005
9154
|
}
|
|
9006
9155
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
9007
|
-
const filePath =
|
|
9156
|
+
const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
9008
9157
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
9009
9158
|
`, "utf-8");
|
|
9010
9159
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -10999,6 +11148,14 @@ function getActiveChatOptions(profile) {
|
|
|
10999
11148
|
if (profile === "full") return {};
|
|
11000
11149
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
11001
11150
|
}
|
|
11151
|
+
function resolveSessionStatus(activeChat, providerStatus) {
|
|
11152
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
11153
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
11154
|
+
if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
|
|
11155
|
+
if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
|
|
11156
|
+
if (topLevelStatus !== "idle") return topLevelStatus;
|
|
11157
|
+
return chatStatus;
|
|
11158
|
+
}
|
|
11002
11159
|
function shouldIncludeSessionControls(profile) {
|
|
11003
11160
|
return profile !== "live";
|
|
11004
11161
|
}
|
|
@@ -11077,9 +11234,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11077
11234
|
providerName: state.name,
|
|
11078
11235
|
kind: "workspace",
|
|
11079
11236
|
transport: "cdp-page",
|
|
11080
|
-
status:
|
|
11081
|
-
activeModal: activeChat?.activeModal || null
|
|
11082
|
-
}),
|
|
11237
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11083
11238
|
title,
|
|
11084
11239
|
workspace,
|
|
11085
11240
|
...git && { git },
|
|
@@ -11114,9 +11269,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11114
11269
|
providerSessionId: ext.providerSessionId,
|
|
11115
11270
|
kind: "agent",
|
|
11116
11271
|
transport: "cdp-webview",
|
|
11117
|
-
status:
|
|
11118
|
-
activeModal: activeChat?.activeModal || null
|
|
11119
|
-
}),
|
|
11272
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
11120
11273
|
title: activeChat?.title || ext.name,
|
|
11121
11274
|
workspace,
|
|
11122
11275
|
...git && { git },
|
|
@@ -11166,9 +11319,7 @@ function buildCliSession(state, options) {
|
|
|
11166
11319
|
providerSessionId: state.providerSessionId,
|
|
11167
11320
|
kind: "agent",
|
|
11168
11321
|
transport: "pty",
|
|
11169
|
-
status:
|
|
11170
|
-
activeModal: activeChat?.activeModal || null
|
|
11171
|
-
}),
|
|
11322
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11172
11323
|
title: activeChat?.title || state.name,
|
|
11173
11324
|
workspace,
|
|
11174
11325
|
...git && { git },
|
|
@@ -11216,9 +11367,7 @@ function buildAcpSession(state, options) {
|
|
|
11216
11367
|
providerName: state.name,
|
|
11217
11368
|
kind: "agent",
|
|
11218
11369
|
transport: "acp",
|
|
11219
|
-
status:
|
|
11220
|
-
activeModal: activeChat?.activeModal || null
|
|
11221
|
-
}),
|
|
11370
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11222
11371
|
title: activeChat?.title || state.name,
|
|
11223
11372
|
workspace,
|
|
11224
11373
|
...git && { git },
|
|
@@ -11341,7 +11490,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
11341
11490
|
// src/commands/chat-commands.ts
|
|
11342
11491
|
import * as fs4 from "fs";
|
|
11343
11492
|
import * as os6 from "os";
|
|
11344
|
-
import * as
|
|
11493
|
+
import * as path12 from "path";
|
|
11345
11494
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
11346
11495
|
|
|
11347
11496
|
// src/providers/provider-input-support.ts
|
|
@@ -11704,6 +11853,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
11704
11853
|
return raw;
|
|
11705
11854
|
}
|
|
11706
11855
|
}
|
|
11856
|
+
function isGeneratingLikeStatus(status) {
|
|
11857
|
+
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
11858
|
+
}
|
|
11859
|
+
function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
11860
|
+
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
11861
|
+
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
11862
|
+
const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
|
|
11863
|
+
if (adapterRawStatus !== "idle") return false;
|
|
11864
|
+
if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
|
|
11865
|
+
return true;
|
|
11866
|
+
}
|
|
11867
|
+
function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
11868
|
+
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
11869
|
+
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
11870
|
+
}
|
|
11871
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
11872
|
+
if (status !== "idle") return messages;
|
|
11873
|
+
return messages.map((message) => {
|
|
11874
|
+
const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
11875
|
+
const hasStreamingMeta = meta?.streaming === true;
|
|
11876
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
11877
|
+
return {
|
|
11878
|
+
...message,
|
|
11879
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
11880
|
+
...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
|
|
11881
|
+
};
|
|
11882
|
+
});
|
|
11883
|
+
}
|
|
11707
11884
|
function buildReadChatCommandResult(payload, args) {
|
|
11708
11885
|
let validatedPayload;
|
|
11709
11886
|
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
@@ -11852,7 +12029,7 @@ function buildDebugBundleText(bundle) {
|
|
|
11852
12029
|
}
|
|
11853
12030
|
function getChatDebugBundleDir() {
|
|
11854
12031
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
11855
|
-
return override ||
|
|
12032
|
+
return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
11856
12033
|
}
|
|
11857
12034
|
function safeBundleIdSegment(value, fallback) {
|
|
11858
12035
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -11885,7 +12062,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
11885
12062
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
11886
12063
|
const dir = getChatDebugBundleDir();
|
|
11887
12064
|
fs4.mkdirSync(dir, { recursive: true });
|
|
11888
|
-
const savedPath =
|
|
12065
|
+
const savedPath = path12.join(dir, `${bundleId}.json`);
|
|
11889
12066
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
11890
12067
|
`;
|
|
11891
12068
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -12142,10 +12319,13 @@ async function handleReadChat(h, args) {
|
|
|
12142
12319
|
const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
12143
12320
|
const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
12144
12321
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
12145
|
-
const returnedStatus = parsedRecord.status
|
|
12146
|
-
|
|
12322
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
12323
|
+
const runtimeMessageMerger = getTargetInstance(h, args);
|
|
12324
|
+
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
|
|
12325
|
+
const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
|
|
12326
|
+
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
12327
|
return buildReadChatCommandResult({
|
|
12148
|
-
messages:
|
|
12328
|
+
messages: returnedMessages,
|
|
12149
12329
|
status: returnedStatus,
|
|
12150
12330
|
activeModal,
|
|
12151
12331
|
debugReadChat: {
|
|
@@ -12156,7 +12336,7 @@ async function handleReadChat(h, args) {
|
|
|
12156
12336
|
returnedStatus: String(returnedStatus || ""),
|
|
12157
12337
|
shouldPreferAdapterMessages: false,
|
|
12158
12338
|
parsedMsgCount: parsedRecord.messages.length,
|
|
12159
|
-
returnedMsgCount:
|
|
12339
|
+
returnedMsgCount: returnedMessages.length
|
|
12160
12340
|
},
|
|
12161
12341
|
...title ? { title } : {},
|
|
12162
12342
|
...providerSessionId ? { providerSessionId } : {},
|
|
@@ -13029,7 +13209,7 @@ async function handleResolveAction(h, args) {
|
|
|
13029
13209
|
|
|
13030
13210
|
// src/commands/cdp-commands.ts
|
|
13031
13211
|
import * as fs5 from "fs";
|
|
13032
|
-
import * as
|
|
13212
|
+
import * as path13 from "path";
|
|
13033
13213
|
import * as os7 from "os";
|
|
13034
13214
|
var KEY_TO_VK = {
|
|
13035
13215
|
Backspace: 8,
|
|
@@ -13286,25 +13466,25 @@ function resolveSafePath(requestedPath) {
|
|
|
13286
13466
|
const inputPath = rawPath || ".";
|
|
13287
13467
|
const home = os7.homedir();
|
|
13288
13468
|
if (inputPath.startsWith("~")) {
|
|
13289
|
-
return
|
|
13469
|
+
return path13.resolve(path13.join(home, inputPath.slice(1)));
|
|
13290
13470
|
}
|
|
13291
13471
|
if (process.platform === "win32") {
|
|
13292
13472
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
13293
|
-
if (
|
|
13294
|
-
return
|
|
13473
|
+
if (path13.win32.isAbsolute(normalized)) {
|
|
13474
|
+
return path13.win32.normalize(normalized);
|
|
13295
13475
|
}
|
|
13296
|
-
return
|
|
13476
|
+
return path13.win32.resolve(normalized);
|
|
13297
13477
|
}
|
|
13298
|
-
if (
|
|
13299
|
-
return
|
|
13478
|
+
if (path13.isAbsolute(inputPath)) {
|
|
13479
|
+
return path13.normalize(inputPath);
|
|
13300
13480
|
}
|
|
13301
|
-
return
|
|
13481
|
+
return path13.resolve(inputPath);
|
|
13302
13482
|
}
|
|
13303
13483
|
function listDirectoryEntriesSafe(dirPath) {
|
|
13304
13484
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
13305
13485
|
const files = [];
|
|
13306
13486
|
for (const entry of entries) {
|
|
13307
|
-
const entryPath =
|
|
13487
|
+
const entryPath = path13.join(dirPath, entry.name);
|
|
13308
13488
|
try {
|
|
13309
13489
|
if (entry.isDirectory()) {
|
|
13310
13490
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -13358,7 +13538,7 @@ async function handleFileRead(h, args) {
|
|
|
13358
13538
|
async function handleFileWrite(h, args) {
|
|
13359
13539
|
try {
|
|
13360
13540
|
const filePath = resolveSafePath(args?.path);
|
|
13361
|
-
fs5.mkdirSync(
|
|
13541
|
+
fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
13362
13542
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
13363
13543
|
return { success: true, path: filePath };
|
|
13364
13544
|
} catch (e) {
|
|
@@ -14478,16 +14658,16 @@ var DaemonCommandHandler = class {
|
|
|
14478
14658
|
// src/commands/cli-manager.ts
|
|
14479
14659
|
init_provider_cli_adapter();
|
|
14480
14660
|
import * as os13 from "os";
|
|
14481
|
-
import * as
|
|
14661
|
+
import * as path17 from "path";
|
|
14482
14662
|
import * as crypto4 from "crypto";
|
|
14483
|
-
import { existsSync as
|
|
14663
|
+
import { existsSync as existsSync12 } from "fs";
|
|
14484
14664
|
import { execFileSync } from "child_process";
|
|
14485
14665
|
import chalk from "chalk";
|
|
14486
14666
|
init_config();
|
|
14487
14667
|
|
|
14488
14668
|
// src/providers/cli-provider-instance.ts
|
|
14489
14669
|
import * as os12 from "os";
|
|
14490
|
-
import * as
|
|
14670
|
+
import * as path16 from "path";
|
|
14491
14671
|
import * as crypto3 from "crypto";
|
|
14492
14672
|
import * as fs6 from "fs";
|
|
14493
14673
|
import { createRequire } from "module";
|
|
@@ -14546,7 +14726,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
14546
14726
|
var CachedDatabaseSync = null;
|
|
14547
14727
|
function getDatabaseSync() {
|
|
14548
14728
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
14549
|
-
const requireFn = typeof __require === "function" ? __require : createRequire(
|
|
14729
|
+
const requireFn = typeof __require === "function" ? __require : createRequire(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
14550
14730
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
14551
14731
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
14552
14732
|
if (!CachedDatabaseSync) {
|
|
@@ -14599,7 +14779,7 @@ var CliProviderInstance = class {
|
|
|
14599
14779
|
this.providerSessionId = options?.providerSessionId;
|
|
14600
14780
|
this.launchMode = options?.launchMode || "new";
|
|
14601
14781
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
14602
|
-
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
|
|
14782
|
+
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
14603
14783
|
this.monitor = new StatusMonitor();
|
|
14604
14784
|
this.historyWriter = new ChatHistoryWriter();
|
|
14605
14785
|
}
|
|
@@ -15283,6 +15463,9 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15283
15463
|
);
|
|
15284
15464
|
}
|
|
15285
15465
|
}
|
|
15466
|
+
mergeRuntimeChatMessages(parsedMessages) {
|
|
15467
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
15468
|
+
}
|
|
15286
15469
|
mergeConversationMessages(parsedMessages) {
|
|
15287
15470
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
15288
15471
|
return normalizeChatMessages([...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b) => {
|
|
@@ -16617,17 +16800,17 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
16617
16800
|
// src/commands/cli-manager.ts
|
|
16618
16801
|
function isExplicitCommand(command) {
|
|
16619
16802
|
const trimmed = command.trim();
|
|
16620
|
-
return
|
|
16803
|
+
return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
16621
16804
|
}
|
|
16622
16805
|
function expandExecutable(command) {
|
|
16623
16806
|
const trimmed = command.trim();
|
|
16624
|
-
return trimmed.startsWith("~") ?
|
|
16807
|
+
return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
16625
16808
|
}
|
|
16626
16809
|
function commandExists(command) {
|
|
16627
16810
|
const trimmed = command.trim();
|
|
16628
16811
|
if (!trimmed) return false;
|
|
16629
16812
|
if (isExplicitCommand(trimmed)) {
|
|
16630
|
-
return
|
|
16813
|
+
return existsSync12(expandExecutable(trimmed));
|
|
16631
16814
|
}
|
|
16632
16815
|
try {
|
|
16633
16816
|
execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -16815,7 +16998,7 @@ var DaemonCliManager = class {
|
|
|
16815
16998
|
attachExisting
|
|
16816
16999
|
}) || void 0;
|
|
16817
17000
|
}
|
|
16818
|
-
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
|
|
17001
|
+
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
|
|
16819
17002
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16820
17003
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
16821
17004
|
if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
|
|
@@ -16829,7 +17012,7 @@ var DaemonCliManager = class {
|
|
|
16829
17012
|
providerSessionId,
|
|
16830
17013
|
attachExisting
|
|
16831
17014
|
);
|
|
16832
|
-
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
|
|
17015
|
+
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
16833
17016
|
}
|
|
16834
17017
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
16835
17018
|
}
|
|
@@ -16902,7 +17085,7 @@ var DaemonCliManager = class {
|
|
|
16902
17085
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
16903
17086
|
const trimmed = (workingDir || "").trim();
|
|
16904
17087
|
if (!trimmed) throw new Error("working directory required");
|
|
16905
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17088
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
|
|
16906
17089
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16907
17090
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
16908
17091
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -17032,6 +17215,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17032
17215
|
{
|
|
17033
17216
|
providerSessionId: sessionBinding.providerSessionId,
|
|
17034
17217
|
launchMode: sessionBinding.launchMode,
|
|
17218
|
+
extraEnv: options?.extraEnv,
|
|
17035
17219
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
17036
17220
|
this.persistRecentActivity({
|
|
17037
17221
|
kind: "cli",
|
|
@@ -17052,7 +17236,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17052
17236
|
resolvedCliArgs,
|
|
17053
17237
|
key,
|
|
17054
17238
|
sessionBinding.providerSessionId,
|
|
17055
|
-
false
|
|
17239
|
+
false,
|
|
17240
|
+
options?.extraEnv
|
|
17056
17241
|
);
|
|
17057
17242
|
try {
|
|
17058
17243
|
await adapter.spawn();
|
|
@@ -17281,7 +17466,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17281
17466
|
dir,
|
|
17282
17467
|
args?.cliArgs,
|
|
17283
17468
|
args?.initialModel,
|
|
17284
|
-
{ resumeSessionId: args?.resumeSessionId, settingsOverride: args?.settings }
|
|
17469
|
+
{ resumeSessionId: args?.resumeSessionId, settingsOverride: args?.settings, extraEnv: args?.env }
|
|
17285
17470
|
);
|
|
17286
17471
|
return {
|
|
17287
17472
|
success: true,
|
|
@@ -17403,11 +17588,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17403
17588
|
import { execSync as execSync4, spawn as spawn2 } from "child_process";
|
|
17404
17589
|
import * as net from "net";
|
|
17405
17590
|
import * as os15 from "os";
|
|
17406
|
-
import * as
|
|
17591
|
+
import * as path19 from "path";
|
|
17407
17592
|
|
|
17408
17593
|
// src/providers/provider-loader.ts
|
|
17409
17594
|
import * as fs7 from "fs";
|
|
17410
|
-
import * as
|
|
17595
|
+
import * as path18 from "path";
|
|
17411
17596
|
import * as os14 from "os";
|
|
17412
17597
|
import * as chokidar from "chokidar";
|
|
17413
17598
|
init_logger();
|
|
@@ -17731,7 +17916,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17731
17916
|
try {
|
|
17732
17917
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
17733
17918
|
return ["ide", "extension", "cli", "acp"].some(
|
|
17734
|
-
(category) => fs7.existsSync(
|
|
17919
|
+
(category) => fs7.existsSync(path18.join(candidate, category))
|
|
17735
17920
|
);
|
|
17736
17921
|
} catch {
|
|
17737
17922
|
return false;
|
|
@@ -17739,20 +17924,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17739
17924
|
}
|
|
17740
17925
|
static hasProviderRootMarker(candidate) {
|
|
17741
17926
|
try {
|
|
17742
|
-
return fs7.existsSync(
|
|
17927
|
+
return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
17743
17928
|
} catch {
|
|
17744
17929
|
return false;
|
|
17745
17930
|
}
|
|
17746
17931
|
}
|
|
17747
17932
|
detectDefaultUserDir() {
|
|
17748
|
-
const fallback =
|
|
17933
|
+
const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17749
17934
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17750
17935
|
const visited = /* @__PURE__ */ new Set();
|
|
17751
17936
|
for (const start of this.probeStarts) {
|
|
17752
|
-
let current =
|
|
17937
|
+
let current = path18.resolve(start);
|
|
17753
17938
|
while (!visited.has(current)) {
|
|
17754
17939
|
visited.add(current);
|
|
17755
|
-
const siblingCandidate =
|
|
17940
|
+
const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17756
17941
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17757
17942
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17758
17943
|
if (envOptIn || hasMarker) {
|
|
@@ -17774,7 +17959,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17774
17959
|
return { path: siblingCandidate, source };
|
|
17775
17960
|
}
|
|
17776
17961
|
}
|
|
17777
|
-
const parent =
|
|
17962
|
+
const parent = path18.dirname(current);
|
|
17778
17963
|
if (parent === current) break;
|
|
17779
17964
|
current = parent;
|
|
17780
17965
|
}
|
|
@@ -17784,11 +17969,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17784
17969
|
constructor(options) {
|
|
17785
17970
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17786
17971
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17787
|
-
this.defaultProvidersDir =
|
|
17972
|
+
this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17788
17973
|
const detected = this.detectDefaultUserDir();
|
|
17789
17974
|
this.userDir = detected.path;
|
|
17790
17975
|
this.userDirSource = detected.source;
|
|
17791
|
-
this.upstreamDir =
|
|
17976
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17792
17977
|
this.disableUpstream = false;
|
|
17793
17978
|
this.applySourceConfig({
|
|
17794
17979
|
userDir: options?.userDir,
|
|
@@ -17847,7 +18032,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17847
18032
|
this.userDir = detected.path;
|
|
17848
18033
|
this.userDirSource = detected.source;
|
|
17849
18034
|
}
|
|
17850
|
-
this.upstreamDir =
|
|
18035
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17851
18036
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
17852
18037
|
if (this.explicitProviderDir) {
|
|
17853
18038
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -17861,7 +18046,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17861
18046
|
* Canonical provider directory shape for a given root.
|
|
17862
18047
|
*/
|
|
17863
18048
|
getProviderDir(root, category, type) {
|
|
17864
|
-
return
|
|
18049
|
+
return path18.join(root, category, type);
|
|
17865
18050
|
}
|
|
17866
18051
|
/**
|
|
17867
18052
|
* Canonical user override directory for a provider.
|
|
@@ -17888,7 +18073,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17888
18073
|
resolveProviderFile(type, ...segments) {
|
|
17889
18074
|
const dir = this.findProviderDirInternal(type);
|
|
17890
18075
|
if (!dir) return null;
|
|
17891
|
-
return
|
|
18076
|
+
return path18.join(dir, ...segments);
|
|
17892
18077
|
}
|
|
17893
18078
|
/**
|
|
17894
18079
|
* Load all providers (3-tier priority)
|
|
@@ -17927,7 +18112,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17927
18112
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
17928
18113
|
try {
|
|
17929
18114
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
17930
|
-
(d) => fs7.statSync(
|
|
18115
|
+
(d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
|
|
17931
18116
|
);
|
|
17932
18117
|
} catch {
|
|
17933
18118
|
return false;
|
|
@@ -18424,8 +18609,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18424
18609
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
18425
18610
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
18426
18611
|
if (providerDir) {
|
|
18427
|
-
const fullDir =
|
|
18428
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18612
|
+
const fullDir = path18.join(providerDir, entry.scriptDir);
|
|
18613
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18429
18614
|
}
|
|
18430
18615
|
matched = true;
|
|
18431
18616
|
}
|
|
@@ -18440,8 +18625,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18440
18625
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18441
18626
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
18442
18627
|
if (providerDir) {
|
|
18443
|
-
const fullDir =
|
|
18444
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18628
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18629
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18445
18630
|
}
|
|
18446
18631
|
}
|
|
18447
18632
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -18458,8 +18643,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18458
18643
|
resolved._resolvedScriptDir = dirOverride;
|
|
18459
18644
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
18460
18645
|
if (providerDir) {
|
|
18461
|
-
const fullDir =
|
|
18462
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18646
|
+
const fullDir = path18.join(providerDir, dirOverride);
|
|
18647
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18463
18648
|
}
|
|
18464
18649
|
}
|
|
18465
18650
|
} else if (override.scripts) {
|
|
@@ -18475,8 +18660,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18475
18660
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18476
18661
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
18477
18662
|
if (providerDir) {
|
|
18478
|
-
const fullDir =
|
|
18479
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18663
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
18664
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18480
18665
|
}
|
|
18481
18666
|
}
|
|
18482
18667
|
}
|
|
@@ -18508,14 +18693,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18508
18693
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
18509
18694
|
return null;
|
|
18510
18695
|
}
|
|
18511
|
-
const dir =
|
|
18696
|
+
const dir = path18.join(providerDir, scriptDir);
|
|
18512
18697
|
if (!fs7.existsSync(dir)) {
|
|
18513
18698
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
18514
18699
|
return null;
|
|
18515
18700
|
}
|
|
18516
18701
|
const cached = this.scriptsCache.get(dir);
|
|
18517
18702
|
if (cached) return cached;
|
|
18518
|
-
const scriptsJs =
|
|
18703
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
18519
18704
|
if (fs7.existsSync(scriptsJs)) {
|
|
18520
18705
|
try {
|
|
18521
18706
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -18557,7 +18742,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18557
18742
|
return;
|
|
18558
18743
|
}
|
|
18559
18744
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
18560
|
-
this.log(`File changed: ${
|
|
18745
|
+
this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
|
|
18561
18746
|
this.reload();
|
|
18562
18747
|
}
|
|
18563
18748
|
};
|
|
@@ -18612,7 +18797,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18612
18797
|
}
|
|
18613
18798
|
const https = __require("https");
|
|
18614
18799
|
const { execSync: execSync7 } = __require("child_process");
|
|
18615
|
-
const metaPath =
|
|
18800
|
+
const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
18616
18801
|
let prevEtag = "";
|
|
18617
18802
|
let prevTimestamp = 0;
|
|
18618
18803
|
try {
|
|
@@ -18672,17 +18857,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18672
18857
|
return { updated: false };
|
|
18673
18858
|
}
|
|
18674
18859
|
this.log("Downloading latest providers from GitHub...");
|
|
18675
|
-
const tmpTar =
|
|
18676
|
-
const tmpExtract =
|
|
18860
|
+
const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
18861
|
+
const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
18677
18862
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
18678
18863
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
18679
18864
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
18680
18865
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
18681
18866
|
const rootDir = extracted.find(
|
|
18682
|
-
(d) => fs7.statSync(
|
|
18867
|
+
(d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
18683
18868
|
);
|
|
18684
18869
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
18685
|
-
const sourceDir =
|
|
18870
|
+
const sourceDir = path18.join(tmpExtract, rootDir);
|
|
18686
18871
|
const backupDir = this.upstreamDir + ".bak";
|
|
18687
18872
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
18688
18873
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -18757,8 +18942,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18757
18942
|
copyDirRecursive(src, dest) {
|
|
18758
18943
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18759
18944
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18760
|
-
const srcPath =
|
|
18761
|
-
const destPath =
|
|
18945
|
+
const srcPath = path18.join(src, entry.name);
|
|
18946
|
+
const destPath = path18.join(dest, entry.name);
|
|
18762
18947
|
if (entry.isDirectory()) {
|
|
18763
18948
|
this.copyDirRecursive(srcPath, destPath);
|
|
18764
18949
|
} else {
|
|
@@ -18769,7 +18954,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18769
18954
|
/** .meta.json save */
|
|
18770
18955
|
writeMeta(metaPath, etag, timestamp) {
|
|
18771
18956
|
try {
|
|
18772
|
-
fs7.mkdirSync(
|
|
18957
|
+
fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
|
|
18773
18958
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18774
18959
|
etag,
|
|
18775
18960
|
timestamp,
|
|
@@ -18786,7 +18971,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18786
18971
|
const scan = (d) => {
|
|
18787
18972
|
try {
|
|
18788
18973
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18789
|
-
if (entry.isDirectory()) scan(
|
|
18974
|
+
if (entry.isDirectory()) scan(path18.join(d, entry.name));
|
|
18790
18975
|
else if (entry.name === "provider.json") count++;
|
|
18791
18976
|
}
|
|
18792
18977
|
} catch {
|
|
@@ -19014,17 +19199,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19014
19199
|
for (const root of searchRoots) {
|
|
19015
19200
|
if (!fs7.existsSync(root)) continue;
|
|
19016
19201
|
const candidate = this.getProviderDir(root, cat, type);
|
|
19017
|
-
if (fs7.existsSync(
|
|
19018
|
-
const catDir =
|
|
19202
|
+
if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
|
|
19203
|
+
const catDir = path18.join(root, cat);
|
|
19019
19204
|
if (fs7.existsSync(catDir)) {
|
|
19020
19205
|
try {
|
|
19021
19206
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
19022
19207
|
if (!entry.isDirectory()) continue;
|
|
19023
|
-
const jsonPath =
|
|
19208
|
+
const jsonPath = path18.join(catDir, entry.name, "provider.json");
|
|
19024
19209
|
if (fs7.existsSync(jsonPath)) {
|
|
19025
19210
|
try {
|
|
19026
19211
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
19027
|
-
if (data.type === type) return
|
|
19212
|
+
if (data.type === type) return path18.join(catDir, entry.name);
|
|
19028
19213
|
} catch {
|
|
19029
19214
|
}
|
|
19030
19215
|
}
|
|
@@ -19041,7 +19226,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19041
19226
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
19042
19227
|
*/
|
|
19043
19228
|
buildScriptWrappersFromDir(dir) {
|
|
19044
|
-
const scriptsJs =
|
|
19229
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
19045
19230
|
if (fs7.existsSync(scriptsJs)) {
|
|
19046
19231
|
try {
|
|
19047
19232
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -19055,7 +19240,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19055
19240
|
for (const file of fs7.readdirSync(dir)) {
|
|
19056
19241
|
if (!file.endsWith(".js")) continue;
|
|
19057
19242
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
19058
|
-
const filePath =
|
|
19243
|
+
const filePath = path18.join(dir, file);
|
|
19059
19244
|
result[scriptName] = (...args) => {
|
|
19060
19245
|
try {
|
|
19061
19246
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -19115,7 +19300,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19115
19300
|
}
|
|
19116
19301
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
19117
19302
|
if (hasJson) {
|
|
19118
|
-
const jsonPath =
|
|
19303
|
+
const jsonPath = path18.join(d, "provider.json");
|
|
19119
19304
|
try {
|
|
19120
19305
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
19121
19306
|
const mod = JSON.parse(raw);
|
|
@@ -19136,7 +19321,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19136
19321
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
19137
19322
|
} else {
|
|
19138
19323
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
19139
|
-
const scriptsPath =
|
|
19324
|
+
const scriptsPath = path18.join(d, "scripts.js");
|
|
19140
19325
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
19141
19326
|
try {
|
|
19142
19327
|
delete __require.cache[__require.resolve(scriptsPath)];
|
|
@@ -19162,7 +19347,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19162
19347
|
if (!entry.isDirectory()) continue;
|
|
19163
19348
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
19164
19349
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
19165
|
-
scan(
|
|
19350
|
+
scan(path18.join(d, entry.name));
|
|
19166
19351
|
}
|
|
19167
19352
|
}
|
|
19168
19353
|
};
|
|
@@ -19487,8 +19672,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
19487
19672
|
const appNameMap = getMacAppIdentifiers();
|
|
19488
19673
|
const appName = appNameMap[ideId];
|
|
19489
19674
|
if (appName) {
|
|
19490
|
-
const storagePath =
|
|
19491
|
-
process.env.APPDATA ||
|
|
19675
|
+
const storagePath = path19.join(
|
|
19676
|
+
process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
|
|
19492
19677
|
appName,
|
|
19493
19678
|
"storage.json"
|
|
19494
19679
|
);
|
|
@@ -19677,9 +19862,9 @@ init_logger();
|
|
|
19677
19862
|
|
|
19678
19863
|
// src/logging/command-log.ts
|
|
19679
19864
|
import * as fs8 from "fs";
|
|
19680
|
-
import * as
|
|
19865
|
+
import * as path20 from "path";
|
|
19681
19866
|
import * as os16 from "os";
|
|
19682
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
19867
|
+
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
19868
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
19684
19869
|
var MAX_DAYS = 7;
|
|
19685
19870
|
try {
|
|
@@ -19717,13 +19902,13 @@ function getDateStr2() {
|
|
|
19717
19902
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19718
19903
|
}
|
|
19719
19904
|
var currentDate2 = getDateStr2();
|
|
19720
|
-
var currentFile =
|
|
19905
|
+
var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19721
19906
|
var writeCount2 = 0;
|
|
19722
19907
|
function checkRotation() {
|
|
19723
19908
|
const today = getDateStr2();
|
|
19724
19909
|
if (today !== currentDate2) {
|
|
19725
19910
|
currentDate2 = today;
|
|
19726
|
-
currentFile =
|
|
19911
|
+
currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19727
19912
|
cleanOldFiles();
|
|
19728
19913
|
}
|
|
19729
19914
|
}
|
|
@@ -19737,7 +19922,7 @@ function cleanOldFiles() {
|
|
|
19737
19922
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
19738
19923
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
19739
19924
|
try {
|
|
19740
|
-
fs8.unlinkSync(
|
|
19925
|
+
fs8.unlinkSync(path20.join(LOG_DIR2, file));
|
|
19741
19926
|
} catch {
|
|
19742
19927
|
}
|
|
19743
19928
|
}
|
|
@@ -19821,13 +20006,65 @@ cleanOldFiles();
|
|
|
19821
20006
|
|
|
19822
20007
|
// src/commands/router.ts
|
|
19823
20008
|
init_logger();
|
|
20009
|
+
import * as yaml from "js-yaml";
|
|
19824
20010
|
|
|
19825
20011
|
// src/commands/mesh-coordinator.ts
|
|
19826
|
-
import {
|
|
20012
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
20013
|
+
import { existsSync as existsSync15, readdirSync as readdirSync6, realpathSync as realpathSync2 } from "fs";
|
|
19827
20014
|
import { createRequire as createRequire2 } from "module";
|
|
19828
|
-
import
|
|
20015
|
+
import * as os17 from "os";
|
|
20016
|
+
import { dirname as dirname4, isAbsolute as isAbsolute10, join as join18, resolve as resolve13 } from "path";
|
|
19829
20017
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
19830
20018
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20019
|
+
var HERMES_CLI_TYPE = "hermes-cli";
|
|
20020
|
+
var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
|
|
20021
|
+
function isHermesProvider(provider, cliType) {
|
|
20022
|
+
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
20023
|
+
return type === HERMES_CLI_TYPE;
|
|
20024
|
+
}
|
|
20025
|
+
function resolveHermesMeshCoordinatorSetup(options) {
|
|
20026
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
20027
|
+
meshId: options.meshId,
|
|
20028
|
+
nodeExecutable: options.nodeExecutable,
|
|
20029
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath
|
|
20030
|
+
});
|
|
20031
|
+
if (!mcpServer) {
|
|
20032
|
+
return {
|
|
20033
|
+
kind: "unsupported",
|
|
20034
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20035
|
+
};
|
|
20036
|
+
}
|
|
20037
|
+
const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
|
|
20038
|
+
if (!configPath.trim()) {
|
|
20039
|
+
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20040
|
+
}
|
|
20041
|
+
return {
|
|
20042
|
+
kind: "auto_import",
|
|
20043
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20044
|
+
configPath,
|
|
20045
|
+
configFormat: "hermes_config_yaml",
|
|
20046
|
+
mcpServer
|
|
20047
|
+
};
|
|
20048
|
+
}
|
|
20049
|
+
function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
|
|
20050
|
+
return {
|
|
20051
|
+
kind: "manual",
|
|
20052
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20053
|
+
configFormat: "hermes_config_yaml",
|
|
20054
|
+
configPathCommand: HERMES_MCP_CONFIG_PATH,
|
|
20055
|
+
requiresRestart: true,
|
|
20056
|
+
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.",
|
|
20057
|
+
template: renderMeshCoordinatorTemplate(
|
|
20058
|
+
"mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
|
|
20059
|
+
{
|
|
20060
|
+
meshId,
|
|
20061
|
+
workspace,
|
|
20062
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20063
|
+
adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
|
|
20064
|
+
}
|
|
20065
|
+
)
|
|
20066
|
+
};
|
|
20067
|
+
}
|
|
19831
20068
|
function resolveMeshCoordinatorSetup(options) {
|
|
19832
20069
|
const { provider, meshId, workspace } = options;
|
|
19833
20070
|
const config = provider?.meshCoordinator;
|
|
@@ -19837,6 +20074,9 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19837
20074
|
reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
|
|
19838
20075
|
};
|
|
19839
20076
|
}
|
|
20077
|
+
if (isHermesProvider(provider, options.cliType)) {
|
|
20078
|
+
return resolveHermesMeshCoordinatorSetup(options);
|
|
20079
|
+
}
|
|
19840
20080
|
const mcpConfig = config.mcpConfig;
|
|
19841
20081
|
if (!mcpConfig || mcpConfig.mode === "none") {
|
|
19842
20082
|
return {
|
|
@@ -19846,8 +20086,8 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19846
20086
|
}
|
|
19847
20087
|
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
|
|
19848
20088
|
if (mcpConfig.mode === "auto_import") {
|
|
19849
|
-
const
|
|
19850
|
-
if (!
|
|
20089
|
+
const path27 = mcpConfig.path?.trim();
|
|
20090
|
+
if (!path27) {
|
|
19851
20091
|
return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
|
|
19852
20092
|
}
|
|
19853
20093
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
@@ -19858,13 +20098,13 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19858
20098
|
if (!mcpServer) {
|
|
19859
20099
|
return {
|
|
19860
20100
|
kind: "unsupported",
|
|
19861
|
-
reason: "Could not resolve the ADHDev MCP server entrypoint
|
|
20101
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
19862
20102
|
};
|
|
19863
20103
|
}
|
|
19864
20104
|
return {
|
|
19865
20105
|
kind: "auto_import",
|
|
19866
20106
|
serverName,
|
|
19867
|
-
configPath:
|
|
20107
|
+
configPath: resolveMcpConfigPath(path27, workspace),
|
|
19868
20108
|
configFormat: mcpConfig.format,
|
|
19869
20109
|
mcpServer
|
|
19870
20110
|
};
|
|
@@ -19898,13 +20138,84 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
19898
20138
|
function renderMeshCoordinatorTemplate(template, values) {
|
|
19899
20139
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
|
|
19900
20140
|
}
|
|
20141
|
+
function resolveMcpConfigPath(configPath, workspace) {
|
|
20142
|
+
const trimmed = configPath.trim();
|
|
20143
|
+
if (trimmed === "~") return os17.homedir();
|
|
20144
|
+
if (trimmed.startsWith("~/")) return join18(os17.homedir(), trimmed.slice(2));
|
|
20145
|
+
if (isAbsolute10(trimmed)) return trimmed;
|
|
20146
|
+
return join18(workspace, trimmed);
|
|
20147
|
+
}
|
|
19901
20148
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
19902
20149
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
19903
20150
|
if (!entryPath) return null;
|
|
20151
|
+
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
|
|
20152
|
+
if (!nodeExecutable) return null;
|
|
19904
20153
|
return {
|
|
19905
|
-
command:
|
|
19906
|
-
args: [entryPath, "--repo-mesh", options.meshId]
|
|
20154
|
+
command: nodeExecutable,
|
|
20155
|
+
args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
|
|
20156
|
+
};
|
|
20157
|
+
}
|
|
20158
|
+
function resolveMcpNodeExecutable(explicitExecutable) {
|
|
20159
|
+
const explicit = explicitExecutable?.trim();
|
|
20160
|
+
if (explicit) return explicit;
|
|
20161
|
+
const candidates = [];
|
|
20162
|
+
const addCandidate = (candidate) => {
|
|
20163
|
+
const trimmed = candidate?.trim();
|
|
20164
|
+
if (!trimmed) return;
|
|
20165
|
+
const normalized = normalizeExistingPath(trimmed) || trimmed;
|
|
20166
|
+
if (!candidates.includes(normalized)) candidates.push(normalized);
|
|
19907
20167
|
};
|
|
20168
|
+
addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
|
|
20169
|
+
addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
|
|
20170
|
+
addCandidate(process.env.npm_node_execpath);
|
|
20171
|
+
addNodeCandidatesFromPath(process.env.PATH, addCandidate);
|
|
20172
|
+
addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
|
|
20173
|
+
addCandidate("/opt/homebrew/bin/node");
|
|
20174
|
+
addCandidate("/usr/local/bin/node");
|
|
20175
|
+
addCandidate("/usr/bin/node");
|
|
20176
|
+
addCandidate(process.execPath);
|
|
20177
|
+
for (const candidate of candidates) {
|
|
20178
|
+
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
|
|
20179
|
+
}
|
|
20180
|
+
return null;
|
|
20181
|
+
}
|
|
20182
|
+
function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
20183
|
+
for (const entry of (pathValue || "").split(":")) {
|
|
20184
|
+
const dir = entry.trim();
|
|
20185
|
+
if (!dir) continue;
|
|
20186
|
+
addCandidate(join18(dir, "node"));
|
|
20187
|
+
}
|
|
20188
|
+
}
|
|
20189
|
+
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
20190
|
+
const versionsDir = join18(homeDir, ".nvm", "versions", "node");
|
|
20191
|
+
try {
|
|
20192
|
+
const versionDirs = readdirSync6(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
20193
|
+
for (const versionDir of versionDirs) {
|
|
20194
|
+
addCandidate(join18(versionsDir, versionDir, "bin", "node"));
|
|
20195
|
+
}
|
|
20196
|
+
} catch {
|
|
20197
|
+
}
|
|
20198
|
+
}
|
|
20199
|
+
function compareNodeVersionNamesDescending(a, b) {
|
|
20200
|
+
const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
20201
|
+
const left = parse(a);
|
|
20202
|
+
const right = parse(b);
|
|
20203
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
20204
|
+
const diff = (right[i] || 0) - (left[i] || 0);
|
|
20205
|
+
if (diff !== 0) return diff;
|
|
20206
|
+
}
|
|
20207
|
+
return b.localeCompare(a);
|
|
20208
|
+
}
|
|
20209
|
+
function nodeRuntimeSupportsWebSocket(nodeExecutable) {
|
|
20210
|
+
try {
|
|
20211
|
+
execFileSync2(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
|
|
20212
|
+
stdio: "ignore",
|
|
20213
|
+
timeout: 3e3
|
|
20214
|
+
});
|
|
20215
|
+
return true;
|
|
20216
|
+
} catch {
|
|
20217
|
+
return false;
|
|
20218
|
+
}
|
|
19908
20219
|
}
|
|
19909
20220
|
function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
19910
20221
|
const explicit = explicitPath?.trim();
|
|
@@ -19918,7 +20229,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19918
20229
|
const addPackagedCandidates = (baseFile) => {
|
|
19919
20230
|
if (!baseFile) return;
|
|
19920
20231
|
const realBase = normalizeExistingPath(baseFile) || baseFile;
|
|
19921
|
-
const dir =
|
|
20232
|
+
const dir = dirname4(realBase);
|
|
19922
20233
|
addCandidate(resolve13(dir, "../vendor/mcp-server/index.js"));
|
|
19923
20234
|
addCandidate(resolve13(dir, "../../vendor/mcp-server/index.js"));
|
|
19924
20235
|
addCandidate(resolve13(dir, "../../../vendor/mcp-server/index.js"));
|
|
@@ -19931,7 +20242,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19931
20242
|
if (normalized) return normalized;
|
|
19932
20243
|
}
|
|
19933
20244
|
try {
|
|
19934
|
-
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] :
|
|
20245
|
+
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join18(process.cwd(), "adhdev-daemon.js");
|
|
19935
20246
|
const req = createRequire2(requireBase);
|
|
19936
20247
|
const resolvedModule = req.resolve("@adhdev/mcp-server");
|
|
19937
20248
|
return normalizeExistingPath(resolvedModule) || resolvedModule;
|
|
@@ -19941,7 +20252,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
19941
20252
|
}
|
|
19942
20253
|
function normalizeExistingPath(filePath) {
|
|
19943
20254
|
try {
|
|
19944
|
-
if (!
|
|
20255
|
+
if (!existsSync15(filePath)) return null;
|
|
19945
20256
|
return realpathSync2.native(filePath);
|
|
19946
20257
|
} catch {
|
|
19947
20258
|
return null;
|
|
@@ -19950,7 +20261,7 @@ function normalizeExistingPath(filePath) {
|
|
|
19950
20261
|
|
|
19951
20262
|
// src/status/snapshot.ts
|
|
19952
20263
|
init_config();
|
|
19953
|
-
import * as
|
|
20264
|
+
import * as os18 from "os";
|
|
19954
20265
|
init_terminal_screen();
|
|
19955
20266
|
init_logger();
|
|
19956
20267
|
var READ_DEBUG_ENABLED = process.argv.includes("--dev") || process.env.ADHDEV_READ_DEBUG === "1";
|
|
@@ -20005,8 +20316,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20005
20316
|
}
|
|
20006
20317
|
function buildMachineInfo(profile = "full") {
|
|
20007
20318
|
const base = {
|
|
20008
|
-
hostname:
|
|
20009
|
-
platform:
|
|
20319
|
+
hostname: os18.hostname(),
|
|
20320
|
+
platform: os18.platform()
|
|
20010
20321
|
};
|
|
20011
20322
|
if (profile === "live") {
|
|
20012
20323
|
return base;
|
|
@@ -20015,23 +20326,23 @@ function buildMachineInfo(profile = "full") {
|
|
|
20015
20326
|
const memSnap2 = getHostMemorySnapshot();
|
|
20016
20327
|
return {
|
|
20017
20328
|
...base,
|
|
20018
|
-
arch:
|
|
20019
|
-
cpus:
|
|
20329
|
+
arch: os18.arch(),
|
|
20330
|
+
cpus: os18.cpus().length,
|
|
20020
20331
|
totalMem: memSnap2.totalMem,
|
|
20021
|
-
release:
|
|
20332
|
+
release: os18.release()
|
|
20022
20333
|
};
|
|
20023
20334
|
}
|
|
20024
20335
|
const memSnap = getHostMemorySnapshot();
|
|
20025
20336
|
return {
|
|
20026
20337
|
...base,
|
|
20027
|
-
arch:
|
|
20028
|
-
cpus:
|
|
20338
|
+
arch: os18.arch(),
|
|
20339
|
+
cpus: os18.cpus().length,
|
|
20029
20340
|
totalMem: memSnap.totalMem,
|
|
20030
20341
|
freeMem: memSnap.freeMem,
|
|
20031
20342
|
availableMem: memSnap.availableMem,
|
|
20032
|
-
loadavg:
|
|
20033
|
-
uptime:
|
|
20034
|
-
release:
|
|
20343
|
+
loadavg: os18.loadavg(),
|
|
20344
|
+
uptime: os18.uptime(),
|
|
20345
|
+
release: os18.release()
|
|
20035
20346
|
};
|
|
20036
20347
|
}
|
|
20037
20348
|
function parseMessageTime(value) {
|
|
@@ -20262,17 +20573,17 @@ function buildStatusSnapshot(options) {
|
|
|
20262
20573
|
}
|
|
20263
20574
|
|
|
20264
20575
|
// src/commands/upgrade-helper.ts
|
|
20265
|
-
import { execFileSync as
|
|
20576
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
20266
20577
|
import { spawn as spawn3 } from "child_process";
|
|
20267
20578
|
import * as fs9 from "fs";
|
|
20268
|
-
import * as
|
|
20269
|
-
import * as
|
|
20579
|
+
import * as os19 from "os";
|
|
20580
|
+
import * as path21 from "path";
|
|
20270
20581
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
20271
20582
|
function getUpgradeLogPath() {
|
|
20272
|
-
const home =
|
|
20273
|
-
const dir =
|
|
20583
|
+
const home = os19.homedir();
|
|
20584
|
+
const dir = path21.join(home, ".adhdev");
|
|
20274
20585
|
fs9.mkdirSync(dir, { recursive: true });
|
|
20275
|
-
return
|
|
20586
|
+
return path21.join(dir, "daemon-upgrade.log");
|
|
20276
20587
|
}
|
|
20277
20588
|
function appendUpgradeLog(message) {
|
|
20278
20589
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -20283,14 +20594,14 @@ function appendUpgradeLog(message) {
|
|
|
20283
20594
|
}
|
|
20284
20595
|
}
|
|
20285
20596
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
20286
|
-
const binDir =
|
|
20597
|
+
const binDir = path21.dirname(nodeExecutable);
|
|
20287
20598
|
if (platform10 === "win32") {
|
|
20288
|
-
const npmCliPath =
|
|
20599
|
+
const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
20289
20600
|
if (fs9.existsSync(npmCliPath)) {
|
|
20290
20601
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20291
20602
|
}
|
|
20292
20603
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
20293
|
-
const candidatePath =
|
|
20604
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20294
20605
|
if (fs9.existsSync(candidatePath)) {
|
|
20295
20606
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20296
20607
|
}
|
|
@@ -20298,7 +20609,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
20298
20609
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20299
20610
|
}
|
|
20300
20611
|
for (const candidate of ["npm"]) {
|
|
20301
|
-
const candidatePath =
|
|
20612
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20302
20613
|
if (fs9.existsSync(candidatePath)) {
|
|
20303
20614
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20304
20615
|
}
|
|
@@ -20315,13 +20626,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20315
20626
|
let currentDir = resolvedPath;
|
|
20316
20627
|
try {
|
|
20317
20628
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
20318
|
-
currentDir =
|
|
20629
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20319
20630
|
}
|
|
20320
20631
|
} catch {
|
|
20321
|
-
currentDir =
|
|
20632
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20322
20633
|
}
|
|
20323
20634
|
while (true) {
|
|
20324
|
-
const packageJsonPath =
|
|
20635
|
+
const packageJsonPath = path21.join(currentDir, "package.json");
|
|
20325
20636
|
try {
|
|
20326
20637
|
if (fs9.existsSync(packageJsonPath)) {
|
|
20327
20638
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -20332,7 +20643,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20332
20643
|
}
|
|
20333
20644
|
} catch {
|
|
20334
20645
|
}
|
|
20335
|
-
const parentDir =
|
|
20646
|
+
const parentDir = path21.dirname(currentDir);
|
|
20336
20647
|
if (parentDir === currentDir) {
|
|
20337
20648
|
return null;
|
|
20338
20649
|
}
|
|
@@ -20340,13 +20651,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20340
20651
|
}
|
|
20341
20652
|
}
|
|
20342
20653
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
20343
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
20344
|
-
if (
|
|
20654
|
+
const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
|
|
20655
|
+
if (path21.basename(nodeModulesDir) !== "node_modules") {
|
|
20345
20656
|
return null;
|
|
20346
20657
|
}
|
|
20347
|
-
const maybeLibDir =
|
|
20348
|
-
if (
|
|
20349
|
-
return
|
|
20658
|
+
const maybeLibDir = path21.dirname(nodeModulesDir);
|
|
20659
|
+
if (path21.basename(maybeLibDir) === "lib") {
|
|
20660
|
+
return path21.dirname(maybeLibDir);
|
|
20350
20661
|
}
|
|
20351
20662
|
return maybeLibDir;
|
|
20352
20663
|
}
|
|
@@ -20382,7 +20693,7 @@ function getNpmExecOptions(platform10 = process.platform) {
|
|
|
20382
20693
|
}
|
|
20383
20694
|
function execNpmCommandSync(args, options = {}, surface) {
|
|
20384
20695
|
const execOptions = surface?.execOptions || getNpmExecOptions();
|
|
20385
|
-
return
|
|
20696
|
+
return execFileSync3(
|
|
20386
20697
|
surface?.npmExecutable || "npm",
|
|
20387
20698
|
[...surface?.npmArgsPrefix || [], ...args],
|
|
20388
20699
|
{
|
|
@@ -20395,7 +20706,7 @@ function execNpmCommandSync(args, options = {}, surface) {
|
|
|
20395
20706
|
function killPid(pid) {
|
|
20396
20707
|
try {
|
|
20397
20708
|
if (process.platform === "win32") {
|
|
20398
|
-
|
|
20709
|
+
execFileSync3("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
|
|
20399
20710
|
} else {
|
|
20400
20711
|
process.kill(pid, "SIGTERM");
|
|
20401
20712
|
}
|
|
@@ -20407,7 +20718,7 @@ function killPid(pid) {
|
|
|
20407
20718
|
function getWindowsProcessCommandLine(pid) {
|
|
20408
20719
|
const pidFilter = `ProcessId=${pid}`;
|
|
20409
20720
|
try {
|
|
20410
|
-
const psOut =
|
|
20721
|
+
const psOut = execFileSync3("powershell.exe", [
|
|
20411
20722
|
"-NoProfile",
|
|
20412
20723
|
"-NonInteractive",
|
|
20413
20724
|
"-ExecutionPolicy",
|
|
@@ -20419,7 +20730,7 @@ function getWindowsProcessCommandLine(pid) {
|
|
|
20419
20730
|
} catch {
|
|
20420
20731
|
}
|
|
20421
20732
|
try {
|
|
20422
|
-
const wmicOut =
|
|
20733
|
+
const wmicOut = execFileSync3("wmic", [
|
|
20423
20734
|
"process",
|
|
20424
20735
|
"where",
|
|
20425
20736
|
pidFilter,
|
|
@@ -20435,7 +20746,7 @@ function getProcessCommandLine(pid) {
|
|
|
20435
20746
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
20436
20747
|
if (process.platform === "win32") return getWindowsProcessCommandLine(pid);
|
|
20437
20748
|
try {
|
|
20438
|
-
const text =
|
|
20749
|
+
const text = execFileSync3("ps", ["-o", "command=", "-p", String(pid)], {
|
|
20439
20750
|
encoding: "utf8",
|
|
20440
20751
|
timeout: 3e3,
|
|
20441
20752
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -20461,7 +20772,7 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
20461
20772
|
}
|
|
20462
20773
|
}
|
|
20463
20774
|
function stopSessionHostProcesses(appName) {
|
|
20464
|
-
const pidFile =
|
|
20775
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
20465
20776
|
try {
|
|
20466
20777
|
if (fs9.existsSync(pidFile)) {
|
|
20467
20778
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -20478,7 +20789,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
20478
20789
|
}
|
|
20479
20790
|
}
|
|
20480
20791
|
function removeDaemonPidFile() {
|
|
20481
|
-
const pidFile =
|
|
20792
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
20482
20793
|
try {
|
|
20483
20794
|
fs9.unlinkSync(pidFile);
|
|
20484
20795
|
} catch {
|
|
@@ -20489,7 +20800,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20489
20800
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20490
20801
|
if (!npmRoot) return;
|
|
20491
20802
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20492
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
20803
|
+
const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
|
|
20493
20804
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
20494
20805
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
20495
20806
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -20497,25 +20808,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20497
20808
|
}
|
|
20498
20809
|
if (pkgName.startsWith("@")) {
|
|
20499
20810
|
const [scope, name] = pkgName.split("/");
|
|
20500
|
-
const scopeDir =
|
|
20811
|
+
const scopeDir = path21.join(npmRoot, scope);
|
|
20501
20812
|
if (!fs9.existsSync(scopeDir)) return;
|
|
20502
20813
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
20503
20814
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
20504
|
-
fs9.rmSync(
|
|
20505
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
20815
|
+
fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
|
|
20816
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
|
|
20506
20817
|
}
|
|
20507
20818
|
} else {
|
|
20508
20819
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
20509
20820
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
20510
|
-
fs9.rmSync(
|
|
20511
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
20821
|
+
fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
|
|
20822
|
+
appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
|
|
20512
20823
|
}
|
|
20513
20824
|
}
|
|
20514
20825
|
if (fs9.existsSync(binDir)) {
|
|
20515
20826
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
20516
20827
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
20517
|
-
fs9.rmSync(
|
|
20518
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
20828
|
+
fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
|
|
20829
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
|
|
20519
20830
|
}
|
|
20520
20831
|
}
|
|
20521
20832
|
}
|
|
@@ -20551,7 +20862,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
20551
20862
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
20552
20863
|
const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
|
|
20553
20864
|
appendUpgradeLog(`Installing ${spec}`);
|
|
20554
|
-
const installOutput =
|
|
20865
|
+
const installOutput = execFileSync3(
|
|
20555
20866
|
installCommand.command,
|
|
20556
20867
|
installCommand.args,
|
|
20557
20868
|
{
|
|
@@ -20602,6 +20913,10 @@ async function maybeRunDaemonUpgradeHelperFromEnv() {
|
|
|
20602
20913
|
// src/commands/router.ts
|
|
20603
20914
|
import * as fs10 from "fs";
|
|
20604
20915
|
var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
|
|
20916
|
+
var CHANNEL_SERVER_URL = {
|
|
20917
|
+
stable: "https://api.adhf.dev",
|
|
20918
|
+
preview: "https://api-preview.adhf.dev"
|
|
20919
|
+
};
|
|
20605
20920
|
function normalizeReleaseChannel(value) {
|
|
20606
20921
|
if (typeof value !== "string") return null;
|
|
20607
20922
|
const normalized = value.trim().toLowerCase();
|
|
@@ -20612,6 +20927,22 @@ function normalizeReleaseChannel(value) {
|
|
|
20612
20927
|
function resolveUpgradeChannel(args) {
|
|
20613
20928
|
return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
|
|
20614
20929
|
}
|
|
20930
|
+
function loadYamlModule() {
|
|
20931
|
+
return yaml;
|
|
20932
|
+
}
|
|
20933
|
+
function getMcpServersKey(format) {
|
|
20934
|
+
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
20935
|
+
}
|
|
20936
|
+
function parseMeshCoordinatorMcpConfig(text, format) {
|
|
20937
|
+
if (!text.trim()) return {};
|
|
20938
|
+
if (format === "claude_mcp_json") return JSON.parse(text);
|
|
20939
|
+
const parsed = loadYamlModule().load(text);
|
|
20940
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
20941
|
+
}
|
|
20942
|
+
function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
20943
|
+
if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
|
|
20944
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
20945
|
+
}
|
|
20615
20946
|
var CHAT_COMMANDS = [
|
|
20616
20947
|
"send_chat",
|
|
20617
20948
|
"new_chat",
|
|
@@ -20710,6 +21041,40 @@ var DaemonCommandRouter = class {
|
|
|
20710
21041
|
constructor(deps) {
|
|
20711
21042
|
this.deps = deps;
|
|
20712
21043
|
}
|
|
21044
|
+
getCachedInlineMesh(meshId, inlineMesh) {
|
|
21045
|
+
if (inlineMesh && typeof inlineMesh === "object") {
|
|
21046
|
+
this.inlineMeshCache.set(meshId, inlineMesh);
|
|
21047
|
+
return inlineMesh;
|
|
21048
|
+
}
|
|
21049
|
+
return this.inlineMeshCache.get(meshId);
|
|
21050
|
+
}
|
|
21051
|
+
async getMeshForCommand(meshId, inlineMesh) {
|
|
21052
|
+
try {
|
|
21053
|
+
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21054
|
+
const mesh = getMesh3(meshId);
|
|
21055
|
+
if (mesh) return { mesh, inline: false };
|
|
21056
|
+
} catch {
|
|
21057
|
+
}
|
|
21058
|
+
const cached = this.getCachedInlineMesh(meshId, inlineMesh);
|
|
21059
|
+
return cached ? { mesh: cached, inline: true } : null;
|
|
21060
|
+
}
|
|
21061
|
+
updateInlineMeshNode(meshId, mesh, node) {
|
|
21062
|
+
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
21063
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
21064
|
+
if (idx >= 0) mesh.nodes[idx] = node;
|
|
21065
|
+
else mesh.nodes.push(node);
|
|
21066
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21067
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21068
|
+
}
|
|
21069
|
+
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
21070
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
21071
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
|
|
21072
|
+
if (idx === -1) return false;
|
|
21073
|
+
mesh.nodes.splice(idx, 1);
|
|
21074
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21075
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21076
|
+
return true;
|
|
21077
|
+
}
|
|
20713
21078
|
async traceSessionHostAction(action, args, run, summarizeResult) {
|
|
20714
21079
|
const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
|
|
20715
21080
|
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -21298,6 +21663,7 @@ var DaemonCommandRouter = class {
|
|
|
21298
21663
|
const npmTag = CHANNEL_NPM_TAG[channel];
|
|
21299
21664
|
const latest = String(execNpmCommandSync(["view", `${pkgName}@${npmTag}`, "version"], { encoding: "utf-8", timeout: 1e4 }, npmSurface)).trim();
|
|
21300
21665
|
LOG.info("Upgrade", `Latest ${pkgName}@${npmTag}: v${latest}`);
|
|
21666
|
+
updateConfig({ updateChannel: channel, serverUrl: CHANNEL_SERVER_URL[channel] });
|
|
21301
21667
|
let currentInstalled = null;
|
|
21302
21668
|
try {
|
|
21303
21669
|
const currentJson = String(execNpmCommandSync(["ls", "-g", pkgName, "--depth=0", "--json"], {
|
|
@@ -21408,13 +21774,94 @@ var DaemonCommandRouter = class {
|
|
|
21408
21774
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
21409
21775
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
21410
21776
|
try {
|
|
21411
|
-
const
|
|
21412
|
-
const
|
|
21777
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
21778
|
+
const mesh = meshRecord?.mesh;
|
|
21779
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
21780
|
+
if (node?.isLocalWorktree && node.workspace) {
|
|
21781
|
+
try {
|
|
21782
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
21783
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
21784
|
+
if (repoRoot) {
|
|
21785
|
+
const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
21786
|
+
await removeWorktree2(repoRoot, node.workspace);
|
|
21787
|
+
}
|
|
21788
|
+
} catch (e) {
|
|
21789
|
+
LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
|
|
21790
|
+
}
|
|
21791
|
+
}
|
|
21792
|
+
let removed = false;
|
|
21793
|
+
if (meshRecord?.inline) {
|
|
21794
|
+
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
21795
|
+
} else {
|
|
21796
|
+
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21797
|
+
removed = removeNode3(meshId, nodeId);
|
|
21798
|
+
}
|
|
21413
21799
|
return { success: true, removed };
|
|
21414
21800
|
} catch (e) {
|
|
21415
21801
|
return { success: false, error: e.message };
|
|
21416
21802
|
}
|
|
21417
21803
|
}
|
|
21804
|
+
case "clone_mesh_node": {
|
|
21805
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21806
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
21807
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
21808
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
21809
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
21810
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
21811
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
21812
|
+
try {
|
|
21813
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
21814
|
+
const mesh = meshRecord?.mesh;
|
|
21815
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
21816
|
+
const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
|
|
21817
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
21818
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
21819
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
21820
|
+
const result = await createWorktree2({
|
|
21821
|
+
repoRoot,
|
|
21822
|
+
branch,
|
|
21823
|
+
baseBranch,
|
|
21824
|
+
meshName: mesh.name
|
|
21825
|
+
});
|
|
21826
|
+
let node;
|
|
21827
|
+
if (meshRecord.inline) {
|
|
21828
|
+
const { randomUUID: randomUUID8 } = await import("crypto");
|
|
21829
|
+
node = {
|
|
21830
|
+
id: `node_${randomUUID8().replace(/-/g, "")}`,
|
|
21831
|
+
workspace: result.worktreePath,
|
|
21832
|
+
repoRoot: result.worktreePath,
|
|
21833
|
+
daemonId: sourceNode.daemonId,
|
|
21834
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
21835
|
+
policy: { ...sourceNode.policy || {} },
|
|
21836
|
+
isLocalWorktree: true,
|
|
21837
|
+
worktreeBranch: result.branch,
|
|
21838
|
+
clonedFromNodeId: sourceNodeId
|
|
21839
|
+
};
|
|
21840
|
+
this.updateInlineMeshNode(meshId, mesh, node);
|
|
21841
|
+
} else {
|
|
21842
|
+
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21843
|
+
node = addNode3(meshId, {
|
|
21844
|
+
workspace: result.worktreePath,
|
|
21845
|
+
repoRoot: result.worktreePath,
|
|
21846
|
+
daemonId: sourceNode.daemonId,
|
|
21847
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
21848
|
+
isLocalWorktree: true,
|
|
21849
|
+
worktreeBranch: result.branch,
|
|
21850
|
+
clonedFromNodeId: sourceNodeId,
|
|
21851
|
+
policy: { ...sourceNode.policy || {} }
|
|
21852
|
+
});
|
|
21853
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
21854
|
+
}
|
|
21855
|
+
return {
|
|
21856
|
+
success: true,
|
|
21857
|
+
node,
|
|
21858
|
+
worktreePath: result.worktreePath,
|
|
21859
|
+
branch: result.branch
|
|
21860
|
+
};
|
|
21861
|
+
} catch (e) {
|
|
21862
|
+
return { success: false, error: e.message };
|
|
21863
|
+
}
|
|
21864
|
+
}
|
|
21418
21865
|
// ─── Mesh Coordinator Launch ───
|
|
21419
21866
|
case "launch_mesh_coordinator": {
|
|
21420
21867
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
@@ -21449,6 +21896,7 @@ var DaemonCommandRouter = class {
|
|
|
21449
21896
|
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
21450
21897
|
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
21451
21898
|
provider: providerMeta,
|
|
21899
|
+
cliType,
|
|
21452
21900
|
meshId,
|
|
21453
21901
|
workspace
|
|
21454
21902
|
});
|
|
@@ -21473,7 +21921,8 @@ var DaemonCommandRouter = class {
|
|
|
21473
21921
|
meshCoordinatorSetup: coordinatorSetup
|
|
21474
21922
|
};
|
|
21475
21923
|
}
|
|
21476
|
-
|
|
21924
|
+
const configFormat = coordinatorSetup.configFormat;
|
|
21925
|
+
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
21477
21926
|
return {
|
|
21478
21927
|
success: false,
|
|
21479
21928
|
code: "mesh_coordinator_unsupported",
|
|
@@ -21483,44 +21932,93 @@ var DaemonCommandRouter = class {
|
|
|
21483
21932
|
workspace
|
|
21484
21933
|
};
|
|
21485
21934
|
}
|
|
21486
|
-
|
|
21487
|
-
|
|
21488
|
-
|
|
21489
|
-
|
|
21490
|
-
|
|
21491
|
-
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21935
|
+
let systemPrompt = "";
|
|
21936
|
+
try {
|
|
21937
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
21938
|
+
} catch (error) {
|
|
21939
|
+
const message = error?.message || String(error);
|
|
21940
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
21941
|
+
return {
|
|
21942
|
+
success: false,
|
|
21943
|
+
code: "mesh_coordinator_prompt_failed",
|
|
21944
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
21945
|
+
meshId,
|
|
21946
|
+
cliType,
|
|
21947
|
+
workspace
|
|
21948
|
+
};
|
|
21496
21949
|
}
|
|
21950
|
+
const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync12, copyFileSync: copyFileSync3, mkdirSync: mkdirSync14 } = await import("fs");
|
|
21951
|
+
const { dirname: dirname9 } = await import("path");
|
|
21952
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
21953
|
+
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
21954
|
+
const returnManualFallback = (message) => ({
|
|
21955
|
+
success: false,
|
|
21956
|
+
code: "mesh_coordinator_manual_mcp_setup_required",
|
|
21957
|
+
error: message,
|
|
21958
|
+
meshId,
|
|
21959
|
+
cliType,
|
|
21960
|
+
workspace,
|
|
21961
|
+
meshCoordinatorSetup: hermesManualFallback
|
|
21962
|
+
});
|
|
21497
21963
|
const mcpServerEntry = {
|
|
21498
21964
|
command: coordinatorSetup.mcpServer.command,
|
|
21499
21965
|
args: coordinatorSetup.mcpServer.args
|
|
21500
21966
|
};
|
|
21501
21967
|
if (args?.inlineMesh) {
|
|
21502
21968
|
mcpServerEntry.env = {
|
|
21503
|
-
ADHDEV_INLINE_MESH: JSON.stringify(mesh)
|
|
21969
|
+
ADHDEV_INLINE_MESH: JSON.stringify(mesh),
|
|
21970
|
+
ADHDEV_MCP_TRANSPORT: "ipc"
|
|
21504
21971
|
};
|
|
21505
21972
|
}
|
|
21973
|
+
try {
|
|
21974
|
+
mkdirSync14(dirname9(mcpConfigPath), { recursive: true });
|
|
21975
|
+
} catch (error) {
|
|
21976
|
+
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
21977
|
+
LOG.error("MeshCoordinator", message);
|
|
21978
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
21979
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21980
|
+
}
|
|
21981
|
+
const hadExistingMcpConfig = existsSync23(mcpConfigPath);
|
|
21982
|
+
let existingMcpConfig = {};
|
|
21983
|
+
if (hadExistingMcpConfig) {
|
|
21984
|
+
try {
|
|
21985
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
|
|
21986
|
+
copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
|
|
21987
|
+
} catch (error) {
|
|
21988
|
+
LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
21989
|
+
return {
|
|
21990
|
+
success: false,
|
|
21991
|
+
code: "mesh_coordinator_config_parse_failed",
|
|
21992
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`
|
|
21993
|
+
};
|
|
21994
|
+
}
|
|
21995
|
+
}
|
|
21996
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
21997
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
21506
21998
|
const mcpConfig = {
|
|
21507
21999
|
...existingMcpConfig,
|
|
21508
|
-
|
|
21509
|
-
...
|
|
22000
|
+
[mcpServersKey]: {
|
|
22001
|
+
...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
|
|
21510
22002
|
[coordinatorSetup.serverName]: mcpServerEntry
|
|
21511
22003
|
}
|
|
21512
22004
|
};
|
|
21513
|
-
writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
21514
|
-
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21515
|
-
let systemPrompt = "";
|
|
21516
22005
|
try {
|
|
21517
|
-
|
|
21518
|
-
} catch {
|
|
21519
|
-
|
|
22006
|
+
writeFileSync12(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
22007
|
+
} catch (error) {
|
|
22008
|
+
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
22009
|
+
LOG.error("MeshCoordinator", message);
|
|
22010
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22011
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21520
22012
|
}
|
|
22013
|
+
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21521
22014
|
const cliArgs = [];
|
|
22015
|
+
const launchEnv = {};
|
|
21522
22016
|
if (systemPrompt) {
|
|
21523
|
-
|
|
22017
|
+
if (configFormat === "hermes_config_yaml") {
|
|
22018
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
22019
|
+
} else {
|
|
22020
|
+
cliArgs.push("--append-system-prompt", systemPrompt);
|
|
22021
|
+
}
|
|
21524
22022
|
}
|
|
21525
22023
|
if (cliType === "claude-cli") {
|
|
21526
22024
|
cliArgs.push("--mcp-config", coordinatorSetup.configPath);
|
|
@@ -21529,6 +22027,7 @@ var DaemonCommandRouter = class {
|
|
|
21529
22027
|
cliType,
|
|
21530
22028
|
dir: workspace,
|
|
21531
22029
|
cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
|
|
22030
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
21532
22031
|
settings: {
|
|
21533
22032
|
meshCoordinatorFor: meshId
|
|
21534
22033
|
}
|
|
@@ -23189,11 +23688,11 @@ var ProviderInstanceManager = class {
|
|
|
23189
23688
|
|
|
23190
23689
|
// src/providers/version-archive.ts
|
|
23191
23690
|
import * as fs11 from "fs";
|
|
23192
|
-
import * as
|
|
23193
|
-
import * as
|
|
23691
|
+
import * as path22 from "path";
|
|
23692
|
+
import * as os20 from "os";
|
|
23194
23693
|
import { execSync as execSync5 } from "child_process";
|
|
23195
23694
|
import { platform as platform8 } from "os";
|
|
23196
|
-
var ARCHIVE_PATH =
|
|
23695
|
+
var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
|
|
23197
23696
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
23198
23697
|
var VersionArchive = class {
|
|
23199
23698
|
history = {};
|
|
@@ -23240,7 +23739,7 @@ var VersionArchive = class {
|
|
|
23240
23739
|
}
|
|
23241
23740
|
save() {
|
|
23242
23741
|
try {
|
|
23243
|
-
fs11.mkdirSync(
|
|
23742
|
+
fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
|
|
23244
23743
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
23245
23744
|
} catch {
|
|
23246
23745
|
}
|
|
@@ -23296,8 +23795,8 @@ function getVersion(binary, versionCommand) {
|
|
|
23296
23795
|
function checkPathExists2(paths) {
|
|
23297
23796
|
for (const p of paths) {
|
|
23298
23797
|
if (p.includes("*")) {
|
|
23299
|
-
const home =
|
|
23300
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
23798
|
+
const home = os20.homedir();
|
|
23799
|
+
const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
|
|
23301
23800
|
if (fs11.existsSync(resolved)) return resolved;
|
|
23302
23801
|
} else {
|
|
23303
23802
|
if (fs11.existsSync(p)) return p;
|
|
@@ -23307,7 +23806,7 @@ function checkPathExists2(paths) {
|
|
|
23307
23806
|
}
|
|
23308
23807
|
function getMacAppVersion(appPath) {
|
|
23309
23808
|
if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
23310
|
-
const plistPath =
|
|
23809
|
+
const plistPath = path22.join(appPath, "Contents", "Info.plist");
|
|
23311
23810
|
if (!fs11.existsSync(plistPath)) return null;
|
|
23312
23811
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
23313
23812
|
return raw || null;
|
|
@@ -23333,7 +23832,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23333
23832
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
23334
23833
|
let resolvedBin = cliBin;
|
|
23335
23834
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
23336
|
-
const bundled =
|
|
23835
|
+
const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
23337
23836
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
23338
23837
|
}
|
|
23339
23838
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -23374,7 +23873,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23374
23873
|
// src/daemon/dev-server.ts
|
|
23375
23874
|
import * as http2 from "http";
|
|
23376
23875
|
import * as fs15 from "fs";
|
|
23377
|
-
import * as
|
|
23876
|
+
import * as path26 from "path";
|
|
23378
23877
|
init_config();
|
|
23379
23878
|
|
|
23380
23879
|
// src/daemon/scaffold-template.ts
|
|
@@ -23726,7 +24225,7 @@ init_logger();
|
|
|
23726
24225
|
// src/daemon/dev-cdp-handlers.ts
|
|
23727
24226
|
init_logger();
|
|
23728
24227
|
import * as fs12 from "fs";
|
|
23729
|
-
import * as
|
|
24228
|
+
import * as path23 from "path";
|
|
23730
24229
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
23731
24230
|
const body = await ctx.readBody(req);
|
|
23732
24231
|
const { expression, timeout, ideType } = body;
|
|
@@ -23904,17 +24403,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
23904
24403
|
return;
|
|
23905
24404
|
}
|
|
23906
24405
|
let scriptsPath = "";
|
|
23907
|
-
const directScripts =
|
|
24406
|
+
const directScripts = path23.join(dir, "scripts.js");
|
|
23908
24407
|
if (fs12.existsSync(directScripts)) {
|
|
23909
24408
|
scriptsPath = directScripts;
|
|
23910
24409
|
} else {
|
|
23911
|
-
const scriptsDir =
|
|
24410
|
+
const scriptsDir = path23.join(dir, "scripts");
|
|
23912
24411
|
if (fs12.existsSync(scriptsDir)) {
|
|
23913
24412
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
23914
|
-
return fs12.statSync(
|
|
24413
|
+
return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
|
|
23915
24414
|
}).sort().reverse();
|
|
23916
24415
|
for (const ver of versions) {
|
|
23917
|
-
const p =
|
|
24416
|
+
const p = path23.join(scriptsDir, ver, "scripts.js");
|
|
23918
24417
|
if (fs12.existsSync(p)) {
|
|
23919
24418
|
scriptsPath = p;
|
|
23920
24419
|
break;
|
|
@@ -24743,7 +25242,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
24743
25242
|
|
|
24744
25243
|
// src/daemon/dev-cli-debug.ts
|
|
24745
25244
|
import * as fs13 from "fs";
|
|
24746
|
-
import * as
|
|
25245
|
+
import * as path24 from "path";
|
|
24747
25246
|
function slugifyFixtureName(value) {
|
|
24748
25247
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24749
25248
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -24753,11 +25252,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
24753
25252
|
if (!providerDir) {
|
|
24754
25253
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
24755
25254
|
}
|
|
24756
|
-
return
|
|
25255
|
+
return path24.join(providerDir, "fixtures");
|
|
24757
25256
|
}
|
|
24758
25257
|
function readCliFixture(ctx, type, name) {
|
|
24759
25258
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
24760
|
-
const filePath =
|
|
25259
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
24761
25260
|
if (!fs13.existsSync(filePath)) {
|
|
24762
25261
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
24763
25262
|
}
|
|
@@ -25524,7 +26023,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
25524
26023
|
},
|
|
25525
26024
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
25526
26025
|
};
|
|
25527
|
-
const filePath =
|
|
26026
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
25528
26027
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
25529
26028
|
ctx.json(res, 200, {
|
|
25530
26029
|
saved: true,
|
|
@@ -25548,7 +26047,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
25548
26047
|
return;
|
|
25549
26048
|
}
|
|
25550
26049
|
const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
25551
|
-
const fullPath =
|
|
26050
|
+
const fullPath = path24.join(fixtureDir, file);
|
|
25552
26051
|
try {
|
|
25553
26052
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
25554
26053
|
return {
|
|
@@ -25684,8 +26183,8 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
25684
26183
|
|
|
25685
26184
|
// src/daemon/dev-auto-implement.ts
|
|
25686
26185
|
import * as fs14 from "fs";
|
|
25687
|
-
import * as
|
|
25688
|
-
import * as
|
|
26186
|
+
import * as path25 from "path";
|
|
26187
|
+
import * as os21 from "os";
|
|
25689
26188
|
function getAutoImplPid(ctx) {
|
|
25690
26189
|
const pid = ctx.autoImplProcess?.pid;
|
|
25691
26190
|
return typeof pid === "number" && pid > 0 ? pid : null;
|
|
@@ -25734,22 +26233,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
25734
26233
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
25735
26234
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
25736
26235
|
try {
|
|
25737
|
-
return fs14.statSync(
|
|
26236
|
+
return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
25738
26237
|
} catch {
|
|
25739
26238
|
return false;
|
|
25740
26239
|
}
|
|
25741
26240
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
25742
26241
|
if (versions.length === 0) return null;
|
|
25743
|
-
return
|
|
26242
|
+
return path25.join(scriptsDir, versions[0]);
|
|
25744
26243
|
}
|
|
25745
26244
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
25746
|
-
const canonicalUserDir =
|
|
25747
|
-
const desiredDir = requestedDir ?
|
|
25748
|
-
const upstreamRoot =
|
|
25749
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
26245
|
+
const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
26246
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
26247
|
+
const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
|
|
26248
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
25750
26249
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
25751
26250
|
}
|
|
25752
|
-
if (
|
|
26251
|
+
if (path25.basename(desiredDir) !== type) {
|
|
25753
26252
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
25754
26253
|
}
|
|
25755
26254
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -25757,11 +26256,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
25757
26256
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
25758
26257
|
}
|
|
25759
26258
|
if (!fs14.existsSync(desiredDir)) {
|
|
25760
|
-
fs14.mkdirSync(
|
|
26259
|
+
fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
25761
26260
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
25762
26261
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
25763
26262
|
}
|
|
25764
|
-
const providerJson =
|
|
26263
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
25765
26264
|
if (!fs14.existsSync(providerJson)) {
|
|
25766
26265
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
25767
26266
|
}
|
|
@@ -25772,13 +26271,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
25772
26271
|
const refDir = ctx.findProviderDir(referenceType);
|
|
25773
26272
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
25774
26273
|
const referenceScripts = {};
|
|
25775
|
-
const scriptsDir =
|
|
26274
|
+
const scriptsDir = path25.join(refDir, "scripts");
|
|
25776
26275
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
25777
26276
|
if (!latestDir) return referenceScripts;
|
|
25778
26277
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
25779
26278
|
if (!file.endsWith(".js")) continue;
|
|
25780
26279
|
try {
|
|
25781
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
26280
|
+
referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
|
|
25782
26281
|
} catch {
|
|
25783
26282
|
}
|
|
25784
26283
|
}
|
|
@@ -25886,9 +26385,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
25886
26385
|
});
|
|
25887
26386
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
25888
26387
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
25889
|
-
const tmpDir =
|
|
26388
|
+
const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
|
|
25890
26389
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
25891
|
-
const promptFile =
|
|
26390
|
+
const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
25892
26391
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
25893
26392
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
25894
26393
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -26041,7 +26540,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26041
26540
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
26042
26541
|
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
26043
26542
|
let shellCmd;
|
|
26044
|
-
const isWin =
|
|
26543
|
+
const isWin = os21.platform() === "win32";
|
|
26045
26544
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
26046
26545
|
const promptMode = autoImpl?.promptMode ?? "stdin";
|
|
26047
26546
|
const extraArgs = autoImpl?.extraArgs ?? [];
|
|
@@ -26080,7 +26579,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26080
26579
|
try {
|
|
26081
26580
|
const pty = __require("node-pty");
|
|
26082
26581
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
26083
|
-
const isWin2 =
|
|
26582
|
+
const isWin2 = os21.platform() === "win32";
|
|
26084
26583
|
child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
26085
26584
|
name: "xterm-256color",
|
|
26086
26585
|
cols: 120,
|
|
@@ -26320,7 +26819,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26320
26819
|
setMode: "set_mode.js"
|
|
26321
26820
|
};
|
|
26322
26821
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26323
|
-
const scriptsDir =
|
|
26822
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26324
26823
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26325
26824
|
if (latestScriptsDir) {
|
|
26326
26825
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26331,7 +26830,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26331
26830
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
26332
26831
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26333
26832
|
try {
|
|
26334
|
-
const content = fs14.readFileSync(
|
|
26833
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26335
26834
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26336
26835
|
lines.push("```javascript");
|
|
26337
26836
|
lines.push(content);
|
|
@@ -26348,7 +26847,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26348
26847
|
lines.push("");
|
|
26349
26848
|
for (const file of refFiles) {
|
|
26350
26849
|
try {
|
|
26351
|
-
const content = fs14.readFileSync(
|
|
26850
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26352
26851
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26353
26852
|
lines.push("```javascript");
|
|
26354
26853
|
lines.push(content);
|
|
@@ -26389,10 +26888,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26389
26888
|
lines.push("");
|
|
26390
26889
|
}
|
|
26391
26890
|
}
|
|
26392
|
-
const docsDir =
|
|
26891
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26393
26892
|
const loadGuide = (name) => {
|
|
26394
26893
|
try {
|
|
26395
|
-
const p =
|
|
26894
|
+
const p = path25.join(docsDir, name);
|
|
26396
26895
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26397
26896
|
} catch {
|
|
26398
26897
|
}
|
|
@@ -26629,7 +27128,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26629
27128
|
parseApproval: "parse_approval.js"
|
|
26630
27129
|
};
|
|
26631
27130
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26632
|
-
const scriptsDir =
|
|
27131
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26633
27132
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26634
27133
|
if (latestScriptsDir) {
|
|
26635
27134
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26641,7 +27140,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26641
27140
|
if (!file.endsWith(".js")) continue;
|
|
26642
27141
|
if (!targetFileNames.has(file)) continue;
|
|
26643
27142
|
try {
|
|
26644
|
-
const content = fs14.readFileSync(
|
|
27143
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26645
27144
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26646
27145
|
lines.push("```javascript");
|
|
26647
27146
|
lines.push(content);
|
|
@@ -26657,7 +27156,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26657
27156
|
lines.push("");
|
|
26658
27157
|
for (const file of refFiles) {
|
|
26659
27158
|
try {
|
|
26660
|
-
const content = fs14.readFileSync(
|
|
27159
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26661
27160
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26662
27161
|
lines.push("```javascript");
|
|
26663
27162
|
lines.push(content);
|
|
@@ -26690,10 +27189,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26690
27189
|
lines.push("");
|
|
26691
27190
|
}
|
|
26692
27191
|
}
|
|
26693
|
-
const docsDir =
|
|
27192
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26694
27193
|
const loadGuide = (name) => {
|
|
26695
27194
|
try {
|
|
26696
|
-
const p =
|
|
27195
|
+
const p = path25.join(docsDir, name);
|
|
26697
27196
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26698
27197
|
} catch {
|
|
26699
27198
|
}
|
|
@@ -27140,8 +27639,8 @@ var DevServer = class _DevServer {
|
|
|
27140
27639
|
}
|
|
27141
27640
|
getEndpointList() {
|
|
27142
27641
|
return this.routes.map((r) => {
|
|
27143
|
-
const
|
|
27144
|
-
return `${r.method.padEnd(5)} ${
|
|
27642
|
+
const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
27643
|
+
return `${r.method.padEnd(5)} ${path27}`;
|
|
27145
27644
|
});
|
|
27146
27645
|
}
|
|
27147
27646
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -27429,12 +27928,12 @@ var DevServer = class _DevServer {
|
|
|
27429
27928
|
// ─── DevConsole SPA ───
|
|
27430
27929
|
getConsoleDistDir() {
|
|
27431
27930
|
const candidates = [
|
|
27432
|
-
|
|
27433
|
-
|
|
27434
|
-
|
|
27931
|
+
path26.resolve(__dirname, "../../web-devconsole/dist"),
|
|
27932
|
+
path26.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
27933
|
+
path26.join(process.cwd(), "packages/web-devconsole/dist")
|
|
27435
27934
|
];
|
|
27436
27935
|
for (const dir of candidates) {
|
|
27437
|
-
if (fs15.existsSync(
|
|
27936
|
+
if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
|
|
27438
27937
|
}
|
|
27439
27938
|
return null;
|
|
27440
27939
|
}
|
|
@@ -27444,7 +27943,7 @@ var DevServer = class _DevServer {
|
|
|
27444
27943
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
27445
27944
|
return;
|
|
27446
27945
|
}
|
|
27447
|
-
const htmlPath =
|
|
27946
|
+
const htmlPath = path26.join(distDir, "index.html");
|
|
27448
27947
|
try {
|
|
27449
27948
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
27450
27949
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -27469,15 +27968,15 @@ var DevServer = class _DevServer {
|
|
|
27469
27968
|
this.json(res, 404, { error: "Not found" });
|
|
27470
27969
|
return;
|
|
27471
27970
|
}
|
|
27472
|
-
const safePath =
|
|
27473
|
-
const filePath =
|
|
27971
|
+
const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
|
|
27972
|
+
const filePath = path26.join(distDir, safePath);
|
|
27474
27973
|
if (!filePath.startsWith(distDir)) {
|
|
27475
27974
|
this.json(res, 403, { error: "Forbidden" });
|
|
27476
27975
|
return;
|
|
27477
27976
|
}
|
|
27478
27977
|
try {
|
|
27479
27978
|
const content = fs15.readFileSync(filePath);
|
|
27480
|
-
const ext =
|
|
27979
|
+
const ext = path26.extname(filePath);
|
|
27481
27980
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
27482
27981
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
27483
27982
|
res.end(content);
|
|
@@ -27590,9 +28089,9 @@ var DevServer = class _DevServer {
|
|
|
27590
28089
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27591
28090
|
if (entry.isDirectory()) {
|
|
27592
28091
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
27593
|
-
scan(
|
|
28092
|
+
scan(path26.join(d, entry.name), rel);
|
|
27594
28093
|
} else {
|
|
27595
|
-
const stat2 = fs15.statSync(
|
|
28094
|
+
const stat2 = fs15.statSync(path26.join(d, entry.name));
|
|
27596
28095
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
27597
28096
|
}
|
|
27598
28097
|
}
|
|
@@ -27615,7 +28114,7 @@ var DevServer = class _DevServer {
|
|
|
27615
28114
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27616
28115
|
return;
|
|
27617
28116
|
}
|
|
27618
|
-
const fullPath =
|
|
28117
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27619
28118
|
if (!fullPath.startsWith(dir)) {
|
|
27620
28119
|
this.json(res, 403, { error: "Forbidden" });
|
|
27621
28120
|
return;
|
|
@@ -27640,14 +28139,14 @@ var DevServer = class _DevServer {
|
|
|
27640
28139
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27641
28140
|
return;
|
|
27642
28141
|
}
|
|
27643
|
-
const fullPath =
|
|
28142
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27644
28143
|
if (!fullPath.startsWith(dir)) {
|
|
27645
28144
|
this.json(res, 403, { error: "Forbidden" });
|
|
27646
28145
|
return;
|
|
27647
28146
|
}
|
|
27648
28147
|
try {
|
|
27649
28148
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
27650
|
-
fs15.mkdirSync(
|
|
28149
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27651
28150
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27652
28151
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
27653
28152
|
this.providerLoader.reload();
|
|
@@ -27664,7 +28163,7 @@ var DevServer = class _DevServer {
|
|
|
27664
28163
|
return;
|
|
27665
28164
|
}
|
|
27666
28165
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
27667
|
-
const p =
|
|
28166
|
+
const p = path26.join(dir, name);
|
|
27668
28167
|
if (fs15.existsSync(p)) {
|
|
27669
28168
|
const source = fs15.readFileSync(p, "utf-8");
|
|
27670
28169
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -27685,8 +28184,8 @@ var DevServer = class _DevServer {
|
|
|
27685
28184
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
27686
28185
|
return;
|
|
27687
28186
|
}
|
|
27688
|
-
const target = fs15.existsSync(
|
|
27689
|
-
const targetPath =
|
|
28187
|
+
const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
28188
|
+
const targetPath = path26.join(dir, target);
|
|
27690
28189
|
try {
|
|
27691
28190
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
27692
28191
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -27833,7 +28332,7 @@ var DevServer = class _DevServer {
|
|
|
27833
28332
|
}
|
|
27834
28333
|
let targetDir;
|
|
27835
28334
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
27836
|
-
const jsonPath =
|
|
28335
|
+
const jsonPath = path26.join(targetDir, "provider.json");
|
|
27837
28336
|
if (fs15.existsSync(jsonPath)) {
|
|
27838
28337
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
27839
28338
|
return;
|
|
@@ -27845,8 +28344,8 @@ var DevServer = class _DevServer {
|
|
|
27845
28344
|
const createdFiles = ["provider.json"];
|
|
27846
28345
|
if (result.files) {
|
|
27847
28346
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
27848
|
-
const fullPath =
|
|
27849
|
-
fs15.mkdirSync(
|
|
28347
|
+
const fullPath = path26.join(targetDir, relPath);
|
|
28348
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27850
28349
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27851
28350
|
createdFiles.push(relPath);
|
|
27852
28351
|
}
|
|
@@ -27899,22 +28398,22 @@ var DevServer = class _DevServer {
|
|
|
27899
28398
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
27900
28399
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
27901
28400
|
try {
|
|
27902
|
-
return fs15.statSync(
|
|
28401
|
+
return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
|
|
27903
28402
|
} catch {
|
|
27904
28403
|
return false;
|
|
27905
28404
|
}
|
|
27906
28405
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
27907
28406
|
if (versions.length === 0) return null;
|
|
27908
|
-
return
|
|
28407
|
+
return path26.join(scriptsDir, versions[0]);
|
|
27909
28408
|
}
|
|
27910
28409
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
27911
|
-
const canonicalUserDir =
|
|
27912
|
-
const desiredDir = requestedDir ?
|
|
27913
|
-
const upstreamRoot =
|
|
27914
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
28410
|
+
const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
28411
|
+
const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
|
|
28412
|
+
const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
|
|
28413
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
|
|
27915
28414
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
27916
28415
|
}
|
|
27917
|
-
if (
|
|
28416
|
+
if (path26.basename(desiredDir) !== type) {
|
|
27918
28417
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
27919
28418
|
}
|
|
27920
28419
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -27922,11 +28421,11 @@ var DevServer = class _DevServer {
|
|
|
27922
28421
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
27923
28422
|
}
|
|
27924
28423
|
if (!fs15.existsSync(desiredDir)) {
|
|
27925
|
-
fs15.mkdirSync(
|
|
28424
|
+
fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
|
|
27926
28425
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
27927
28426
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
27928
28427
|
}
|
|
27929
|
-
const providerJson =
|
|
28428
|
+
const providerJson = path26.join(desiredDir, "provider.json");
|
|
27930
28429
|
if (!fs15.existsSync(providerJson)) {
|
|
27931
28430
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
27932
28431
|
}
|
|
@@ -27962,7 +28461,7 @@ var DevServer = class _DevServer {
|
|
|
27962
28461
|
setMode: "set_mode.js"
|
|
27963
28462
|
};
|
|
27964
28463
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
27965
|
-
const scriptsDir =
|
|
28464
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
27966
28465
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
27967
28466
|
if (latestScriptsDir) {
|
|
27968
28467
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -27973,7 +28472,7 @@ var DevServer = class _DevServer {
|
|
|
27973
28472
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
27974
28473
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
27975
28474
|
try {
|
|
27976
|
-
const content = fs15.readFileSync(
|
|
28475
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
27977
28476
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
27978
28477
|
lines.push("```javascript");
|
|
27979
28478
|
lines.push(content);
|
|
@@ -27990,7 +28489,7 @@ var DevServer = class _DevServer {
|
|
|
27990
28489
|
lines.push("");
|
|
27991
28490
|
for (const file of refFiles) {
|
|
27992
28491
|
try {
|
|
27993
|
-
const content = fs15.readFileSync(
|
|
28492
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
27994
28493
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
27995
28494
|
lines.push("```javascript");
|
|
27996
28495
|
lines.push(content);
|
|
@@ -28031,10 +28530,10 @@ var DevServer = class _DevServer {
|
|
|
28031
28530
|
lines.push("");
|
|
28032
28531
|
}
|
|
28033
28532
|
}
|
|
28034
|
-
const docsDir =
|
|
28533
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28035
28534
|
const loadGuide = (name) => {
|
|
28036
28535
|
try {
|
|
28037
|
-
const p =
|
|
28536
|
+
const p = path26.join(docsDir, name);
|
|
28038
28537
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28039
28538
|
} catch {
|
|
28040
28539
|
}
|
|
@@ -28208,7 +28707,7 @@ var DevServer = class _DevServer {
|
|
|
28208
28707
|
parseApproval: "parse_approval.js"
|
|
28209
28708
|
};
|
|
28210
28709
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28211
|
-
const scriptsDir =
|
|
28710
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28212
28711
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28213
28712
|
if (latestScriptsDir) {
|
|
28214
28713
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28220,7 +28719,7 @@ var DevServer = class _DevServer {
|
|
|
28220
28719
|
if (!file.endsWith(".js")) continue;
|
|
28221
28720
|
if (!targetFileNames.has(file)) continue;
|
|
28222
28721
|
try {
|
|
28223
|
-
const content = fs15.readFileSync(
|
|
28722
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28224
28723
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28225
28724
|
lines.push("```javascript");
|
|
28226
28725
|
lines.push(content);
|
|
@@ -28236,7 +28735,7 @@ var DevServer = class _DevServer {
|
|
|
28236
28735
|
lines.push("");
|
|
28237
28736
|
for (const file of refFiles) {
|
|
28238
28737
|
try {
|
|
28239
|
-
const content = fs15.readFileSync(
|
|
28738
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28240
28739
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28241
28740
|
lines.push("```javascript");
|
|
28242
28741
|
lines.push(content);
|
|
@@ -28269,10 +28768,10 @@ var DevServer = class _DevServer {
|
|
|
28269
28768
|
lines.push("");
|
|
28270
28769
|
}
|
|
28271
28770
|
}
|
|
28272
|
-
const docsDir =
|
|
28771
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28273
28772
|
const loadGuide = (name) => {
|
|
28274
28773
|
try {
|
|
28275
|
-
const p =
|
|
28774
|
+
const p = path26.join(docsDir, name);
|
|
28276
28775
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28277
28776
|
} catch {
|
|
28278
28777
|
}
|
|
@@ -29624,6 +30123,7 @@ export {
|
|
|
29624
30123
|
createGitWorkspaceMonitor,
|
|
29625
30124
|
createInteractionId,
|
|
29626
30125
|
createMesh,
|
|
30126
|
+
createWorktree,
|
|
29627
30127
|
deleteMesh,
|
|
29628
30128
|
detectAllVersions,
|
|
29629
30129
|
detectCLIs,
|
|
@@ -29676,6 +30176,7 @@ export {
|
|
|
29676
30176
|
launchWithCdp,
|
|
29677
30177
|
listHostedCliRuntimes,
|
|
29678
30178
|
listMeshes,
|
|
30179
|
+
listWorktrees,
|
|
29679
30180
|
loadConfig,
|
|
29680
30181
|
loadState,
|
|
29681
30182
|
logCommand,
|
|
@@ -29695,6 +30196,7 @@ export {
|
|
|
29695
30196
|
normalizeSessionModalFields,
|
|
29696
30197
|
parsePorcelainV2Status,
|
|
29697
30198
|
parseProviderSourceConfigUpdate,
|
|
30199
|
+
parseWorktreeListOutput,
|
|
29698
30200
|
partitionSessionHostDiagnosticsSessions,
|
|
29699
30201
|
partitionSessionHostRecords,
|
|
29700
30202
|
prepareSessionChatTailUpdate,
|
|
@@ -29704,6 +30206,7 @@ export {
|
|
|
29704
30206
|
recordDebugTrace,
|
|
29705
30207
|
registerExtensionProviders,
|
|
29706
30208
|
removeNode,
|
|
30209
|
+
removeWorktree,
|
|
29707
30210
|
resetConfig,
|
|
29708
30211
|
resetDebugRuntimeConfig,
|
|
29709
30212
|
resetState,
|
|
@@ -29713,6 +30216,7 @@ export {
|
|
|
29713
30216
|
resolveGitRepository,
|
|
29714
30217
|
resolveSessionHostAppName,
|
|
29715
30218
|
resolveSessionHostAppNameResolution,
|
|
30219
|
+
resolveWorktreePath,
|
|
29716
30220
|
runAsyncBatch,
|
|
29717
30221
|
runGit,
|
|
29718
30222
|
saveConfig,
|