@adhdev/daemon-core 0.9.76-rc.6 → 0.9.76-rc.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -1
- package/dist/cli-adapters/provider-cli-runtime.d.ts +1 -0
- package/dist/commands/cli-manager.d.ts +17 -4
- package/dist/commands/mesh-coordinator.d.ts +2 -0
- package/dist/commands/router.d.ts +11 -0
- package/dist/config/mesh-config.d.ts +3 -0
- package/dist/git/git-types.d.ts +1 -1
- package/dist/git/git-worktree.d.ts +64 -0
- package/dist/git/index.d.ts +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1525 -446
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1550 -477
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +1 -0
- package/dist/mesh/mesh-events.d.ts +9 -0
- package/dist/providers/chat-message-normalization.d.ts +11 -0
- package/dist/providers/cli-provider-instance.d.ts +3 -0
- package/dist/providers/provider-instance-manager.d.ts +1 -0
- package/dist/providers/provider-instance.d.ts +2 -0
- package/dist/repo-mesh-types.d.ts +27 -0
- package/dist/session-host/runtime-support.d.ts +2 -1
- package/dist/shared-types.d.ts +4 -0
- package/dist/types.d.ts +9 -0
- package/package.json +4 -5
- package/src/cli-adapters/provider-cli-adapter.ts +28 -7
- package/src/cli-adapters/provider-cli-runtime.ts +3 -2
- package/src/commands/chat-commands.ts +126 -11
- package/src/commands/cli-manager.ts +78 -5
- package/src/commands/handler.ts +13 -4
- package/src/commands/mesh-coordinator.ts +148 -5
- package/src/commands/router.d.ts +1 -0
- package/src/commands/router.ts +553 -34
- package/src/config/mesh-config.ts +23 -2
- package/src/git/git-commands.ts +5 -1
- package/src/git/git-types.ts +1 -0
- package/src/git/git-worktree.ts +214 -0
- package/src/git/index.ts +14 -0
- package/src/index.ts +3 -0
- package/src/mesh/coordinator-prompt.ts +29 -14
- package/src/mesh/mesh-events.ts +109 -43
- package/src/providers/chat-message-normalization.ts +80 -0
- package/src/providers/cli-provider-instance.d.ts +2 -0
- package/src/providers/cli-provider-instance.ts +93 -8
- package/src/providers/provider-instance-manager.ts +20 -1
- package/src/providers/provider-instance.ts +2 -0
- package/src/providers/read-chat-contract.ts +8 -0
- package/src/repo-mesh-types.ts +30 -0
- package/src/session-host/runtime-support.ts +55 -7
- package/src/shared-types.ts +4 -0
- package/src/status/builders.ts +17 -12
- package/src/status/reporter.ts +6 -0
- package/src/types.ts +9 -0
package/dist/index.js
CHANGED
|
@@ -41,11 +41,140 @@ var init_repo_mesh_types = __esm({
|
|
|
41
41
|
requireApprovalForPush: true,
|
|
42
42
|
requireApprovalForDestructiveGit: true,
|
|
43
43
|
dirtyWorkspaceBehavior: "warn",
|
|
44
|
-
maxParallelTasks: 2
|
|
44
|
+
maxParallelTasks: 2,
|
|
45
|
+
sessionCleanupOnNodeRemove: "preserve"
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
});
|
|
48
49
|
|
|
50
|
+
// src/git/git-worktree.ts
|
|
51
|
+
var git_worktree_exports = {};
|
|
52
|
+
__export(git_worktree_exports, {
|
|
53
|
+
createWorktree: () => createWorktree,
|
|
54
|
+
listWorktrees: () => listWorktrees,
|
|
55
|
+
parseWorktreeListOutput: () => parseWorktreeListOutput,
|
|
56
|
+
removeWorktree: () => removeWorktree,
|
|
57
|
+
resolveWorktreePath: () => resolveWorktreePath
|
|
58
|
+
});
|
|
59
|
+
function resolveWorktreePath(repoRoot, meshName, branch) {
|
|
60
|
+
const safeBranch = branch.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
|
|
61
|
+
const safeMeshName = meshName.replace(/[/\\:*?"<>|]/g, "-").replace(/^\.+|\.+$/g, "");
|
|
62
|
+
const parentDir = path4.dirname(repoRoot);
|
|
63
|
+
return path4.join(parentDir, WORKTREE_DIR_NAME, safeMeshName, safeBranch);
|
|
64
|
+
}
|
|
65
|
+
async function createWorktree(opts) {
|
|
66
|
+
const { repoRoot, branch, baseBranch, meshName } = opts;
|
|
67
|
+
const targetDir = opts.targetDir || resolveWorktreePath(repoRoot, meshName, branch);
|
|
68
|
+
if ((0, import_node_fs2.existsSync)(targetDir)) {
|
|
69
|
+
throw new Error(`Worktree target directory already exists: ${targetDir}`);
|
|
70
|
+
}
|
|
71
|
+
await (0, import_promises3.mkdir)(path4.dirname(targetDir), { recursive: true });
|
|
72
|
+
const args = ["worktree", "add", targetDir, "-b", branch];
|
|
73
|
+
if (baseBranch) {
|
|
74
|
+
args.push(baseBranch);
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
await execFileAsync2("git", args, {
|
|
78
|
+
cwd: repoRoot,
|
|
79
|
+
encoding: "utf8",
|
|
80
|
+
timeout: GIT_TIMEOUT_MS,
|
|
81
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
82
|
+
windowsHide: true
|
|
83
|
+
});
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const stderr = typeof error.stderr === "string" ? error.stderr : "";
|
|
86
|
+
if (/already exists/i.test(stderr)) {
|
|
87
|
+
throw new Error(`Branch '${branch}' already exists or is checked out in another worktree`);
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`git worktree add failed: ${stderr.trim() || error.message}`);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
worktreePath: targetDir,
|
|
94
|
+
branch
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async function removeWorktree(repoRoot, worktreePath) {
|
|
98
|
+
if (!(0, import_node_fs2.existsSync)(worktreePath)) {
|
|
99
|
+
await pruneWorktrees(repoRoot);
|
|
100
|
+
return { success: true, removedPath: worktreePath };
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
await execFileAsync2("git", ["worktree", "remove", worktreePath, "--force"], {
|
|
104
|
+
cwd: repoRoot,
|
|
105
|
+
encoding: "utf8",
|
|
106
|
+
timeout: GIT_TIMEOUT_MS,
|
|
107
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
108
|
+
windowsHide: true
|
|
109
|
+
});
|
|
110
|
+
} catch (error) {
|
|
111
|
+
const stderr = typeof error.stderr === "string" ? error.stderr : "";
|
|
112
|
+
throw new Error(`git worktree remove failed: ${stderr.trim() || error.message}`);
|
|
113
|
+
}
|
|
114
|
+
return { success: true, removedPath: worktreePath };
|
|
115
|
+
}
|
|
116
|
+
async function listWorktrees(repoRoot) {
|
|
117
|
+
const { stdout } = await execFileAsync2("git", ["worktree", "list", "--porcelain"], {
|
|
118
|
+
cwd: repoRoot,
|
|
119
|
+
encoding: "utf8",
|
|
120
|
+
timeout: GIT_TIMEOUT_MS,
|
|
121
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
122
|
+
windowsHide: true
|
|
123
|
+
});
|
|
124
|
+
return parseWorktreeListOutput(stdout);
|
|
125
|
+
}
|
|
126
|
+
function parseWorktreeListOutput(output) {
|
|
127
|
+
const entries = [];
|
|
128
|
+
const blocks = output.trim().split(/\n\n+/);
|
|
129
|
+
for (const block of blocks) {
|
|
130
|
+
if (!block.trim()) continue;
|
|
131
|
+
const lines = block.trim().split("\n");
|
|
132
|
+
const entry = { path: "", head: "", branch: null, bare: false };
|
|
133
|
+
for (const line of lines) {
|
|
134
|
+
if (line.startsWith("worktree ")) {
|
|
135
|
+
entry.path = line.slice("worktree ".length).trim();
|
|
136
|
+
} else if (line.startsWith("HEAD ")) {
|
|
137
|
+
entry.head = line.slice("HEAD ".length).trim();
|
|
138
|
+
} else if (line.startsWith("branch ")) {
|
|
139
|
+
const ref = line.slice("branch ".length).trim();
|
|
140
|
+
entry.branch = ref.replace(/^refs\/heads\//, "");
|
|
141
|
+
} else if (line === "bare") {
|
|
142
|
+
entry.bare = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (entry.path) {
|
|
146
|
+
entries.push(entry);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return entries;
|
|
150
|
+
}
|
|
151
|
+
async function pruneWorktrees(repoRoot) {
|
|
152
|
+
try {
|
|
153
|
+
await execFileAsync2("git", ["worktree", "prune"], {
|
|
154
|
+
cwd: repoRoot,
|
|
155
|
+
encoding: "utf8",
|
|
156
|
+
timeout: GIT_TIMEOUT_MS,
|
|
157
|
+
windowsHide: true
|
|
158
|
+
});
|
|
159
|
+
} catch {
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
var path4, import_promises3, import_node_fs2, import_node_child_process2, import_node_util2, execFileAsync2, WORKTREE_DIR_NAME, GIT_TIMEOUT_MS, GIT_MAX_BUFFER;
|
|
163
|
+
var init_git_worktree = __esm({
|
|
164
|
+
"src/git/git-worktree.ts"() {
|
|
165
|
+
"use strict";
|
|
166
|
+
path4 = __toESM(require("path"));
|
|
167
|
+
import_promises3 = require("fs/promises");
|
|
168
|
+
import_node_fs2 = require("fs");
|
|
169
|
+
import_node_child_process2 = require("child_process");
|
|
170
|
+
import_node_util2 = require("util");
|
|
171
|
+
execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
|
|
172
|
+
WORKTREE_DIR_NAME = ".adhdev-worktrees";
|
|
173
|
+
GIT_TIMEOUT_MS = 3e4;
|
|
174
|
+
GIT_MAX_BUFFER = 4 * 1024 * 1024;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
49
178
|
// src/config/config.ts
|
|
50
179
|
var config_exports = {};
|
|
51
180
|
__export(config_exports, {
|
|
@@ -304,10 +433,10 @@ function getMeshConfigPath() {
|
|
|
304
433
|
return (0, import_path2.join)(getConfigDir(), "meshes.json");
|
|
305
434
|
}
|
|
306
435
|
function loadMeshConfig() {
|
|
307
|
-
const
|
|
308
|
-
if (!(0, import_fs2.existsSync)(
|
|
436
|
+
const path27 = getMeshConfigPath();
|
|
437
|
+
if (!(0, import_fs2.existsSync)(path27)) return { meshes: [] };
|
|
309
438
|
try {
|
|
310
|
-
const raw = JSON.parse((0, import_fs2.readFileSync)(
|
|
439
|
+
const raw = JSON.parse((0, import_fs2.readFileSync)(path27, "utf-8"));
|
|
311
440
|
if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
|
|
312
441
|
return raw;
|
|
313
442
|
} catch {
|
|
@@ -315,16 +444,16 @@ function loadMeshConfig() {
|
|
|
315
444
|
}
|
|
316
445
|
}
|
|
317
446
|
function saveMeshConfig(config) {
|
|
318
|
-
const
|
|
319
|
-
(0, import_fs2.writeFileSync)(
|
|
447
|
+
const path27 = getMeshConfigPath();
|
|
448
|
+
(0, import_fs2.writeFileSync)(path27, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
|
|
320
449
|
}
|
|
321
450
|
function normalizeRepoIdentity(remoteUrl) {
|
|
322
451
|
let identity = remoteUrl.trim();
|
|
323
452
|
if (identity.startsWith("http://") || identity.startsWith("https://")) {
|
|
324
453
|
try {
|
|
325
454
|
const url = new URL(identity);
|
|
326
|
-
const
|
|
327
|
-
return `${url.hostname}/${
|
|
455
|
+
const path27 = url.pathname.replace(/^\//, "").replace(/\.git$/, "");
|
|
456
|
+
return `${url.hostname}/${path27}`;
|
|
328
457
|
} catch {
|
|
329
458
|
}
|
|
330
459
|
}
|
|
@@ -332,6 +461,18 @@ function normalizeRepoIdentity(remoteUrl) {
|
|
|
332
461
|
if (sshMatch) return `${sshMatch[1]}/${sshMatch[2]}`;
|
|
333
462
|
return identity;
|
|
334
463
|
}
|
|
464
|
+
function mergeMeshPolicy(base, patch) {
|
|
465
|
+
const policy = { ...DEFAULT_MESH_POLICY, ...base || {}, ...patch || {} };
|
|
466
|
+
if (!["block", "warn", "checkpoint_then_continue"].includes(policy.dirtyWorkspaceBehavior)) {
|
|
467
|
+
policy.dirtyWorkspaceBehavior = "warn";
|
|
468
|
+
}
|
|
469
|
+
const maxParallelTasks = Number(policy.maxParallelTasks);
|
|
470
|
+
policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
|
|
471
|
+
if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
|
|
472
|
+
policy.sessionCleanupOnNodeRemove = "preserve";
|
|
473
|
+
}
|
|
474
|
+
return policy;
|
|
475
|
+
}
|
|
335
476
|
function listMeshes() {
|
|
336
477
|
return loadMeshConfig().meshes;
|
|
337
478
|
}
|
|
@@ -355,7 +496,7 @@ function createMesh(opts) {
|
|
|
355
496
|
repoIdentity,
|
|
356
497
|
repoRemoteUrl: opts.repoRemoteUrl,
|
|
357
498
|
defaultBranch: opts.defaultBranch,
|
|
358
|
-
policy:
|
|
499
|
+
policy: mergeMeshPolicy(void 0, opts.policy),
|
|
359
500
|
coordinator: opts.coordinator || {},
|
|
360
501
|
nodes: [],
|
|
361
502
|
createdAt: now,
|
|
@@ -371,7 +512,7 @@ function updateMesh(meshId, opts) {
|
|
|
371
512
|
if (!mesh) return void 0;
|
|
372
513
|
if (opts.name !== void 0) mesh.name = opts.name.trim().slice(0, 100);
|
|
373
514
|
if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
|
|
374
|
-
if (opts.policy) mesh.policy =
|
|
515
|
+
if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
|
|
375
516
|
if (opts.coordinator) mesh.coordinator = opts.coordinator;
|
|
376
517
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
377
518
|
saveMeshConfig(config);
|
|
@@ -399,9 +540,12 @@ function addNode(meshId, opts) {
|
|
|
399
540
|
id: `node_${(0, import_crypto3.randomUUID)().replace(/-/g, "")}`,
|
|
400
541
|
workspace: opts.workspace.trim(),
|
|
401
542
|
repoRoot: opts.repoRoot,
|
|
543
|
+
daemonId: opts.daemonId,
|
|
402
544
|
userOverrides: opts.userOverrides || {},
|
|
403
545
|
policy: opts.policy || {},
|
|
404
|
-
isLocalWorktree: opts.isLocalWorktree
|
|
546
|
+
isLocalWorktree: opts.isLocalWorktree,
|
|
547
|
+
worktreeBranch: opts.worktreeBranch,
|
|
548
|
+
clonedFromNodeId: opts.clonedFromNodeId
|
|
405
549
|
};
|
|
406
550
|
mesh.nodes.push(node);
|
|
407
551
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -431,7 +575,7 @@ function updateNode(meshId, nodeId, opts) {
|
|
|
431
575
|
saveMeshConfig(config);
|
|
432
576
|
return node;
|
|
433
577
|
}
|
|
434
|
-
var import_fs2, import_path2, import_crypto3;
|
|
578
|
+
var import_fs2, import_path2, import_crypto3, SESSION_CLEANUP_MODES;
|
|
435
579
|
var init_mesh_config = __esm({
|
|
436
580
|
"src/config/mesh-config.ts"() {
|
|
437
581
|
"use strict";
|
|
@@ -440,6 +584,7 @@ var init_mesh_config = __esm({
|
|
|
440
584
|
import_crypto3 = require("crypto");
|
|
441
585
|
init_config();
|
|
442
586
|
init_repo_mesh_types();
|
|
587
|
+
SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
|
|
443
588
|
}
|
|
444
589
|
});
|
|
445
590
|
|
|
@@ -449,7 +594,7 @@ __export(coordinator_prompt_exports, {
|
|
|
449
594
|
buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt
|
|
450
595
|
});
|
|
451
596
|
function buildCoordinatorSystemPrompt(ctx) {
|
|
452
|
-
const { mesh, status, userInstruction } = ctx;
|
|
597
|
+
const { mesh, status, userInstruction, coordinatorCliType } = ctx;
|
|
453
598
|
const sections = [];
|
|
454
599
|
sections.push(`You are a **Repo Mesh Coordinator** \u2014 a technical team lead who orchestrates work across multiple agent sessions on a shared Git repository.
|
|
455
600
|
|
|
@@ -463,15 +608,15 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
463
608
|
} else {
|
|
464
609
|
sections.push("## Nodes\nNo nodes configured yet. Ask the user to add nodes with `adhdev mesh add-node`.");
|
|
465
610
|
}
|
|
466
|
-
sections.push(buildPolicySection(mesh.policy));
|
|
611
|
+
sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
|
|
467
612
|
sections.push(TOOLS_SECTION);
|
|
468
613
|
sections.push(WORKFLOW_SECTION);
|
|
469
|
-
sections.push(
|
|
614
|
+
sections.push(buildRulesSection(coordinatorCliType));
|
|
470
615
|
if (userInstruction) {
|
|
471
616
|
sections.push(`## Additional Context
|
|
472
617
|
${userInstruction}`);
|
|
473
618
|
}
|
|
474
|
-
if (mesh.coordinator
|
|
619
|
+
if (mesh.coordinator?.systemPromptSuffix) {
|
|
475
620
|
sections.push(mesh.coordinator.systemPromptSuffix);
|
|
476
621
|
}
|
|
477
622
|
return sections.join("\n\n");
|
|
@@ -516,10 +661,29 @@ function buildPolicySection(policy) {
|
|
|
516
661
|
return `## Policy
|
|
517
662
|
${rules.join("\n")}`;
|
|
518
663
|
}
|
|
519
|
-
|
|
664
|
+
function buildRulesSection(coordinatorCliType) {
|
|
665
|
+
const coordinatorNote = coordinatorCliType ? `
|
|
666
|
+
- **Coordinator runtime is not a delegation default.** This coordinator is running as \`${coordinatorCliType}\`, but delegated node sessions must follow the user's requested provider, not the coordinator's own runtime.` : "";
|
|
667
|
+
return `## Rules
|
|
668
|
+
|
|
669
|
+
- **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
|
|
670
|
+
- **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
|
|
671
|
+
- **Respect explicit provider requests.** If the user names an agent/provider, pass the matching provider type to \`mesh_launch_session\`: Hermes \u2192 \`hermes-cli\`, Claude Code/Claude \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`. Never substitute \`claude-cli\` just because the coordinator itself is Claude Code.
|
|
672
|
+
- **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
|
|
673
|
+
- **Don't inspect code.** Treat delegated agent summaries as self-reports, not verification. Verify side effects via \`mesh_git_status\` (including related repo freshness when configured), not by reading source files.
|
|
674
|
+
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed. Never launch a duplicate session or second worker solely because \`mesh_read_chat\` has no final assistant message while the delegated session is still showing tool/terminal activity.
|
|
675
|
+
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
676
|
+
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
677
|
+
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
678
|
+
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.
|
|
679
|
+
- **Clean up worktree nodes.** After a worktree task completes and its changes are merged or checkpointed, call \`mesh_remove_node\` to free resources.
|
|
680
|
+
- **Name worktree branches meaningfully.** Use descriptive names like \`feat/auth-refactor\` or \`fix/build-123\`.${coordinatorNote}`;
|
|
681
|
+
}
|
|
682
|
+
var TOOLS_SECTION, WORKFLOW_SECTION;
|
|
520
683
|
var init_coordinator_prompt = __esm({
|
|
521
684
|
"src/mesh/coordinator-prompt.ts"() {
|
|
522
685
|
"use strict";
|
|
686
|
+
init_repo_mesh_types();
|
|
523
687
|
TOOLS_SECTION = `## Available Tools
|
|
524
688
|
|
|
525
689
|
| Tool | Purpose |
|
|
@@ -531,30 +695,23 @@ var init_coordinator_prompt = __esm({
|
|
|
531
695
|
| \`mesh_read_chat\` | Read an agent's recent messages to check progress |
|
|
532
696
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
533
697
|
| \`mesh_checkpoint\` | Create a git checkpoint on a node |
|
|
534
|
-
| \`mesh_approve\` | Approve/reject a pending agent action
|
|
698
|
+
| \`mesh_approve\` | Approve/reject a pending agent action |
|
|
699
|
+
| \`mesh_clone_node\` | Create a worktree node for isolated parallel branch work |
|
|
700
|
+
| \`mesh_remove_node\` | Remove a node (cleans up worktree if applicable) |`;
|
|
535
701
|
WORKFLOW_SECTION = `## Orchestration Workflow
|
|
536
702
|
|
|
537
703
|
1. **Assess** \u2014 Call \`mesh_status\` to see which nodes are healthy and available.
|
|
538
704
|
2. **Plan** \u2014 Decompose the user's request into independent tasks for parallel execution, or sequential tasks when dependencies exist.
|
|
539
705
|
3. **Delegate** \u2014 For each task:
|
|
540
706
|
a. Pick the best node (consider: health, dirty state, current workload).
|
|
541
|
-
b. If
|
|
542
|
-
c.
|
|
543
|
-
|
|
544
|
-
|
|
707
|
+
b. If you need branch isolation for parallel work, call \`mesh_clone_node\` to create a worktree node first.
|
|
708
|
+
c. If no session exists, call \`mesh_launch_session\` to start one.
|
|
709
|
+
d. Call \`mesh_send_task\` with a **complete, self-contained** instruction that includes all context the agent needs (file paths, line numbers, what to change, why). Do not send partial instructions expecting future follow-up.
|
|
710
|
+
4. **Monitor** \u2014 Prefer event-driven completion/status notifications. Do **not** poll \`mesh_read_chat\` repeatedly just because the delegated session has not produced a final assistant message yet; tool/terminal activity means work may still be in progress. Do not call \`mesh_read_chat\` again within a few seconds for the same generating session; wait for the completion callback/status event instead unless you are debugging a real stall. Use at most one compact \`mesh_read_chat\` check after a completion/approval signal, an explicit user status request, or a real timeout/stall. Handle approvals via \`mesh_approve\`.
|
|
711
|
+
5. **Verify** \u2014 When a task reports completion or git work is visible, call \`mesh_git_status\` to verify changes were made.
|
|
545
712
|
6. **Checkpoint** \u2014 Call \`mesh_checkpoint\` to save the work.
|
|
546
|
-
7. **
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
- **Minimize coordinator context.** The coordinator's job is routing, not implementing. Do not read source files, run commands, or analyze code directly \u2014 delegate all of that to node agents. Your context should stay lean.
|
|
550
|
-
- **Delegate analysis too.** If you need to understand a bug or explore the codebase, send that investigation as a task to a node. Do not do it yourself.
|
|
551
|
-
- **Front-load the task message.** When calling \`mesh_send_task\`, include everything the agent needs: what files to touch, what the problem is, what the fix should look like. The agent won't ask follow-up questions.
|
|
552
|
-
- **Don't inspect code.** Trust the agent's output. Verify via \`mesh_git_status\`, not by reading source files.
|
|
553
|
-
- **Don't over-parallelize.** Start with 1-2 concurrent tasks. Scale up if they succeed.
|
|
554
|
-
- **Handle failures gracefully.** If a task fails, read the chat to understand why, then retry or reassign.
|
|
555
|
-
- **Keep the user informed.** Report progress after each delegation round \u2014 one or two sentences, not a narration.
|
|
556
|
-
- **Respect node capabilities.** Don't send build tasks to read-only nodes. Don't push from nodes that aren't allowed to.
|
|
557
|
-
- **Never fabricate tool results.** Always call the actual tool; never pretend you did.`;
|
|
713
|
+
7. **Clean up** \u2014 Remove worktree nodes via \`mesh_remove_node\` after their work is merged or no longer needed.
|
|
714
|
+
8. **Report** \u2014 Summarize what was done, what changed, and any issues.`;
|
|
558
715
|
}
|
|
559
716
|
});
|
|
560
717
|
|
|
@@ -573,13 +730,13 @@ function getDaemonLogDir() {
|
|
|
573
730
|
return LOG_DIR;
|
|
574
731
|
}
|
|
575
732
|
function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
|
|
576
|
-
return
|
|
733
|
+
return path10.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
|
|
577
734
|
}
|
|
578
735
|
function checkDateRotation() {
|
|
579
736
|
const today = getDateStr();
|
|
580
737
|
if (today !== currentDate) {
|
|
581
738
|
currentDate = today;
|
|
582
|
-
currentLogFile =
|
|
739
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
583
740
|
cleanOldLogs();
|
|
584
741
|
}
|
|
585
742
|
}
|
|
@@ -593,7 +750,7 @@ function cleanOldLogs() {
|
|
|
593
750
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
594
751
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
595
752
|
try {
|
|
596
|
-
fs2.unlinkSync(
|
|
753
|
+
fs2.unlinkSync(path10.join(LOG_DIR, file));
|
|
597
754
|
} catch {
|
|
598
755
|
}
|
|
599
756
|
}
|
|
@@ -709,17 +866,17 @@ function installGlobalInterceptor() {
|
|
|
709
866
|
writeToFile(`Log file: ${currentLogFile}`);
|
|
710
867
|
writeToFile(`Log level: ${currentLevel}`);
|
|
711
868
|
}
|
|
712
|
-
var fs2,
|
|
869
|
+
var fs2, path10, os4, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
|
|
713
870
|
var init_logger = __esm({
|
|
714
871
|
"src/logging/logger.ts"() {
|
|
715
872
|
"use strict";
|
|
716
873
|
fs2 = __toESM(require("fs"));
|
|
717
|
-
|
|
874
|
+
path10 = __toESM(require("path"));
|
|
718
875
|
os4 = __toESM(require("os"));
|
|
719
876
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
720
877
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
721
878
|
currentLevel = "info";
|
|
722
|
-
LOG_DIR = process.platform === "win32" ?
|
|
879
|
+
LOG_DIR = process.platform === "win32" ? path10.join(process.env.LOCALAPPDATA || process.env.APPDATA || path10.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path10.join(os4.homedir(), "Library", "Logs", "adhdev") : path10.join(os4.homedir(), ".local", "share", "adhdev", "logs");
|
|
723
880
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
724
881
|
MAX_LOG_DAYS = 7;
|
|
725
882
|
try {
|
|
@@ -727,16 +884,16 @@ var init_logger = __esm({
|
|
|
727
884
|
} catch {
|
|
728
885
|
}
|
|
729
886
|
currentDate = getDateStr();
|
|
730
|
-
currentLogFile =
|
|
887
|
+
currentLogFile = path10.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
731
888
|
cleanOldLogs();
|
|
732
889
|
try {
|
|
733
|
-
const oldLog =
|
|
890
|
+
const oldLog = path10.join(LOG_DIR, "daemon.log");
|
|
734
891
|
if (fs2.existsSync(oldLog)) {
|
|
735
892
|
const stat2 = fs2.statSync(oldLog);
|
|
736
893
|
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
737
|
-
fs2.renameSync(oldLog,
|
|
894
|
+
fs2.renameSync(oldLog, path10.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
738
895
|
}
|
|
739
|
-
const oldLogBackup =
|
|
896
|
+
const oldLogBackup = path10.join(LOG_DIR, "daemon.log.old");
|
|
740
897
|
if (fs2.existsSync(oldLogBackup)) {
|
|
741
898
|
fs2.unlinkSync(oldLogBackup);
|
|
742
899
|
}
|
|
@@ -768,7 +925,7 @@ var init_logger = __esm({
|
|
|
768
925
|
}
|
|
769
926
|
};
|
|
770
927
|
interceptorInstalled = false;
|
|
771
|
-
LOG_PATH =
|
|
928
|
+
LOG_PATH = path10.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
772
929
|
}
|
|
773
930
|
});
|
|
774
931
|
|
|
@@ -1236,9 +1393,9 @@ function buildCliScreenSnapshot(text) {
|
|
|
1236
1393
|
function findBinary(name) {
|
|
1237
1394
|
const trimmed = String(name || "").trim();
|
|
1238
1395
|
if (!trimmed) return trimmed;
|
|
1239
|
-
const expanded = trimmed.startsWith("~") ?
|
|
1240
|
-
if (
|
|
1241
|
-
return
|
|
1396
|
+
const expanded = trimmed.startsWith("~") ? path14.join(os9.homedir(), trimmed.slice(1)) : trimmed;
|
|
1397
|
+
if (path14.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
|
|
1398
|
+
return path14.isAbsolute(expanded) ? expanded : path14.resolve(expanded);
|
|
1242
1399
|
}
|
|
1243
1400
|
const isWin = os9.platform() === "win32";
|
|
1244
1401
|
try {
|
|
@@ -1254,7 +1411,7 @@ function findBinary(name) {
|
|
|
1254
1411
|
}
|
|
1255
1412
|
}
|
|
1256
1413
|
function isScriptBinary(binaryPath) {
|
|
1257
|
-
if (!
|
|
1414
|
+
if (!path14.isAbsolute(binaryPath)) return false;
|
|
1258
1415
|
try {
|
|
1259
1416
|
const fs16 = require("fs");
|
|
1260
1417
|
const resolved = fs16.realpathSync(binaryPath);
|
|
@@ -1270,7 +1427,7 @@ function isScriptBinary(binaryPath) {
|
|
|
1270
1427
|
}
|
|
1271
1428
|
}
|
|
1272
1429
|
function looksLikeMachOOrElf(filePath) {
|
|
1273
|
-
if (!
|
|
1430
|
+
if (!path14.isAbsolute(filePath)) return false;
|
|
1274
1431
|
try {
|
|
1275
1432
|
const fs16 = require("fs");
|
|
1276
1433
|
const resolved = fs16.realpathSync(filePath);
|
|
@@ -1359,12 +1516,12 @@ function normalizeCliProviderForRuntime(raw) {
|
|
|
1359
1516
|
}
|
|
1360
1517
|
};
|
|
1361
1518
|
}
|
|
1362
|
-
var os9,
|
|
1519
|
+
var os9, path14, import_child_process4, buildCliSpawnEnv;
|
|
1363
1520
|
var init_provider_cli_shared = __esm({
|
|
1364
1521
|
"src/cli-adapters/provider-cli-shared.ts"() {
|
|
1365
1522
|
"use strict";
|
|
1366
1523
|
os9 = __toESM(require("os"));
|
|
1367
|
-
|
|
1524
|
+
path14 = __toESM(require("path"));
|
|
1368
1525
|
import_child_process4 = require("child_process");
|
|
1369
1526
|
init_spawn_env();
|
|
1370
1527
|
buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
|
|
@@ -1487,7 +1644,7 @@ var init_provider_cli_config = __esm({
|
|
|
1487
1644
|
|
|
1488
1645
|
// src/cli-adapters/provider-cli-runtime.ts
|
|
1489
1646
|
function resolveCliSpawnPlan(options) {
|
|
1490
|
-
const { provider, runtimeSettings, workingDir, extraArgs } = options;
|
|
1647
|
+
const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
|
|
1491
1648
|
const { spawn: spawnConfig } = provider;
|
|
1492
1649
|
const configuredCommand = typeof runtimeSettings.executablePath === "string" && runtimeSettings.executablePath.trim() ? runtimeSettings.executablePath.trim() : spawnConfig.command;
|
|
1493
1650
|
const binaryPath = findBinary(configuredCommand);
|
|
@@ -1495,9 +1652,9 @@ function resolveCliSpawnPlan(options) {
|
|
|
1495
1652
|
const allArgs = [...spawnConfig.args, ...extraArgs];
|
|
1496
1653
|
let shellCmd;
|
|
1497
1654
|
let shellArgs;
|
|
1498
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1655
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1499
1656
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
1500
|
-
const useShellWin = !!spawnConfig.shell || isCmdShim || !
|
|
1657
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path15.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
1501
1658
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
1502
1659
|
if (useShell) {
|
|
1503
1660
|
shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
|
|
@@ -1511,7 +1668,7 @@ function resolveCliSpawnPlan(options) {
|
|
|
1511
1668
|
shellCmd = binaryPath;
|
|
1512
1669
|
shellArgs = allArgs;
|
|
1513
1670
|
}
|
|
1514
|
-
const env = buildCliSpawnEnv(process.env, spawnConfig.env);
|
|
1671
|
+
const env = buildCliSpawnEnv(process.env, { ...spawnConfig.env || {}, ...extraEnv || {} });
|
|
1515
1672
|
env.TERMINAL_CWD = workingDir;
|
|
1516
1673
|
return {
|
|
1517
1674
|
binaryPath,
|
|
@@ -1573,12 +1730,12 @@ function respondToCliTerminalQueries(options) {
|
|
|
1573
1730
|
}
|
|
1574
1731
|
return "";
|
|
1575
1732
|
}
|
|
1576
|
-
var os10,
|
|
1733
|
+
var os10, path15, import_session_host_core2;
|
|
1577
1734
|
var init_provider_cli_runtime = __esm({
|
|
1578
1735
|
"src/cli-adapters/provider-cli-runtime.ts"() {
|
|
1579
1736
|
"use strict";
|
|
1580
1737
|
os10 = __toESM(require("os"));
|
|
1581
|
-
|
|
1738
|
+
path15 = __toESM(require("path"));
|
|
1582
1739
|
import_session_host_core2 = require("@adhdev/session-host-core");
|
|
1583
1740
|
init_provider_cli_shared();
|
|
1584
1741
|
}
|
|
@@ -1614,8 +1771,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1614
1771
|
init_provider_cli_runtime();
|
|
1615
1772
|
init_provider_cli_shared();
|
|
1616
1773
|
ProviderCliAdapter = class _ProviderCliAdapter {
|
|
1617
|
-
constructor(provider, workingDir, extraArgs = [], transportFactory = new NodePtyTransportFactory()) {
|
|
1774
|
+
constructor(provider, workingDir, extraArgs = [], extraEnv = {}, transportFactory = new NodePtyTransportFactory()) {
|
|
1618
1775
|
this.extraArgs = extraArgs;
|
|
1776
|
+
this.extraEnv = extraEnv;
|
|
1619
1777
|
this.provider = provider;
|
|
1620
1778
|
this.transportFactory = transportFactory;
|
|
1621
1779
|
this.cliType = provider.type;
|
|
@@ -1766,8 +1924,9 @@ var init_provider_cli_adapter = __esm({
|
|
|
1766
1924
|
const currentSnapshot = normalizeScreenSnapshot(screenText);
|
|
1767
1925
|
const lastSnapshot = this.lastScreenSnapshot;
|
|
1768
1926
|
if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
|
|
1769
|
-
const
|
|
1770
|
-
const
|
|
1927
|
+
const activeScreenPattern = /\besc to (?:interrupt|stop)\b|Enter to interrupt, Ctrl\+C to cancel|Enter to confirm\s*[·•-]\s*Esc to cancel|\b(?:MCP servers?|tool calls?)\b[^\n\r]{0,160}\brequire approval\b/i;
|
|
1928
|
+
const staleSnapshotLooksActive = activeScreenPattern.test(lastSnapshot);
|
|
1929
|
+
const currentScreenLooksIdle = /(?:^|\n|\r)\s*[❯›>]\s*(?:Try\s+["“][^\n\r"”]+["”])?\s*(?:\n|\r|$)/.test(screenText) && !activeScreenPattern.test(screenText);
|
|
1771
1930
|
if (staleSnapshotLooksActive && currentScreenLooksIdle) return screenText;
|
|
1772
1931
|
if (currentSnapshot.length >= lastSnapshot.length) return screenText;
|
|
1773
1932
|
return `${screenText}
|
|
@@ -1930,7 +2089,8 @@ ${lastSnapshot}`;
|
|
|
1930
2089
|
provider: this.provider,
|
|
1931
2090
|
runtimeSettings: this.runtimeSettings,
|
|
1932
2091
|
workingDir: this.workingDir,
|
|
1933
|
-
extraArgs: this.extraArgs
|
|
2092
|
+
extraArgs: this.extraArgs,
|
|
2093
|
+
extraEnv: this.extraEnv
|
|
1934
2094
|
});
|
|
1935
2095
|
LOG.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
1936
2096
|
this.resetTraceSession();
|
|
@@ -3128,9 +3288,8 @@ ${lastSnapshot}`;
|
|
|
3128
3288
|
};
|
|
3129
3289
|
this.recordTrace("submit_echo_missing", diagnostic);
|
|
3130
3290
|
if (this.requirePromptEchoBeforeSubmit) {
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
completion.rejectOnce(new Error(message));
|
|
3291
|
+
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending guarded submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
|
|
3292
|
+
this.submitSendKey(state, completion);
|
|
3134
3293
|
return;
|
|
3135
3294
|
}
|
|
3136
3295
|
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
|
|
@@ -3177,7 +3336,14 @@ ${lastSnapshot}`;
|
|
|
3177
3336
|
})() : null;
|
|
3178
3337
|
const parsedSessionStatus = typeof parsedStatusBeforeSend?.status === "string" ? String(parsedStatusBeforeSend.status) : "";
|
|
3179
3338
|
if (!allowInputDuringGeneration && (parsedSessionStatus === "generating" || parsedSessionStatus === "long_generating")) {
|
|
3180
|
-
|
|
3339
|
+
const parsedModal = parsedStatusBeforeSend?.activeModal ?? parsedStatusBeforeSend?.modal ?? null;
|
|
3340
|
+
const parsedHasActionableModal = Boolean(
|
|
3341
|
+
parsedModal && Array.isArray(parsedModal.buttons) && parsedModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim())
|
|
3342
|
+
);
|
|
3343
|
+
const terminalLooksIdle = this.currentStatus === "idle" && this.runDetectStatus(this.recentOutputBuffer) === "idle" && !this.isWaitingForResponse && !this.currentTurnScope && !this.hasActionableApproval() && !parsedHasActionableModal;
|
|
3344
|
+
if (!terminalLooksIdle) {
|
|
3345
|
+
throw new Error(`${this.cliName} is still processing the previous prompt`);
|
|
3346
|
+
}
|
|
3181
3347
|
}
|
|
3182
3348
|
if (this.isWaitingForResponse && !allowInputDuringGeneration) {
|
|
3183
3349
|
if (!this.clearStaleIdleResponseGuard("send_message_guard")) {
|
|
@@ -3727,12 +3893,14 @@ __export(index_exports, {
|
|
|
3727
3893
|
createGitWorkspaceMonitor: () => createGitWorkspaceMonitor,
|
|
3728
3894
|
createInteractionId: () => createInteractionId,
|
|
3729
3895
|
createMesh: () => createMesh,
|
|
3896
|
+
createWorktree: () => createWorktree,
|
|
3730
3897
|
deleteMesh: () => deleteMesh,
|
|
3731
3898
|
detectAllVersions: () => detectAllVersions,
|
|
3732
3899
|
detectCLIs: () => detectCLIs,
|
|
3733
3900
|
detectIDEs: () => detectIDEs,
|
|
3734
3901
|
ensureSessionHostReady: () => ensureSessionHostReady,
|
|
3735
3902
|
execNpmCommandSync: () => execNpmCommandSync,
|
|
3903
|
+
filterUserFacingChatMessages: () => filterUserFacingChatMessages,
|
|
3736
3904
|
findCdpManager: () => findCdpManager,
|
|
3737
3905
|
flattenMessageParts: () => flattenMessageParts,
|
|
3738
3906
|
forwardAgentStreamsToIdeInstance: () => forwardAgentStreamsToIdeInstance,
|
|
@@ -3774,11 +3942,13 @@ __export(index_exports, {
|
|
|
3774
3942
|
isSessionHostLiveRuntime: () => isSessionHostLiveRuntime,
|
|
3775
3943
|
isSessionHostRecoverySnapshot: () => isSessionHostRecoverySnapshot,
|
|
3776
3944
|
isSetupComplete: () => isSetupComplete,
|
|
3945
|
+
isUserFacingChatMessage: () => isUserFacingChatMessage,
|
|
3777
3946
|
killIdeProcess: () => killIdeProcess,
|
|
3778
3947
|
launchIDE: () => launchIDE,
|
|
3779
3948
|
launchWithCdp: () => launchWithCdp,
|
|
3780
3949
|
listHostedCliRuntimes: () => listHostedCliRuntimes,
|
|
3781
3950
|
listMeshes: () => listMeshes,
|
|
3951
|
+
listWorktrees: () => listWorktrees,
|
|
3782
3952
|
loadConfig: () => loadConfig,
|
|
3783
3953
|
loadState: () => loadState,
|
|
3784
3954
|
logCommand: () => logCommand,
|
|
@@ -3798,6 +3968,7 @@ __export(index_exports, {
|
|
|
3798
3968
|
normalizeSessionModalFields: () => normalizeSessionModalFields,
|
|
3799
3969
|
parsePorcelainV2Status: () => parsePorcelainV2Status,
|
|
3800
3970
|
parseProviderSourceConfigUpdate: () => parseProviderSourceConfigUpdate,
|
|
3971
|
+
parseWorktreeListOutput: () => parseWorktreeListOutput,
|
|
3801
3972
|
partitionSessionHostDiagnosticsSessions: () => partitionSessionHostDiagnosticsSessions,
|
|
3802
3973
|
partitionSessionHostRecords: () => partitionSessionHostRecords,
|
|
3803
3974
|
prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
|
|
@@ -3807,6 +3978,7 @@ __export(index_exports, {
|
|
|
3807
3978
|
recordDebugTrace: () => recordDebugTrace,
|
|
3808
3979
|
registerExtensionProviders: () => registerExtensionProviders,
|
|
3809
3980
|
removeNode: () => removeNode,
|
|
3981
|
+
removeWorktree: () => removeWorktree,
|
|
3810
3982
|
resetConfig: () => resetConfig,
|
|
3811
3983
|
resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
|
|
3812
3984
|
resetState: () => resetState,
|
|
@@ -3816,6 +3988,7 @@ __export(index_exports, {
|
|
|
3816
3988
|
resolveGitRepository: () => resolveGitRepository,
|
|
3817
3989
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
3818
3990
|
resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
|
|
3991
|
+
resolveWorktreePath: () => resolveWorktreePath,
|
|
3819
3992
|
runAsyncBatch: () => runAsyncBatch,
|
|
3820
3993
|
runGit: () => runGit,
|
|
3821
3994
|
saveConfig: () => saveConfig,
|
|
@@ -4739,6 +4912,7 @@ var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
|
4739
4912
|
"dirty_index_required",
|
|
4740
4913
|
"conflict",
|
|
4741
4914
|
"invalid_args",
|
|
4915
|
+
"nothing_to_commit",
|
|
4742
4916
|
"git_command_failed"
|
|
4743
4917
|
]);
|
|
4744
4918
|
function failure(reason, error) {
|
|
@@ -4983,7 +5157,10 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
|
4983
5157
|
} catch (err) {
|
|
4984
5158
|
const output = (err?.stdout || "") + (err?.stderr || "");
|
|
4985
5159
|
if (/nothing to commit/i.test(output)) {
|
|
4986
|
-
throw new GitCommandError("
|
|
5160
|
+
throw new GitCommandError("nothing_to_commit", "Nothing to commit \u2014 working tree is clean.", {
|
|
5161
|
+
stdout: err?.stdout,
|
|
5162
|
+
stderr: err?.stderr
|
|
5163
|
+
});
|
|
4987
5164
|
}
|
|
4988
5165
|
throw err;
|
|
4989
5166
|
}
|
|
@@ -5175,20 +5352,23 @@ var TurnSnapshotTracker = class {
|
|
|
5175
5352
|
}
|
|
5176
5353
|
};
|
|
5177
5354
|
|
|
5355
|
+
// src/git/index.ts
|
|
5356
|
+
init_git_worktree();
|
|
5357
|
+
|
|
5178
5358
|
// src/index.ts
|
|
5179
5359
|
init_config();
|
|
5180
5360
|
|
|
5181
5361
|
// src/config/workspaces.ts
|
|
5182
5362
|
var fs = __toESM(require("fs"));
|
|
5183
5363
|
var os = __toESM(require("os"));
|
|
5184
|
-
var
|
|
5364
|
+
var path5 = __toESM(require("path"));
|
|
5185
5365
|
var import_crypto2 = require("crypto");
|
|
5186
5366
|
var MAX_WORKSPACES = 50;
|
|
5187
5367
|
function expandPath(p) {
|
|
5188
5368
|
const t = (p || "").trim();
|
|
5189
5369
|
if (!t) return "";
|
|
5190
|
-
if (t.startsWith("~")) return
|
|
5191
|
-
return
|
|
5370
|
+
if (t.startsWith("~")) return path5.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5371
|
+
return path5.resolve(t);
|
|
5192
5372
|
}
|
|
5193
5373
|
function validateWorkspacePath(absPath) {
|
|
5194
5374
|
try {
|
|
@@ -5202,7 +5382,7 @@ function validateWorkspacePath(absPath) {
|
|
|
5202
5382
|
}
|
|
5203
5383
|
}
|
|
5204
5384
|
function defaultWorkspaceLabel(absPath) {
|
|
5205
|
-
const base =
|
|
5385
|
+
const base = path5.basename(absPath) || absPath;
|
|
5206
5386
|
return base;
|
|
5207
5387
|
}
|
|
5208
5388
|
function getDefaultWorkspacePath(config) {
|
|
@@ -5293,9 +5473,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
5293
5473
|
return getDefaultWorkspacePath(config) || void 0;
|
|
5294
5474
|
}
|
|
5295
5475
|
function findWorkspaceByPath(config, rawPath) {
|
|
5296
|
-
const abs =
|
|
5476
|
+
const abs = path5.resolve(expandPath(rawPath));
|
|
5297
5477
|
if (!abs) return void 0;
|
|
5298
|
-
return (config.workspaces || []).find((w) =>
|
|
5478
|
+
return (config.workspaces || []).find((w) => path5.resolve(expandPath(w.path)) === abs);
|
|
5299
5479
|
}
|
|
5300
5480
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
5301
5481
|
const abs = expandPath(rawPath);
|
|
@@ -5311,7 +5491,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
5311
5491
|
const v = validateWorkspacePath(abs);
|
|
5312
5492
|
if (!v.ok) return { error: v.error };
|
|
5313
5493
|
const list = [...config.workspaces || []];
|
|
5314
|
-
if (list.some((w) =>
|
|
5494
|
+
if (list.some((w) => path5.resolve(w.path) === abs)) {
|
|
5315
5495
|
return { error: "Workspace already in list" };
|
|
5316
5496
|
}
|
|
5317
5497
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -5345,7 +5525,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
5345
5525
|
}
|
|
5346
5526
|
|
|
5347
5527
|
// src/config/recent-activity.ts
|
|
5348
|
-
var
|
|
5528
|
+
var path6 = __toESM(require("path"));
|
|
5349
5529
|
|
|
5350
5530
|
// src/providers/summary-metadata.ts
|
|
5351
5531
|
function normalizeSummaryItem(item) {
|
|
@@ -5414,9 +5594,9 @@ var MAX_ACTIVITY = 30;
|
|
|
5414
5594
|
function normalizeWorkspace(workspace) {
|
|
5415
5595
|
if (!workspace) return "";
|
|
5416
5596
|
try {
|
|
5417
|
-
return
|
|
5597
|
+
return path6.resolve(expandPath(workspace));
|
|
5418
5598
|
} catch {
|
|
5419
|
-
return
|
|
5599
|
+
return path6.resolve(workspace);
|
|
5420
5600
|
}
|
|
5421
5601
|
}
|
|
5422
5602
|
function buildRecentActivityKey(entry) {
|
|
@@ -5584,14 +5764,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5584
5764
|
}
|
|
5585
5765
|
|
|
5586
5766
|
// src/config/saved-sessions.ts
|
|
5587
|
-
var
|
|
5767
|
+
var path7 = __toESM(require("path"));
|
|
5588
5768
|
var MAX_SAVED_SESSIONS = 500;
|
|
5589
5769
|
function normalizeWorkspace2(workspace) {
|
|
5590
5770
|
if (!workspace) return "";
|
|
5591
5771
|
try {
|
|
5592
|
-
return
|
|
5772
|
+
return path7.resolve(expandPath(workspace));
|
|
5593
5773
|
} catch {
|
|
5594
|
-
return
|
|
5774
|
+
return path7.resolve(workspace);
|
|
5595
5775
|
}
|
|
5596
5776
|
}
|
|
5597
5777
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5770,7 +5950,7 @@ function resetState() {
|
|
|
5770
5950
|
var import_child_process = require("child_process");
|
|
5771
5951
|
var import_fs4 = require("fs");
|
|
5772
5952
|
var import_os2 = require("os");
|
|
5773
|
-
var
|
|
5953
|
+
var path8 = __toESM(require("path"));
|
|
5774
5954
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5775
5955
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5776
5956
|
function registerIDEDefinition(def) {
|
|
@@ -5789,9 +5969,9 @@ function getMergedDefinitions() {
|
|
|
5789
5969
|
function findCliCommand(command) {
|
|
5790
5970
|
const trimmed = String(command || "").trim();
|
|
5791
5971
|
if (!trimmed) return null;
|
|
5792
|
-
if (
|
|
5793
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5794
|
-
const resolved =
|
|
5972
|
+
if (path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
5973
|
+
const candidate = trimmed.startsWith("~") ? path8.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
|
|
5974
|
+
const resolved = path8.isAbsolute(candidate) ? candidate : path8.resolve(candidate);
|
|
5795
5975
|
return (0, import_fs4.existsSync)(resolved) ? resolved : null;
|
|
5796
5976
|
}
|
|
5797
5977
|
try {
|
|
@@ -5819,7 +5999,7 @@ function getIdeVersion(cliCommand) {
|
|
|
5819
5999
|
function checkPathExists(paths) {
|
|
5820
6000
|
const home = (0, import_os2.homedir)();
|
|
5821
6001
|
for (const p of paths) {
|
|
5822
|
-
const normalized = p.startsWith("~") ?
|
|
6002
|
+
const normalized = p.startsWith("~") ? path8.join(home, p.slice(1)) : p;
|
|
5823
6003
|
if (normalized.includes("*")) {
|
|
5824
6004
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5825
6005
|
const resolved = normalized.replace("*", username);
|
|
@@ -5831,19 +6011,19 @@ function checkPathExists(paths) {
|
|
|
5831
6011
|
return null;
|
|
5832
6012
|
}
|
|
5833
6013
|
async function detectIDEs(providerLoader) {
|
|
5834
|
-
const
|
|
6014
|
+
const os22 = (0, import_os2.platform)();
|
|
5835
6015
|
const results = [];
|
|
5836
6016
|
for (const def of getMergedDefinitions()) {
|
|
5837
6017
|
const cliPath = findCliCommand(providerLoader?.getIdeCliCommand(def.id, def.cli) || def.cli);
|
|
5838
|
-
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[
|
|
6018
|
+
const appPath = checkPathExists(providerLoader?.getIdePathCandidates(def.id, def.paths[os22] || []) || []);
|
|
5839
6019
|
let resolvedCli = cliPath;
|
|
5840
|
-
if (!resolvedCli && appPath &&
|
|
6020
|
+
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
5841
6021
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
5842
6022
|
if ((0, import_fs4.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
5843
6023
|
}
|
|
5844
|
-
if (!resolvedCli && appPath &&
|
|
5845
|
-
const { dirname:
|
|
5846
|
-
const appDir =
|
|
6024
|
+
if (!resolvedCli && appPath && os22 === "win32") {
|
|
6025
|
+
const { dirname: dirname9 } = await import("path");
|
|
6026
|
+
const appDir = dirname9(appPath);
|
|
5847
6027
|
const candidates = [
|
|
5848
6028
|
`${appDir}\\\\bin\\\\${def.cli}.cmd`,
|
|
5849
6029
|
`${appDir}\\\\bin\\\\${def.cli}`,
|
|
@@ -5858,7 +6038,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5858
6038
|
}
|
|
5859
6039
|
}
|
|
5860
6040
|
}
|
|
5861
|
-
const installed =
|
|
6041
|
+
const installed = os22 === "darwin" ? !!(resolvedCli || appPath) : !!resolvedCli;
|
|
5862
6042
|
const version = resolvedCli ? getIdeVersion(resolvedCli) : null;
|
|
5863
6043
|
results.push({
|
|
5864
6044
|
id: def.id,
|
|
@@ -5877,7 +6057,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5877
6057
|
// src/detection/cli-detector.ts
|
|
5878
6058
|
var import_child_process2 = require("child_process");
|
|
5879
6059
|
var os2 = __toESM(require("os"));
|
|
5880
|
-
var
|
|
6060
|
+
var path9 = __toESM(require("path"));
|
|
5881
6061
|
var import_fs5 = require("fs");
|
|
5882
6062
|
function parseVersion(raw) {
|
|
5883
6063
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
@@ -5890,18 +6070,18 @@ function shellQuote(value) {
|
|
|
5890
6070
|
function expandHome(value) {
|
|
5891
6071
|
const trimmed = value.trim();
|
|
5892
6072
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5893
|
-
return
|
|
6073
|
+
return path9.join(os2.homedir(), trimmed.slice(1));
|
|
5894
6074
|
}
|
|
5895
6075
|
function isExplicitCommandPath(command) {
|
|
5896
6076
|
const trimmed = command.trim();
|
|
5897
|
-
return
|
|
6077
|
+
return path9.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5898
6078
|
}
|
|
5899
6079
|
function resolveCommandPath(command) {
|
|
5900
6080
|
const trimmed = command.trim();
|
|
5901
6081
|
if (!trimmed) return null;
|
|
5902
6082
|
if (isExplicitCommandPath(trimmed)) {
|
|
5903
6083
|
const expanded = expandHome(trimmed);
|
|
5904
|
-
const candidate =
|
|
6084
|
+
const candidate = path9.isAbsolute(expanded) ? expanded : path9.resolve(expanded);
|
|
5905
6085
|
return (0, import_fs5.existsSync)(candidate) ? candidate : null;
|
|
5906
6086
|
}
|
|
5907
6087
|
return null;
|
|
@@ -7974,6 +8154,44 @@ function normalizeChatMessage(message) {
|
|
|
7974
8154
|
function normalizeChatMessages(messages) {
|
|
7975
8155
|
return (Array.isArray(messages) ? messages : []).map((message) => normalizeChatMessage(message));
|
|
7976
8156
|
}
|
|
8157
|
+
function readMessageMeta(message) {
|
|
8158
|
+
const meta = message?.meta;
|
|
8159
|
+
return meta && typeof meta === "object" && !Array.isArray(meta) ? meta : null;
|
|
8160
|
+
}
|
|
8161
|
+
function readStringField(value) {
|
|
8162
|
+
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
8163
|
+
}
|
|
8164
|
+
function readVisibilityField(message, meta) {
|
|
8165
|
+
const record = message;
|
|
8166
|
+
return readStringField(record.visibility ?? record.transcriptVisibility ?? meta?.visibility ?? meta?.transcriptVisibility);
|
|
8167
|
+
}
|
|
8168
|
+
function isExplicitlyHiddenFromTranscript(message, meta) {
|
|
8169
|
+
const record = message;
|
|
8170
|
+
const visibility = readVisibilityField(message, meta);
|
|
8171
|
+
const audience = readStringField(record.audience ?? meta?.audience);
|
|
8172
|
+
const source = readStringField(record.source ?? meta?.source);
|
|
8173
|
+
return visibility === "hidden" || visibility === "debug" || visibility === "internal" || audience === "debug" || audience === "trace" || audience === "internal" || source === "runtime_status" || source === "runtime_activity" || source === "provider_chrome" || source === "control" || record.internal === true || record.isInternal === true || record.debug === true || meta?.internal === true || meta?.isInternal === true || meta?.debug === true || meta?.statusOnly === true || meta?.controlOnly === true;
|
|
8174
|
+
}
|
|
8175
|
+
function isExplicitlyVisibleInTranscript(message, meta) {
|
|
8176
|
+
const record = message;
|
|
8177
|
+
const visibility = readVisibilityField(message, meta);
|
|
8178
|
+
const audience = readStringField(record.audience ?? meta?.audience);
|
|
8179
|
+
return visibility === "visible" || visibility === "user" || visibility === "chat" || audience === "chat" || record.userFacing === true || meta?.userFacing === true;
|
|
8180
|
+
}
|
|
8181
|
+
function isUserFacingChatMessage(message) {
|
|
8182
|
+
if (!message) return false;
|
|
8183
|
+
const meta = readMessageMeta(message);
|
|
8184
|
+
if (isExplicitlyHiddenFromTranscript(message, meta)) return false;
|
|
8185
|
+
if (isExplicitlyVisibleInTranscript(message, meta)) return true;
|
|
8186
|
+
const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
8187
|
+
const kind = resolveChatMessageKind(message);
|
|
8188
|
+
if (role === "user" || role === "human") return kind === "standard" || kind === "";
|
|
8189
|
+
if (role === "assistant") return kind === "standard" || kind === "";
|
|
8190
|
+
return false;
|
|
8191
|
+
}
|
|
8192
|
+
function filterUserFacingChatMessages(messages) {
|
|
8193
|
+
return (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
|
|
8194
|
+
}
|
|
7977
8195
|
|
|
7978
8196
|
// src/providers/control-effects.ts
|
|
7979
8197
|
function extractProviderControlValues(controls, data) {
|
|
@@ -8170,9 +8388,9 @@ ${cleanBody}`;
|
|
|
8170
8388
|
|
|
8171
8389
|
// src/config/chat-history.ts
|
|
8172
8390
|
var fs3 = __toESM(require("fs"));
|
|
8173
|
-
var
|
|
8391
|
+
var path11 = __toESM(require("path"));
|
|
8174
8392
|
var os5 = __toESM(require("os"));
|
|
8175
|
-
var HISTORY_DIR =
|
|
8393
|
+
var HISTORY_DIR = path11.join(os5.homedir(), ".adhdev", "history");
|
|
8176
8394
|
var RETAIN_DAYS = 30;
|
|
8177
8395
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
8178
8396
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -8335,7 +8553,7 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
8335
8553
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
8336
8554
|
return new Map(files.map((file) => {
|
|
8337
8555
|
try {
|
|
8338
|
-
const stat2 = fs3.statSync(
|
|
8556
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8339
8557
|
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
8340
8558
|
} catch {
|
|
8341
8559
|
return [file, `${file}:missing`];
|
|
@@ -8346,7 +8564,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
8346
8564
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
8347
8565
|
}
|
|
8348
8566
|
function getSavedHistoryIndexFilePath(dir) {
|
|
8349
|
-
return
|
|
8567
|
+
return path11.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
8350
8568
|
}
|
|
8351
8569
|
function getSavedHistoryIndexLockPath(dir) {
|
|
8352
8570
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -8448,7 +8666,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
8448
8666
|
}
|
|
8449
8667
|
for (const file of Array.from(currentEntries.keys())) {
|
|
8450
8668
|
if (incomingFiles.has(file)) continue;
|
|
8451
|
-
if (!fs3.existsSync(
|
|
8669
|
+
if (!fs3.existsSync(path11.join(dir, file))) {
|
|
8452
8670
|
currentEntries.delete(file);
|
|
8453
8671
|
}
|
|
8454
8672
|
}
|
|
@@ -8474,7 +8692,7 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8474
8692
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8475
8693
|
const files = listHistoryFiles(dir);
|
|
8476
8694
|
for (const file of files) {
|
|
8477
|
-
const stat2 = fs3.statSync(
|
|
8695
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8478
8696
|
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
8479
8697
|
}
|
|
8480
8698
|
return false;
|
|
@@ -8484,14 +8702,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
8484
8702
|
}
|
|
8485
8703
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
8486
8704
|
try {
|
|
8487
|
-
const stat2 = fs3.statSync(
|
|
8705
|
+
const stat2 = fs3.statSync(path11.join(dir, file));
|
|
8488
8706
|
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
8489
8707
|
} catch {
|
|
8490
8708
|
return `${file}:missing`;
|
|
8491
8709
|
}
|
|
8492
8710
|
}
|
|
8493
8711
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
8494
|
-
const filePath =
|
|
8712
|
+
const filePath = path11.join(dir, file);
|
|
8495
8713
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
8496
8714
|
const currentEntry = entries.get(file) || null;
|
|
8497
8715
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -8564,7 +8782,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
8564
8782
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
8565
8783
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
8566
8784
|
if (!historySessionId) return null;
|
|
8567
|
-
const filePath =
|
|
8785
|
+
const filePath = path11.join(dir, file);
|
|
8568
8786
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8569
8787
|
const lines = content.split("\n").filter(Boolean);
|
|
8570
8788
|
let messageCount = 0;
|
|
@@ -8651,7 +8869,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
8651
8869
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
8652
8870
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
8653
8871
|
for (const file of files.slice().sort()) {
|
|
8654
|
-
const filePath =
|
|
8872
|
+
const filePath = path11.join(dir, file);
|
|
8655
8873
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
8656
8874
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
8657
8875
|
const persisted = persistedEntries.get(file);
|
|
@@ -8771,12 +8989,12 @@ var ChatHistoryWriter = class {
|
|
|
8771
8989
|
});
|
|
8772
8990
|
}
|
|
8773
8991
|
if (newMessages.length === 0) return;
|
|
8774
|
-
const dir =
|
|
8992
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8775
8993
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8776
8994
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8777
8995
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
8778
8996
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
8779
|
-
const filePath =
|
|
8997
|
+
const filePath = path11.join(dir, fileName);
|
|
8780
8998
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
8781
8999
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
8782
9000
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -8867,11 +9085,11 @@ var ChatHistoryWriter = class {
|
|
|
8867
9085
|
const ws = String(workspace || "").trim();
|
|
8868
9086
|
if (!id || !ws) return;
|
|
8869
9087
|
try {
|
|
8870
|
-
const dir =
|
|
9088
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8871
9089
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8872
9090
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8873
9091
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
8874
|
-
const filePath =
|
|
9092
|
+
const filePath = path11.join(dir, fileName);
|
|
8875
9093
|
const record = {
|
|
8876
9094
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8877
9095
|
receivedAt: Date.now(),
|
|
@@ -8917,14 +9135,14 @@ var ChatHistoryWriter = class {
|
|
|
8917
9135
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8918
9136
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8919
9137
|
}
|
|
8920
|
-
const dir =
|
|
9138
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8921
9139
|
if (!fs3.existsSync(dir)) return;
|
|
8922
9140
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8923
9141
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8924
9142
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8925
9143
|
for (const file of files) {
|
|
8926
|
-
const sourcePath =
|
|
8927
|
-
const targetPath =
|
|
9144
|
+
const sourcePath = path11.join(dir, file);
|
|
9145
|
+
const targetPath = path11.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8928
9146
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8929
9147
|
const rewritten = sourceLines.map((line) => {
|
|
8930
9148
|
try {
|
|
@@ -8958,13 +9176,13 @@ var ChatHistoryWriter = class {
|
|
|
8958
9176
|
const sessionId = String(historySessionId || "").trim();
|
|
8959
9177
|
if (!sessionId) return;
|
|
8960
9178
|
try {
|
|
8961
|
-
const dir =
|
|
9179
|
+
const dir = path11.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8962
9180
|
if (!fs3.existsSync(dir)) return;
|
|
8963
9181
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8964
9182
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8965
9183
|
const seen = /* @__PURE__ */ new Set();
|
|
8966
9184
|
for (const file of files) {
|
|
8967
|
-
const filePath =
|
|
9185
|
+
const filePath = path11.join(dir, file);
|
|
8968
9186
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8969
9187
|
const next = [];
|
|
8970
9188
|
for (const line of lines) {
|
|
@@ -9018,11 +9236,11 @@ var ChatHistoryWriter = class {
|
|
|
9018
9236
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
9019
9237
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
9020
9238
|
for (const dir of agentDirs) {
|
|
9021
|
-
const dirPath =
|
|
9239
|
+
const dirPath = path11.join(HISTORY_DIR, dir.name);
|
|
9022
9240
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
9023
9241
|
let removedAny = false;
|
|
9024
9242
|
for (const file of files) {
|
|
9025
|
-
const filePath =
|
|
9243
|
+
const filePath = path11.join(dirPath, file);
|
|
9026
9244
|
const stat2 = fs3.statSync(filePath);
|
|
9027
9245
|
if (stat2.mtimeMs < cutoff) {
|
|
9028
9246
|
fs3.unlinkSync(filePath);
|
|
@@ -9072,13 +9290,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
9072
9290
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
9073
9291
|
try {
|
|
9074
9292
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9075
|
-
const dir =
|
|
9293
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
9076
9294
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
9077
9295
|
const files = listHistoryFiles(dir, historySessionId);
|
|
9078
9296
|
const allMessages = [];
|
|
9079
9297
|
const seen = /* @__PURE__ */ new Set();
|
|
9080
9298
|
for (const file of files) {
|
|
9081
|
-
const filePath =
|
|
9299
|
+
const filePath = path11.join(dir, file);
|
|
9082
9300
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
9083
9301
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
9084
9302
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -9102,7 +9320,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
9102
9320
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
9103
9321
|
try {
|
|
9104
9322
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9105
|
-
const dir =
|
|
9323
|
+
const dir = path11.join(HISTORY_DIR, sanitized);
|
|
9106
9324
|
if (!fs3.existsSync(dir)) {
|
|
9107
9325
|
savedHistorySessionCache.delete(sanitized);
|
|
9108
9326
|
return { sessions: [], hasMore: false };
|
|
@@ -9163,11 +9381,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
9163
9381
|
}
|
|
9164
9382
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
9165
9383
|
try {
|
|
9166
|
-
const dir =
|
|
9384
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
9167
9385
|
if (!fs3.existsSync(dir)) return null;
|
|
9168
9386
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
9169
9387
|
for (const file of files) {
|
|
9170
|
-
const lines = fs3.readFileSync(
|
|
9388
|
+
const lines = fs3.readFileSync(path11.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
9171
9389
|
for (const line of lines) {
|
|
9172
9390
|
try {
|
|
9173
9391
|
const parsed = JSON.parse(line);
|
|
@@ -9187,16 +9405,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
9187
9405
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
9188
9406
|
if (records.length === 0) return false;
|
|
9189
9407
|
try {
|
|
9190
|
-
const dir =
|
|
9408
|
+
const dir = path11.join(HISTORY_DIR, agentType);
|
|
9191
9409
|
fs3.mkdirSync(dir, { recursive: true });
|
|
9192
9410
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
9193
9411
|
for (const file of fs3.readdirSync(dir)) {
|
|
9194
9412
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
9195
|
-
fs3.unlinkSync(
|
|
9413
|
+
fs3.unlinkSync(path11.join(dir, file));
|
|
9196
9414
|
}
|
|
9197
9415
|
}
|
|
9198
9416
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
9199
|
-
const filePath =
|
|
9417
|
+
const filePath = path11.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
9200
9418
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
9201
9419
|
`, "utf-8");
|
|
9202
9420
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -9946,6 +10164,14 @@ function validateMessage(message, source, index) {
|
|
|
9946
10164
|
if (typeof message.senderName === "string") normalized.senderName = message.senderName;
|
|
9947
10165
|
if (typeof message._type === "string") normalized._type = message._type;
|
|
9948
10166
|
if (typeof message._sub === "string") normalized._sub = message._sub;
|
|
10167
|
+
if (typeof message.visibility === "string") normalized.visibility = message.visibility;
|
|
10168
|
+
if (typeof message.transcriptVisibility === "string") normalized.transcriptVisibility = message.transcriptVisibility;
|
|
10169
|
+
if (typeof message.audience === "string") normalized.audience = message.audience;
|
|
10170
|
+
if (typeof message.source === "string") normalized.source = message.source;
|
|
10171
|
+
if (typeof message.userFacing === "boolean") normalized.userFacing = message.userFacing;
|
|
10172
|
+
if (typeof message.internal === "boolean") normalized.internal = message.internal;
|
|
10173
|
+
if (typeof message.isInternal === "boolean") normalized.isInternal = message.isInternal;
|
|
10174
|
+
if (typeof message.debug === "boolean") normalized.debug = message.debug;
|
|
9949
10175
|
return normalized;
|
|
9950
10176
|
}
|
|
9951
10177
|
function validateModal(activeModal, status, source) {
|
|
@@ -11191,6 +11417,14 @@ function getActiveChatOptions(profile) {
|
|
|
11191
11417
|
if (profile === "full") return {};
|
|
11192
11418
|
return LIVE_STATUS_ACTIVE_CHAT_OPTIONS;
|
|
11193
11419
|
}
|
|
11420
|
+
function resolveSessionStatus(activeChat, providerStatus) {
|
|
11421
|
+
const chatStatus = normalizeManagedStatus(activeChat?.status, { activeModal: activeChat?.activeModal || null });
|
|
11422
|
+
const topLevelStatus = normalizeManagedStatus(providerStatus, { activeModal: activeChat?.activeModal || null });
|
|
11423
|
+
if (chatStatus === "waiting_approval" || topLevelStatus === "waiting_approval") return "waiting_approval";
|
|
11424
|
+
if (chatStatus === "generating" || topLevelStatus === "generating") return "generating";
|
|
11425
|
+
if (topLevelStatus !== "idle") return topLevelStatus;
|
|
11426
|
+
return chatStatus;
|
|
11427
|
+
}
|
|
11194
11428
|
function shouldIncludeSessionControls(profile) {
|
|
11195
11429
|
return profile !== "live";
|
|
11196
11430
|
}
|
|
@@ -11269,9 +11503,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
11269
11503
|
providerName: state.name,
|
|
11270
11504
|
kind: "workspace",
|
|
11271
11505
|
transport: "cdp-page",
|
|
11272
|
-
status:
|
|
11273
|
-
activeModal: activeChat?.activeModal || null
|
|
11274
|
-
}),
|
|
11506
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11275
11507
|
title,
|
|
11276
11508
|
workspace,
|
|
11277
11509
|
...git && { git },
|
|
@@ -11306,9 +11538,7 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
11306
11538
|
providerSessionId: ext.providerSessionId,
|
|
11307
11539
|
kind: "agent",
|
|
11308
11540
|
transport: "cdp-webview",
|
|
11309
|
-
status:
|
|
11310
|
-
activeModal: activeChat?.activeModal || null
|
|
11311
|
-
}),
|
|
11541
|
+
status: resolveSessionStatus(activeChat, ext.status),
|
|
11312
11542
|
title: activeChat?.title || ext.name,
|
|
11313
11543
|
workspace,
|
|
11314
11544
|
...git && { git },
|
|
@@ -11358,9 +11588,7 @@ function buildCliSession(state, options) {
|
|
|
11358
11588
|
providerSessionId: state.providerSessionId,
|
|
11359
11589
|
kind: "agent",
|
|
11360
11590
|
transport: "pty",
|
|
11361
|
-
status:
|
|
11362
|
-
activeModal: activeChat?.activeModal || null
|
|
11363
|
-
}),
|
|
11591
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11364
11592
|
title: activeChat?.title || state.name,
|
|
11365
11593
|
workspace,
|
|
11366
11594
|
...git && { git },
|
|
@@ -11408,9 +11636,7 @@ function buildAcpSession(state, options) {
|
|
|
11408
11636
|
providerName: state.name,
|
|
11409
11637
|
kind: "agent",
|
|
11410
11638
|
transport: "acp",
|
|
11411
|
-
status:
|
|
11412
|
-
activeModal: activeChat?.activeModal || null
|
|
11413
|
-
}),
|
|
11639
|
+
status: resolveSessionStatus(activeChat, state.status),
|
|
11414
11640
|
title: activeChat?.title || state.name,
|
|
11415
11641
|
workspace,
|
|
11416
11642
|
...git && { git },
|
|
@@ -11533,7 +11759,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
11533
11759
|
// src/commands/chat-commands.ts
|
|
11534
11760
|
var fs4 = __toESM(require("fs"));
|
|
11535
11761
|
var os6 = __toESM(require("os"));
|
|
11536
|
-
var
|
|
11762
|
+
var path12 = __toESM(require("path"));
|
|
11537
11763
|
var import_node_crypto = require("crypto");
|
|
11538
11764
|
|
|
11539
11765
|
// src/providers/provider-input-support.ts
|
|
@@ -11736,6 +11962,7 @@ function buildSessionModalDeliverySignature(payload) {
|
|
|
11736
11962
|
// src/commands/chat-commands.ts
|
|
11737
11963
|
var RECENT_SEND_WINDOW_MS = 1200;
|
|
11738
11964
|
var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
|
|
11965
|
+
var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
|
|
11739
11966
|
var recentSendByTarget = /* @__PURE__ */ new Map();
|
|
11740
11967
|
function getCurrentProviderType(h, fallback = "") {
|
|
11741
11968
|
return h.currentSession?.providerType || h.currentProviderType || fallback;
|
|
@@ -11788,6 +12015,16 @@ function buildSendInputSignature(input) {
|
|
|
11788
12015
|
function getSendChatInputEnvelope(args) {
|
|
11789
12016
|
return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
|
|
11790
12017
|
}
|
|
12018
|
+
function sleep(ms) {
|
|
12019
|
+
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
12020
|
+
}
|
|
12021
|
+
async function waitOnceForFreshHermesCliStart(adapter, log) {
|
|
12022
|
+
if (adapter.cliType !== "hermes-cli") return;
|
|
12023
|
+
const status = typeof adapter.getStatus === "function" ? adapter.getStatus()?.status : void 0;
|
|
12024
|
+
if (status !== "starting") return;
|
|
12025
|
+
log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
|
|
12026
|
+
await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
|
|
12027
|
+
}
|
|
11791
12028
|
function getHistorySessionId(h, args) {
|
|
11792
12029
|
const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
|
|
11793
12030
|
if (explicit) return explicit;
|
|
@@ -11842,7 +12079,7 @@ function normalizeReadChatTailLimit(args) {
|
|
|
11842
12079
|
}
|
|
11843
12080
|
function normalizeReadChatMessages(payload) {
|
|
11844
12081
|
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
11845
|
-
return messages;
|
|
12082
|
+
return normalizeChatMessages(messages);
|
|
11846
12083
|
}
|
|
11847
12084
|
function deriveHistoryDedupKey(message) {
|
|
11848
12085
|
const unitKey = typeof message._unitKey === "string" ? message._unitKey.trim() : "";
|
|
@@ -11896,6 +12133,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
|
|
|
11896
12133
|
return raw;
|
|
11897
12134
|
}
|
|
11898
12135
|
}
|
|
12136
|
+
function isGeneratingLikeStatus(status) {
|
|
12137
|
+
return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
|
|
12138
|
+
}
|
|
12139
|
+
function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
12140
|
+
if (!isGeneratingLikeStatus(parsedStatus)) return false;
|
|
12141
|
+
if (hasNonEmptyModalButtons(activeModal)) return false;
|
|
12142
|
+
const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
|
|
12143
|
+
if (adapterRawStatus !== "idle") return false;
|
|
12144
|
+
if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
|
|
12145
|
+
return true;
|
|
12146
|
+
}
|
|
12147
|
+
function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
|
|
12148
|
+
if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
|
|
12149
|
+
return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
|
|
12150
|
+
}
|
|
12151
|
+
function finalizeStreamingMessagesWhenIdle(messages, status) {
|
|
12152
|
+
if (status !== "idle") return messages;
|
|
12153
|
+
return messages.map((message) => {
|
|
12154
|
+
const meta = message.meta && typeof message.meta === "object" ? message.meta : void 0;
|
|
12155
|
+
const hasStreamingMeta = meta?.streaming === true;
|
|
12156
|
+
if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
|
|
12157
|
+
return {
|
|
12158
|
+
...message,
|
|
12159
|
+
...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
|
|
12160
|
+
...hasStreamingMeta ? { meta: { ...meta, streaming: false } } : {}
|
|
12161
|
+
};
|
|
12162
|
+
});
|
|
12163
|
+
}
|
|
11899
12164
|
function buildReadChatCommandResult(payload, args) {
|
|
11900
12165
|
let validatedPayload;
|
|
11901
12166
|
const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
|
|
@@ -11908,13 +12173,22 @@ function buildReadChatCommandResult(payload, args) {
|
|
|
11908
12173
|
return { success: false, error: error?.message || String(error) };
|
|
11909
12174
|
}
|
|
11910
12175
|
const messages = normalizeReadChatMessages(validatedPayload);
|
|
11911
|
-
const
|
|
12176
|
+
const visibleMessages = filterUserFacingChatMessages(messages);
|
|
12177
|
+
const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
|
|
12178
|
+
const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
|
|
12179
|
+
const returnedDebugReadChat = debugReadChat ? {
|
|
12180
|
+
...debugReadChat,
|
|
12181
|
+
fullMsgCount: typeof debugReadChat.fullMsgCount === "number" ? debugReadChat.fullMsgCount : messages.length,
|
|
12182
|
+
visibleMsgCount: visibleMessages.length,
|
|
12183
|
+
hiddenMsgCount,
|
|
12184
|
+
returnedMsgCount: sync.messages.length
|
|
12185
|
+
} : void 0;
|
|
11912
12186
|
return {
|
|
11913
12187
|
success: true,
|
|
11914
12188
|
...validatedPayload,
|
|
11915
12189
|
messages: sync.messages,
|
|
11916
12190
|
totalMessages: sync.totalMessages,
|
|
11917
|
-
...
|
|
12191
|
+
...returnedDebugReadChat ? { debugReadChat: returnedDebugReadChat } : {}
|
|
11918
12192
|
};
|
|
11919
12193
|
}
|
|
11920
12194
|
var DEFAULT_DEBUG_SANITIZE_OPTIONS = {
|
|
@@ -12044,7 +12318,7 @@ function buildDebugBundleText(bundle) {
|
|
|
12044
12318
|
}
|
|
12045
12319
|
function getChatDebugBundleDir() {
|
|
12046
12320
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
12047
|
-
return override ||
|
|
12321
|
+
return override || path12.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
12048
12322
|
}
|
|
12049
12323
|
function safeBundleIdSegment(value, fallback) {
|
|
12050
12324
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -12060,6 +12334,14 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
12060
12334
|
const readChat = bundle.readChat && typeof bundle.readChat === "object" ? bundle.readChat : {};
|
|
12061
12335
|
const cli = bundle.cli && typeof bundle.cli === "object" ? bundle.cli : null;
|
|
12062
12336
|
const frontend = bundle.frontend && typeof bundle.frontend === "object" ? bundle.frontend : null;
|
|
12337
|
+
const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === "object" ? readChat.debugReadChat : {};
|
|
12338
|
+
const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === "object" ? cli.parsedStatus : null;
|
|
12339
|
+
const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : void 0;
|
|
12340
|
+
const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : void 0;
|
|
12341
|
+
const cliPartialResponse = typeof cli?.partialResponse === "string" ? cli.partialResponse : "";
|
|
12342
|
+
const readChatStatus = typeof readChat.status === "string" ? readChat.status : "";
|
|
12343
|
+
const cliStatus = typeof cli?.status === "string" ? cli.status : "";
|
|
12344
|
+
const cliParsedStatus = typeof parsedStatus?.status === "string" ? parsedStatus.status : "";
|
|
12063
12345
|
return {
|
|
12064
12346
|
createdAt: bundle.createdAt,
|
|
12065
12347
|
targetSessionId: target.targetSessionId,
|
|
@@ -12068,8 +12350,22 @@ function buildChatDebugBundleSummary(bundle) {
|
|
|
12068
12350
|
readChatSuccess: readChat.success,
|
|
12069
12351
|
readChatStatus: readChat.status,
|
|
12070
12352
|
readChatTotalMessages: readChat.totalMessages,
|
|
12353
|
+
readChatReturnedMessages,
|
|
12071
12354
|
cliStatus: cli?.status,
|
|
12355
|
+
cliParsedStatus: cliParsedStatus || void 0,
|
|
12072
12356
|
cliMessageCount: cli?.messageCount,
|
|
12357
|
+
cliParsedMessageCount,
|
|
12358
|
+
cliPartialResponseChars: cliPartialResponse.length,
|
|
12359
|
+
parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
|
|
12360
|
+
parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
|
|
12361
|
+
readChatDebug: Object.keys(debugReadChat).length ? {
|
|
12362
|
+
adapterStatus: debugReadChat.adapterStatus,
|
|
12363
|
+
parsedStatus: debugReadChat.parsedStatus,
|
|
12364
|
+
returnedStatus: debugReadChat.returnedStatus,
|
|
12365
|
+
parsedMsgCount: debugReadChat.parsedMsgCount,
|
|
12366
|
+
returnedMsgCount: debugReadChat.returnedMsgCount,
|
|
12367
|
+
shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages
|
|
12368
|
+
} : void 0,
|
|
12073
12369
|
hasFrontendSnapshot: !!frontend
|
|
12074
12370
|
};
|
|
12075
12371
|
}
|
|
@@ -12077,7 +12373,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
12077
12373
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
12078
12374
|
const dir = getChatDebugBundleDir();
|
|
12079
12375
|
fs4.mkdirSync(dir, { recursive: true });
|
|
12080
|
-
const savedPath =
|
|
12376
|
+
const savedPath = path12.join(dir, `${bundleId}.json`);
|
|
12081
12377
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
12082
12378
|
`;
|
|
12083
12379
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -12307,7 +12603,7 @@ async function handleChatHistory(h, args) {
|
|
|
12307
12603
|
}
|
|
12308
12604
|
}
|
|
12309
12605
|
async function handleReadChat(h, args) {
|
|
12310
|
-
const provider = h.getProvider(args?.agentType);
|
|
12606
|
+
const provider = h.getProvider(args?.agentType || args?.providerType);
|
|
12311
12607
|
const transport = getTargetTransport(h, provider);
|
|
12312
12608
|
const historySessionId = getHistorySessionId(h, args);
|
|
12313
12609
|
const _log = (msg) => LOG.debug("Command", `[read_chat] ${msg}`);
|
|
@@ -12334,10 +12630,13 @@ async function handleReadChat(h, args) {
|
|
|
12334
12630
|
const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
12335
12631
|
const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
12336
12632
|
const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
|
|
12337
|
-
const returnedStatus = parsedRecord.status
|
|
12338
|
-
|
|
12633
|
+
const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
|
|
12634
|
+
const runtimeMessageMerger = getTargetInstance(h, args);
|
|
12635
|
+
const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
|
|
12636
|
+
const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
|
|
12637
|
+
LOG.debug("Command", `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord.status || "")} parsedMsgCount=${parsedRecord.messages.length} returnedMsgCount=${returnedMessages.length}`);
|
|
12339
12638
|
return buildReadChatCommandResult({
|
|
12340
|
-
messages:
|
|
12639
|
+
messages: returnedMessages,
|
|
12341
12640
|
status: returnedStatus,
|
|
12342
12641
|
activeModal,
|
|
12343
12642
|
debugReadChat: {
|
|
@@ -12348,7 +12647,7 @@ async function handleReadChat(h, args) {
|
|
|
12348
12647
|
returnedStatus: String(returnedStatus || ""),
|
|
12349
12648
|
shouldPreferAdapterMessages: false,
|
|
12350
12649
|
parsedMsgCount: parsedRecord.messages.length,
|
|
12351
|
-
returnedMsgCount:
|
|
12650
|
+
returnedMsgCount: returnedMessages.length
|
|
12352
12651
|
},
|
|
12353
12652
|
...title ? { title } : {},
|
|
12354
12653
|
...providerSessionId ? { providerSessionId } : {},
|
|
@@ -12594,6 +12893,7 @@ async function handleSendChat(h, args) {
|
|
|
12594
12893
|
try {
|
|
12595
12894
|
assertTextOnlyInput(provider, input);
|
|
12596
12895
|
if (!text) return { success: false, error: "text required for PTY send" };
|
|
12896
|
+
await waitOnceForFreshHermesCliStart(adapter, _log);
|
|
12597
12897
|
await adapter.sendMessage(text);
|
|
12598
12898
|
return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
|
|
12599
12899
|
} catch (e) {
|
|
@@ -13093,9 +13393,17 @@ async function handleResolveAction(h, args) {
|
|
|
13093
13393
|
const targetState = targetInstance?.getState?.();
|
|
13094
13394
|
const surfacedModal = targetState?.activeChat?.activeModal && Array.isArray(targetState.activeChat.activeModal.buttons) && targetState.activeChat.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? targetState.activeChat.activeModal : null;
|
|
13095
13395
|
const statusModal = status?.activeModal && Array.isArray(status.activeModal.buttons) && status.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? status.activeModal : null;
|
|
13096
|
-
const
|
|
13097
|
-
|
|
13098
|
-
|
|
13396
|
+
const parsedStatus = !statusModal && !surfacedModal && typeof adapter.getScriptParsedStatus === "function" ? (() => {
|
|
13397
|
+
try {
|
|
13398
|
+
return parseMaybeJson(adapter.getScriptParsedStatus());
|
|
13399
|
+
} catch {
|
|
13400
|
+
return null;
|
|
13401
|
+
}
|
|
13402
|
+
})() : null;
|
|
13403
|
+
const parsedModal = parsedStatus?.status === "waiting_approval" && parsedStatus?.activeModal && Array.isArray(parsedStatus.activeModal.buttons) && parsedStatus.activeModal.buttons.some((candidate) => typeof candidate === "string" && candidate.trim()) ? parsedStatus.activeModal : null;
|
|
13404
|
+
const effectiveModal = statusModal || surfacedModal || parsedModal;
|
|
13405
|
+
const effectiveStatus = status?.status === "waiting_approval" || targetState?.activeChat?.status === "waiting_approval" || parsedStatus?.status === "waiting_approval" ? "waiting_approval" : status?.status;
|
|
13406
|
+
LOG.info("Command", `[resolveAction] CLI PTY gate target=${String(args?.targetSessionId || "")} rawStatus=${String(status?.status || "")} effectiveStatus=${String(effectiveStatus || "")} statusModal=${statusModal ? "yes" : "no"} surfacedModal=${surfacedModal ? "yes" : "no"} parsedModal=${parsedModal ? "yes" : "no"} instance=${targetInstance ? "yes" : "no"}`);
|
|
13099
13407
|
if (!effectiveModal) {
|
|
13100
13408
|
return { success: false, error: "Not in approval state" };
|
|
13101
13409
|
}
|
|
@@ -13221,7 +13529,7 @@ async function handleResolveAction(h, args) {
|
|
|
13221
13529
|
|
|
13222
13530
|
// src/commands/cdp-commands.ts
|
|
13223
13531
|
var fs5 = __toESM(require("fs"));
|
|
13224
|
-
var
|
|
13532
|
+
var path13 = __toESM(require("path"));
|
|
13225
13533
|
var os7 = __toESM(require("os"));
|
|
13226
13534
|
var KEY_TO_VK = {
|
|
13227
13535
|
Backspace: 8,
|
|
@@ -13478,25 +13786,25 @@ function resolveSafePath(requestedPath) {
|
|
|
13478
13786
|
const inputPath = rawPath || ".";
|
|
13479
13787
|
const home = os7.homedir();
|
|
13480
13788
|
if (inputPath.startsWith("~")) {
|
|
13481
|
-
return
|
|
13789
|
+
return path13.resolve(path13.join(home, inputPath.slice(1)));
|
|
13482
13790
|
}
|
|
13483
13791
|
if (process.platform === "win32") {
|
|
13484
13792
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
13485
|
-
if (
|
|
13486
|
-
return
|
|
13793
|
+
if (path13.win32.isAbsolute(normalized)) {
|
|
13794
|
+
return path13.win32.normalize(normalized);
|
|
13487
13795
|
}
|
|
13488
|
-
return
|
|
13796
|
+
return path13.win32.resolve(normalized);
|
|
13489
13797
|
}
|
|
13490
|
-
if (
|
|
13491
|
-
return
|
|
13798
|
+
if (path13.isAbsolute(inputPath)) {
|
|
13799
|
+
return path13.normalize(inputPath);
|
|
13492
13800
|
}
|
|
13493
|
-
return
|
|
13801
|
+
return path13.resolve(inputPath);
|
|
13494
13802
|
}
|
|
13495
13803
|
function listDirectoryEntriesSafe(dirPath) {
|
|
13496
13804
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
13497
13805
|
const files = [];
|
|
13498
13806
|
for (const entry of entries) {
|
|
13499
|
-
const entryPath =
|
|
13807
|
+
const entryPath = path13.join(dirPath, entry.name);
|
|
13500
13808
|
try {
|
|
13501
13809
|
if (entry.isDirectory()) {
|
|
13502
13810
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -13550,7 +13858,7 @@ async function handleFileRead(h, args) {
|
|
|
13550
13858
|
async function handleFileWrite(h, args) {
|
|
13551
13859
|
try {
|
|
13552
13860
|
const filePath = resolveSafePath(args?.path);
|
|
13553
|
-
fs5.mkdirSync(
|
|
13861
|
+
fs5.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
13554
13862
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
13555
13863
|
return { success: true, path: filePath };
|
|
13556
13864
|
} catch (e) {
|
|
@@ -14334,9 +14642,11 @@ var DaemonCommandHandler = class {
|
|
|
14334
14642
|
}
|
|
14335
14643
|
const sessionLookupFailed = !!targetSessionId && !session;
|
|
14336
14644
|
const managerKey = this.extractIdeType(args, sessionLookupFailed);
|
|
14337
|
-
let providerType;
|
|
14645
|
+
let providerType = args?.agentType || args?.providerType;
|
|
14338
14646
|
if (!sessionLookupFailed) {
|
|
14339
|
-
providerType = session?.providerType ||
|
|
14647
|
+
providerType = session?.providerType || providerType || this.inferProviderType(managerKey);
|
|
14648
|
+
} else if (!providerType) {
|
|
14649
|
+
providerType = this.inferProviderType(managerKey);
|
|
14340
14650
|
}
|
|
14341
14651
|
return { session, managerKey, providerType, sessionLookupFailed };
|
|
14342
14652
|
}
|
|
@@ -14416,7 +14726,8 @@ var DaemonCommandHandler = class {
|
|
|
14416
14726
|
"pty_resize",
|
|
14417
14727
|
"invoke_provider_script"
|
|
14418
14728
|
]);
|
|
14419
|
-
|
|
14729
|
+
const allowsInactiveReadChatFallback = cmd === "read_chat" && !!this._currentRoute.providerType && (typeof args?.providerSessionId === "string" && args.providerSessionId.trim().length > 0 || typeof args?.historySessionId === "string" && args.historySessionId.trim().length > 0);
|
|
14730
|
+
if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd) && !allowsInactiveReadChatFallback) {
|
|
14420
14731
|
const result2 = {
|
|
14421
14732
|
success: false,
|
|
14422
14733
|
error: `Live session not found for targetSessionId: ${String(args?.targetSessionId || "").trim() || "unknown"}`
|
|
@@ -14669,7 +14980,7 @@ var DaemonCommandHandler = class {
|
|
|
14669
14980
|
|
|
14670
14981
|
// src/commands/cli-manager.ts
|
|
14671
14982
|
var os13 = __toESM(require("os"));
|
|
14672
|
-
var
|
|
14983
|
+
var path17 = __toESM(require("path"));
|
|
14673
14984
|
var crypto4 = __toESM(require("crypto"));
|
|
14674
14985
|
var import_fs6 = require("fs");
|
|
14675
14986
|
var import_child_process6 = require("child_process");
|
|
@@ -14679,7 +14990,7 @@ init_config();
|
|
|
14679
14990
|
|
|
14680
14991
|
// src/providers/cli-provider-instance.ts
|
|
14681
14992
|
var os12 = __toESM(require("os"));
|
|
14682
|
-
var
|
|
14993
|
+
var path16 = __toESM(require("path"));
|
|
14683
14994
|
var crypto3 = __toESM(require("crypto"));
|
|
14684
14995
|
var fs6 = __toESM(require("fs"));
|
|
14685
14996
|
var import_node_module = require("module");
|
|
@@ -14738,7 +15049,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
14738
15049
|
var CachedDatabaseSync = null;
|
|
14739
15050
|
function getDatabaseSync() {
|
|
14740
15051
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
14741
|
-
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(
|
|
15052
|
+
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path16.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
14742
15053
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
14743
15054
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
14744
15055
|
if (!CachedDatabaseSync) {
|
|
@@ -14791,7 +15102,7 @@ var CliProviderInstance = class {
|
|
|
14791
15102
|
this.providerSessionId = options?.providerSessionId;
|
|
14792
15103
|
this.launchMode = options?.launchMode || "new";
|
|
14793
15104
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
14794
|
-
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, transportFactory);
|
|
15105
|
+
this.adapter = new ProviderCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
14795
15106
|
this.monitor = new StatusMonitor();
|
|
14796
15107
|
this.historyWriter = new ChatHistoryWriter();
|
|
14797
15108
|
}
|
|
@@ -15268,7 +15579,19 @@ var CliProviderInstance = class {
|
|
|
15268
15579
|
}
|
|
15269
15580
|
}
|
|
15270
15581
|
pushEvent(event) {
|
|
15271
|
-
|
|
15582
|
+
const enrichedEvent = {
|
|
15583
|
+
...event,
|
|
15584
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : this.instanceId,
|
|
15585
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : this.instanceId,
|
|
15586
|
+
providerType: typeof event.providerType === "string" && event.providerType.trim() ? event.providerType : this.type,
|
|
15587
|
+
workspaceName: typeof event.workspaceName === "string" && event.workspaceName.trim() ? event.workspaceName : this.workingDir,
|
|
15588
|
+
providerSessionId: typeof event.providerSessionId === "string" && event.providerSessionId.trim() ? event.providerSessionId : this.providerSessionId
|
|
15589
|
+
};
|
|
15590
|
+
if (this.context?.emitProviderEvent) {
|
|
15591
|
+
this.context.emitProviderEvent(enrichedEvent);
|
|
15592
|
+
return;
|
|
15593
|
+
}
|
|
15594
|
+
this.events.push(enrichedEvent);
|
|
15272
15595
|
}
|
|
15273
15596
|
flushEvents() {
|
|
15274
15597
|
const events = [...this.events];
|
|
@@ -15475,12 +15798,59 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15475
15798
|
);
|
|
15476
15799
|
}
|
|
15477
15800
|
}
|
|
15801
|
+
mergeRuntimeChatMessages(parsedMessages) {
|
|
15802
|
+
return this.mergeConversationMessages(parsedMessages);
|
|
15803
|
+
}
|
|
15478
15804
|
mergeConversationMessages(parsedMessages) {
|
|
15479
15805
|
if (this.runtimeMessages.length === 0) return normalizeChatMessages(parsedMessages);
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15483
|
-
|
|
15806
|
+
const parsedEntries = parsedMessages.map((message, index) => ({
|
|
15807
|
+
message,
|
|
15808
|
+
index,
|
|
15809
|
+
source: "parsed"
|
|
15810
|
+
}));
|
|
15811
|
+
const runtimeEntries = this.runtimeMessages.map((entry, index) => ({
|
|
15812
|
+
message: entry.message,
|
|
15813
|
+
index: parsedMessages.length + index,
|
|
15814
|
+
source: "runtime",
|
|
15815
|
+
runtimeKey: entry.key
|
|
15816
|
+
}));
|
|
15817
|
+
const getTime = (message) => {
|
|
15818
|
+
const value = typeof message.receivedAt === "number" ? message.receivedAt : typeof message.timestamp === "number" ? message.timestamp : 0;
|
|
15819
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
15820
|
+
};
|
|
15821
|
+
const getRole = (message) => typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
15822
|
+
const isRuntimeOverlay = (entry) => {
|
|
15823
|
+
if (entry.source !== "runtime") return false;
|
|
15824
|
+
const key = typeof entry.runtimeKey === "string" ? entry.runtimeKey.trim().toLowerCase() : "";
|
|
15825
|
+
if (key.startsWith("auto_approval:")) return true;
|
|
15826
|
+
return !isUserFacingChatMessage(entry.message);
|
|
15827
|
+
};
|
|
15828
|
+
const shouldKeepParsedBeforeUntimedRuntime = (message) => {
|
|
15829
|
+
const role = getRole(message);
|
|
15830
|
+
return role === "user" || role === "human";
|
|
15831
|
+
};
|
|
15832
|
+
const shouldKeepParsedAfterUntimedRuntime = (message) => {
|
|
15833
|
+
const role = getRole(message);
|
|
15834
|
+
if (role !== "assistant") return false;
|
|
15835
|
+
const kind = resolveChatMessageKind(message);
|
|
15836
|
+
return kind === "standard" || kind === "terminal";
|
|
15837
|
+
};
|
|
15838
|
+
return normalizeChatMessages([...parsedEntries, ...runtimeEntries].sort((a, b) => {
|
|
15839
|
+
const aTime = getTime(a.message);
|
|
15840
|
+
const bTime = getTime(b.message);
|
|
15841
|
+
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
15842
|
+
if (a.source !== b.source && aTime !== bTime) {
|
|
15843
|
+
const parsedEntry = a.source === "parsed" ? a : b.source === "parsed" ? b : null;
|
|
15844
|
+
const runtimeEntry = a.source === "runtime" ? a : b.source === "runtime" ? b : null;
|
|
15845
|
+
if (parsedEntry && runtimeEntry && isRuntimeOverlay(runtimeEntry) && getTime(parsedEntry.message) === 0 && getTime(runtimeEntry.message) > 0) {
|
|
15846
|
+
if (shouldKeepParsedBeforeUntimedRuntime(parsedEntry.message)) {
|
|
15847
|
+
return a.source === "parsed" ? -1 : 1;
|
|
15848
|
+
}
|
|
15849
|
+
if (shouldKeepParsedAfterUntimedRuntime(parsedEntry.message)) {
|
|
15850
|
+
return a.source === "parsed" ? 1 : -1;
|
|
15851
|
+
}
|
|
15852
|
+
}
|
|
15853
|
+
}
|
|
15484
15854
|
return a.index - b.index;
|
|
15485
15855
|
}).map((entry) => entry.message));
|
|
15486
15856
|
}
|
|
@@ -16804,11 +17174,11 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
16804
17174
|
// src/commands/cli-manager.ts
|
|
16805
17175
|
function isExplicitCommand(command) {
|
|
16806
17176
|
const trimmed = command.trim();
|
|
16807
|
-
return
|
|
17177
|
+
return path17.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
16808
17178
|
}
|
|
16809
17179
|
function expandExecutable(command) {
|
|
16810
17180
|
const trimmed = command.trim();
|
|
16811
|
-
return trimmed.startsWith("~") ?
|
|
17181
|
+
return trimmed.startsWith("~") ? path17.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
16812
17182
|
}
|
|
16813
17183
|
function commandExists(command) {
|
|
16814
17184
|
const trimmed = command.trim();
|
|
@@ -16832,6 +17202,35 @@ function colorize(color, text) {
|
|
|
16832
17202
|
const fn = chalkApi?.[color];
|
|
16833
17203
|
return typeof fn === "function" ? fn(text) : text;
|
|
16834
17204
|
}
|
|
17205
|
+
var COORDINATOR_DELEGATED_ENV_UNSETS = {
|
|
17206
|
+
ADHDEV_INLINE_MESH: "",
|
|
17207
|
+
ADHDEV_MCP_TRANSPORT: "",
|
|
17208
|
+
ADHDEV_MESH_ID: "",
|
|
17209
|
+
HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
|
|
17210
|
+
};
|
|
17211
|
+
function hasCliArg(args, flag) {
|
|
17212
|
+
return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
17213
|
+
}
|
|
17214
|
+
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
17215
|
+
const baseDir = path17.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
17216
|
+
(0, import_fs6.mkdirSync)(baseDir, { recursive: true });
|
|
17217
|
+
const workspaceHash = crypto4.createHash("sha256").update(path17.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
17218
|
+
const filePath = path17.join(baseDir, `${workspaceHash}.json`);
|
|
17219
|
+
(0, import_fs6.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
17220
|
+
return filePath;
|
|
17221
|
+
}
|
|
17222
|
+
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
17223
|
+
const cliType = String(input.cliType || "").trim();
|
|
17224
|
+
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
17225
|
+
const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
|
|
17226
|
+
if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
|
|
17227
|
+
cliArgs.unshift("--ignore-user-config");
|
|
17228
|
+
}
|
|
17229
|
+
if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
|
|
17230
|
+
cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
17231
|
+
}
|
|
17232
|
+
return { cliArgs, env };
|
|
17233
|
+
}
|
|
16835
17234
|
function isUuid(value) {
|
|
16836
17235
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
16837
17236
|
}
|
|
@@ -17002,7 +17401,7 @@ var DaemonCliManager = class {
|
|
|
17002
17401
|
attachExisting
|
|
17003
17402
|
}) || void 0;
|
|
17004
17403
|
}
|
|
17005
|
-
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false) {
|
|
17404
|
+
createAdapter(cliType, workingDir, cliArgs, runtimeId, providerSessionId, attachExisting = false, extraEnv) {
|
|
17006
17405
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
17007
17406
|
const provider = this.providerLoader.getMeta(normalizedType);
|
|
17008
17407
|
if (provider && provider.category === "cli" && provider.patterns && provider.spawn) {
|
|
@@ -17016,7 +17415,7 @@ var DaemonCliManager = class {
|
|
|
17016
17415
|
providerSessionId,
|
|
17017
17416
|
attachExisting
|
|
17018
17417
|
);
|
|
17019
|
-
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, transportFactory);
|
|
17418
|
+
return new ProviderCliAdapter(resolvedProvider, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
17020
17419
|
}
|
|
17021
17420
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
17022
17421
|
}
|
|
@@ -17089,7 +17488,7 @@ var DaemonCliManager = class {
|
|
|
17089
17488
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
17090
17489
|
const trimmed = (workingDir || "").trim();
|
|
17091
17490
|
if (!trimmed) throw new Error("working directory required");
|
|
17092
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17491
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path17.resolve(trimmed);
|
|
17093
17492
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
17094
17493
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
17095
17494
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -17219,6 +17618,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17219
17618
|
{
|
|
17220
17619
|
providerSessionId: sessionBinding.providerSessionId,
|
|
17221
17620
|
launchMode: sessionBinding.launchMode,
|
|
17621
|
+
extraEnv: options?.extraEnv,
|
|
17222
17622
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
17223
17623
|
this.persistRecentActivity({
|
|
17224
17624
|
kind: "cli",
|
|
@@ -17239,7 +17639,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17239
17639
|
resolvedCliArgs,
|
|
17240
17640
|
key,
|
|
17241
17641
|
sessionBinding.providerSessionId,
|
|
17242
|
-
false
|
|
17642
|
+
false,
|
|
17643
|
+
options?.extraEnv
|
|
17243
17644
|
);
|
|
17244
17645
|
try {
|
|
17245
17646
|
await adapter.spawn();
|
|
@@ -17463,12 +17864,23 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17463
17864
|
const dir = resolved.path;
|
|
17464
17865
|
const launchSource = resolved.source;
|
|
17465
17866
|
if (!cliType) throw new Error("cliType required");
|
|
17867
|
+
const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
|
|
17868
|
+
const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
|
|
17869
|
+
cliType,
|
|
17870
|
+
workspace: dir,
|
|
17871
|
+
cliArgs: args?.cliArgs,
|
|
17872
|
+
env: args?.env
|
|
17873
|
+
}) : null;
|
|
17466
17874
|
const started = await this.startSession(
|
|
17467
17875
|
cliType,
|
|
17468
17876
|
dir,
|
|
17469
|
-
args?.cliArgs,
|
|
17877
|
+
delegatedLaunch ? delegatedLaunch.cliArgs : args?.cliArgs,
|
|
17470
17878
|
args?.initialModel,
|
|
17471
|
-
{
|
|
17879
|
+
{
|
|
17880
|
+
resumeSessionId: args?.resumeSessionId,
|
|
17881
|
+
settingsOverride,
|
|
17882
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
17883
|
+
}
|
|
17472
17884
|
);
|
|
17473
17885
|
return {
|
|
17474
17886
|
success: true,
|
|
@@ -17590,11 +18002,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
17590
18002
|
var import_child_process7 = require("child_process");
|
|
17591
18003
|
var net = __toESM(require("net"));
|
|
17592
18004
|
var os15 = __toESM(require("os"));
|
|
17593
|
-
var
|
|
18005
|
+
var path19 = __toESM(require("path"));
|
|
17594
18006
|
|
|
17595
18007
|
// src/providers/provider-loader.ts
|
|
17596
18008
|
var fs7 = __toESM(require("fs"));
|
|
17597
|
-
var
|
|
18009
|
+
var path18 = __toESM(require("path"));
|
|
17598
18010
|
var os14 = __toESM(require("os"));
|
|
17599
18011
|
var chokidar = __toESM(require("chokidar"));
|
|
17600
18012
|
init_logger();
|
|
@@ -17918,7 +18330,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17918
18330
|
try {
|
|
17919
18331
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
17920
18332
|
return ["ide", "extension", "cli", "acp"].some(
|
|
17921
|
-
(category) => fs7.existsSync(
|
|
18333
|
+
(category) => fs7.existsSync(path18.join(candidate, category))
|
|
17922
18334
|
);
|
|
17923
18335
|
} catch {
|
|
17924
18336
|
return false;
|
|
@@ -17926,20 +18338,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17926
18338
|
}
|
|
17927
18339
|
static hasProviderRootMarker(candidate) {
|
|
17928
18340
|
try {
|
|
17929
|
-
return fs7.existsSync(
|
|
18341
|
+
return fs7.existsSync(path18.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
17930
18342
|
} catch {
|
|
17931
18343
|
return false;
|
|
17932
18344
|
}
|
|
17933
18345
|
}
|
|
17934
18346
|
detectDefaultUserDir() {
|
|
17935
|
-
const fallback =
|
|
18347
|
+
const fallback = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17936
18348
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17937
18349
|
const visited = /* @__PURE__ */ new Set();
|
|
17938
18350
|
for (const start of this.probeStarts) {
|
|
17939
|
-
let current =
|
|
18351
|
+
let current = path18.resolve(start);
|
|
17940
18352
|
while (!visited.has(current)) {
|
|
17941
18353
|
visited.add(current);
|
|
17942
|
-
const siblingCandidate =
|
|
18354
|
+
const siblingCandidate = path18.join(path18.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17943
18355
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17944
18356
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17945
18357
|
if (envOptIn || hasMarker) {
|
|
@@ -17961,7 +18373,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17961
18373
|
return { path: siblingCandidate, source };
|
|
17962
18374
|
}
|
|
17963
18375
|
}
|
|
17964
|
-
const parent =
|
|
18376
|
+
const parent = path18.dirname(current);
|
|
17965
18377
|
if (parent === current) break;
|
|
17966
18378
|
current = parent;
|
|
17967
18379
|
}
|
|
@@ -17971,11 +18383,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17971
18383
|
constructor(options) {
|
|
17972
18384
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17973
18385
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17974
|
-
this.defaultProvidersDir =
|
|
18386
|
+
this.defaultProvidersDir = path18.join(os14.homedir(), ".adhdev", "providers");
|
|
17975
18387
|
const detected = this.detectDefaultUserDir();
|
|
17976
18388
|
this.userDir = detected.path;
|
|
17977
18389
|
this.userDirSource = detected.source;
|
|
17978
|
-
this.upstreamDir =
|
|
18390
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
17979
18391
|
this.disableUpstream = false;
|
|
17980
18392
|
this.applySourceConfig({
|
|
17981
18393
|
userDir: options?.userDir,
|
|
@@ -18034,7 +18446,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18034
18446
|
this.userDir = detected.path;
|
|
18035
18447
|
this.userDirSource = detected.source;
|
|
18036
18448
|
}
|
|
18037
|
-
this.upstreamDir =
|
|
18449
|
+
this.upstreamDir = path18.join(this.defaultProvidersDir, ".upstream");
|
|
18038
18450
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
18039
18451
|
if (this.explicitProviderDir) {
|
|
18040
18452
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -18048,7 +18460,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18048
18460
|
* Canonical provider directory shape for a given root.
|
|
18049
18461
|
*/
|
|
18050
18462
|
getProviderDir(root, category, type) {
|
|
18051
|
-
return
|
|
18463
|
+
return path18.join(root, category, type);
|
|
18052
18464
|
}
|
|
18053
18465
|
/**
|
|
18054
18466
|
* Canonical user override directory for a provider.
|
|
@@ -18075,7 +18487,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18075
18487
|
resolveProviderFile(type, ...segments) {
|
|
18076
18488
|
const dir = this.findProviderDirInternal(type);
|
|
18077
18489
|
if (!dir) return null;
|
|
18078
|
-
return
|
|
18490
|
+
return path18.join(dir, ...segments);
|
|
18079
18491
|
}
|
|
18080
18492
|
/**
|
|
18081
18493
|
* Load all providers (3-tier priority)
|
|
@@ -18114,7 +18526,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18114
18526
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
18115
18527
|
try {
|
|
18116
18528
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
18117
|
-
(d) => fs7.statSync(
|
|
18529
|
+
(d) => fs7.statSync(path18.join(this.upstreamDir, d)).isDirectory()
|
|
18118
18530
|
);
|
|
18119
18531
|
} catch {
|
|
18120
18532
|
return false;
|
|
@@ -18611,8 +19023,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18611
19023
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
18612
19024
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
18613
19025
|
if (providerDir) {
|
|
18614
|
-
const fullDir =
|
|
18615
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
19026
|
+
const fullDir = path18.join(providerDir, entry.scriptDir);
|
|
19027
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18616
19028
|
}
|
|
18617
19029
|
matched = true;
|
|
18618
19030
|
}
|
|
@@ -18627,8 +19039,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18627
19039
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18628
19040
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
18629
19041
|
if (providerDir) {
|
|
18630
|
-
const fullDir =
|
|
18631
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
19042
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
19043
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18632
19044
|
}
|
|
18633
19045
|
}
|
|
18634
19046
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -18645,8 +19057,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18645
19057
|
resolved._resolvedScriptDir = dirOverride;
|
|
18646
19058
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
18647
19059
|
if (providerDir) {
|
|
18648
|
-
const fullDir =
|
|
18649
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
19060
|
+
const fullDir = path18.join(providerDir, dirOverride);
|
|
19061
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18650
19062
|
}
|
|
18651
19063
|
}
|
|
18652
19064
|
} else if (override.scripts) {
|
|
@@ -18662,8 +19074,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18662
19074
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
18663
19075
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
18664
19076
|
if (providerDir) {
|
|
18665
|
-
const fullDir =
|
|
18666
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
19077
|
+
const fullDir = path18.join(providerDir, base.defaultScriptDir);
|
|
19078
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path18.join(fullDir, "scripts.js")) ? path18.join(fullDir, "scripts.js") : fullDir;
|
|
18667
19079
|
}
|
|
18668
19080
|
}
|
|
18669
19081
|
}
|
|
@@ -18695,14 +19107,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18695
19107
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
18696
19108
|
return null;
|
|
18697
19109
|
}
|
|
18698
|
-
const dir =
|
|
19110
|
+
const dir = path18.join(providerDir, scriptDir);
|
|
18699
19111
|
if (!fs7.existsSync(dir)) {
|
|
18700
19112
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
18701
19113
|
return null;
|
|
18702
19114
|
}
|
|
18703
19115
|
const cached = this.scriptsCache.get(dir);
|
|
18704
19116
|
if (cached) return cached;
|
|
18705
|
-
const scriptsJs =
|
|
19117
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
18706
19118
|
if (fs7.existsSync(scriptsJs)) {
|
|
18707
19119
|
try {
|
|
18708
19120
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -18744,7 +19156,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18744
19156
|
return;
|
|
18745
19157
|
}
|
|
18746
19158
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
18747
|
-
this.log(`File changed: ${
|
|
19159
|
+
this.log(`File changed: ${path18.basename(filePath)}, reloading...`);
|
|
18748
19160
|
this.reload();
|
|
18749
19161
|
}
|
|
18750
19162
|
};
|
|
@@ -18799,7 +19211,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18799
19211
|
}
|
|
18800
19212
|
const https = require("https");
|
|
18801
19213
|
const { execSync: execSync7 } = require("child_process");
|
|
18802
|
-
const metaPath =
|
|
19214
|
+
const metaPath = path18.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
18803
19215
|
let prevEtag = "";
|
|
18804
19216
|
let prevTimestamp = 0;
|
|
18805
19217
|
try {
|
|
@@ -18859,17 +19271,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18859
19271
|
return { updated: false };
|
|
18860
19272
|
}
|
|
18861
19273
|
this.log("Downloading latest providers from GitHub...");
|
|
18862
|
-
const tmpTar =
|
|
18863
|
-
const tmpExtract =
|
|
19274
|
+
const tmpTar = path18.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
19275
|
+
const tmpExtract = path18.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
18864
19276
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
18865
19277
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
18866
19278
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
18867
19279
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
18868
19280
|
const rootDir = extracted.find(
|
|
18869
|
-
(d) => fs7.statSync(
|
|
19281
|
+
(d) => fs7.statSync(path18.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
18870
19282
|
);
|
|
18871
19283
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
18872
|
-
const sourceDir =
|
|
19284
|
+
const sourceDir = path18.join(tmpExtract, rootDir);
|
|
18873
19285
|
const backupDir = this.upstreamDir + ".bak";
|
|
18874
19286
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
18875
19287
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -18944,8 +19356,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18944
19356
|
copyDirRecursive(src, dest) {
|
|
18945
19357
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18946
19358
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18947
|
-
const srcPath =
|
|
18948
|
-
const destPath =
|
|
19359
|
+
const srcPath = path18.join(src, entry.name);
|
|
19360
|
+
const destPath = path18.join(dest, entry.name);
|
|
18949
19361
|
if (entry.isDirectory()) {
|
|
18950
19362
|
this.copyDirRecursive(srcPath, destPath);
|
|
18951
19363
|
} else {
|
|
@@ -18956,7 +19368,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18956
19368
|
/** .meta.json save */
|
|
18957
19369
|
writeMeta(metaPath, etag, timestamp) {
|
|
18958
19370
|
try {
|
|
18959
|
-
fs7.mkdirSync(
|
|
19371
|
+
fs7.mkdirSync(path18.dirname(metaPath), { recursive: true });
|
|
18960
19372
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18961
19373
|
etag,
|
|
18962
19374
|
timestamp,
|
|
@@ -18973,7 +19385,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18973
19385
|
const scan = (d) => {
|
|
18974
19386
|
try {
|
|
18975
19387
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18976
|
-
if (entry.isDirectory()) scan(
|
|
19388
|
+
if (entry.isDirectory()) scan(path18.join(d, entry.name));
|
|
18977
19389
|
else if (entry.name === "provider.json") count++;
|
|
18978
19390
|
}
|
|
18979
19391
|
} catch {
|
|
@@ -19201,17 +19613,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19201
19613
|
for (const root of searchRoots) {
|
|
19202
19614
|
if (!fs7.existsSync(root)) continue;
|
|
19203
19615
|
const candidate = this.getProviderDir(root, cat, type);
|
|
19204
|
-
if (fs7.existsSync(
|
|
19205
|
-
const catDir =
|
|
19616
|
+
if (fs7.existsSync(path18.join(candidate, "provider.json"))) return candidate;
|
|
19617
|
+
const catDir = path18.join(root, cat);
|
|
19206
19618
|
if (fs7.existsSync(catDir)) {
|
|
19207
19619
|
try {
|
|
19208
19620
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
19209
19621
|
if (!entry.isDirectory()) continue;
|
|
19210
|
-
const jsonPath =
|
|
19622
|
+
const jsonPath = path18.join(catDir, entry.name, "provider.json");
|
|
19211
19623
|
if (fs7.existsSync(jsonPath)) {
|
|
19212
19624
|
try {
|
|
19213
19625
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
19214
|
-
if (data.type === type) return
|
|
19626
|
+
if (data.type === type) return path18.join(catDir, entry.name);
|
|
19215
19627
|
} catch {
|
|
19216
19628
|
}
|
|
19217
19629
|
}
|
|
@@ -19228,7 +19640,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19228
19640
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
19229
19641
|
*/
|
|
19230
19642
|
buildScriptWrappersFromDir(dir) {
|
|
19231
|
-
const scriptsJs =
|
|
19643
|
+
const scriptsJs = path18.join(dir, "scripts.js");
|
|
19232
19644
|
if (fs7.existsSync(scriptsJs)) {
|
|
19233
19645
|
try {
|
|
19234
19646
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -19242,7 +19654,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19242
19654
|
for (const file of fs7.readdirSync(dir)) {
|
|
19243
19655
|
if (!file.endsWith(".js")) continue;
|
|
19244
19656
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
19245
|
-
const filePath =
|
|
19657
|
+
const filePath = path18.join(dir, file);
|
|
19246
19658
|
result[scriptName] = (...args) => {
|
|
19247
19659
|
try {
|
|
19248
19660
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -19302,7 +19714,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19302
19714
|
}
|
|
19303
19715
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
19304
19716
|
if (hasJson) {
|
|
19305
|
-
const jsonPath =
|
|
19717
|
+
const jsonPath = path18.join(d, "provider.json");
|
|
19306
19718
|
try {
|
|
19307
19719
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
19308
19720
|
const mod = JSON.parse(raw);
|
|
@@ -19323,7 +19735,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19323
19735
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
19324
19736
|
} else {
|
|
19325
19737
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
19326
|
-
const scriptsPath =
|
|
19738
|
+
const scriptsPath = path18.join(d, "scripts.js");
|
|
19327
19739
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
19328
19740
|
try {
|
|
19329
19741
|
delete require.cache[require.resolve(scriptsPath)];
|
|
@@ -19349,7 +19761,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
19349
19761
|
if (!entry.isDirectory()) continue;
|
|
19350
19762
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
19351
19763
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
19352
|
-
scan(
|
|
19764
|
+
scan(path18.join(d, entry.name));
|
|
19353
19765
|
}
|
|
19354
19766
|
}
|
|
19355
19767
|
};
|
|
@@ -19674,8 +20086,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
19674
20086
|
const appNameMap = getMacAppIdentifiers();
|
|
19675
20087
|
const appName = appNameMap[ideId];
|
|
19676
20088
|
if (appName) {
|
|
19677
|
-
const storagePath =
|
|
19678
|
-
process.env.APPDATA ||
|
|
20089
|
+
const storagePath = path19.join(
|
|
20090
|
+
process.env.APPDATA || path19.join(os15.homedir(), "AppData", "Roaming"),
|
|
19679
20091
|
appName,
|
|
19680
20092
|
"storage.json"
|
|
19681
20093
|
);
|
|
@@ -19864,9 +20276,9 @@ init_logger();
|
|
|
19864
20276
|
|
|
19865
20277
|
// src/logging/command-log.ts
|
|
19866
20278
|
var fs8 = __toESM(require("fs"));
|
|
19867
|
-
var
|
|
20279
|
+
var path20 = __toESM(require("path"));
|
|
19868
20280
|
var os16 = __toESM(require("os"));
|
|
19869
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
20281
|
+
var LOG_DIR2 = process.platform === "win32" ? path20.join(process.env.LOCALAPPDATA || process.env.APPDATA || path20.join(os16.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path20.join(os16.homedir(), "Library", "Logs", "adhdev") : path20.join(os16.homedir(), ".local", "share", "adhdev", "logs");
|
|
19870
20282
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
19871
20283
|
var MAX_DAYS = 7;
|
|
19872
20284
|
try {
|
|
@@ -19904,13 +20316,13 @@ function getDateStr2() {
|
|
|
19904
20316
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19905
20317
|
}
|
|
19906
20318
|
var currentDate2 = getDateStr2();
|
|
19907
|
-
var currentFile =
|
|
20319
|
+
var currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19908
20320
|
var writeCount2 = 0;
|
|
19909
20321
|
function checkRotation() {
|
|
19910
20322
|
const today = getDateStr2();
|
|
19911
20323
|
if (today !== currentDate2) {
|
|
19912
20324
|
currentDate2 = today;
|
|
19913
|
-
currentFile =
|
|
20325
|
+
currentFile = path20.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
19914
20326
|
cleanOldFiles();
|
|
19915
20327
|
}
|
|
19916
20328
|
}
|
|
@@ -19924,7 +20336,7 @@ function cleanOldFiles() {
|
|
|
19924
20336
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
19925
20337
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
19926
20338
|
try {
|
|
19927
|
-
fs8.unlinkSync(
|
|
20339
|
+
fs8.unlinkSync(path20.join(LOG_DIR2, file));
|
|
19928
20340
|
} catch {
|
|
19929
20341
|
}
|
|
19930
20342
|
}
|
|
@@ -20007,14 +20419,66 @@ function getRecentCommands(count = 50) {
|
|
|
20007
20419
|
cleanOldFiles();
|
|
20008
20420
|
|
|
20009
20421
|
// src/commands/router.ts
|
|
20422
|
+
var yaml = __toESM(require("js-yaml"));
|
|
20010
20423
|
init_logger();
|
|
20011
20424
|
|
|
20012
20425
|
// src/commands/mesh-coordinator.ts
|
|
20013
|
-
var
|
|
20426
|
+
var import_node_child_process3 = require("child_process");
|
|
20427
|
+
var import_node_fs3 = require("fs");
|
|
20014
20428
|
var import_node_module2 = require("module");
|
|
20429
|
+
var os17 = __toESM(require("os"));
|
|
20015
20430
|
var import_node_path = require("path");
|
|
20016
20431
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
20017
20432
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
20433
|
+
var HERMES_CLI_TYPE = "hermes-cli";
|
|
20434
|
+
var HERMES_MCP_CONFIG_PATH = "~/.hermes/config.yaml";
|
|
20435
|
+
function isHermesProvider(provider, cliType) {
|
|
20436
|
+
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
20437
|
+
return type === HERMES_CLI_TYPE;
|
|
20438
|
+
}
|
|
20439
|
+
function resolveHermesMeshCoordinatorSetup(options) {
|
|
20440
|
+
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
20441
|
+
meshId: options.meshId,
|
|
20442
|
+
nodeExecutable: options.nodeExecutable,
|
|
20443
|
+
adhdevMcpEntryPath: options.adhdevMcpEntryPath
|
|
20444
|
+
});
|
|
20445
|
+
if (!mcpServer) {
|
|
20446
|
+
return {
|
|
20447
|
+
kind: "unsupported",
|
|
20448
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20449
|
+
};
|
|
20450
|
+
}
|
|
20451
|
+
const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace);
|
|
20452
|
+
if (!configPath.trim()) {
|
|
20453
|
+
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
20454
|
+
}
|
|
20455
|
+
return {
|
|
20456
|
+
kind: "auto_import",
|
|
20457
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20458
|
+
configPath,
|
|
20459
|
+
configFormat: "hermes_config_yaml",
|
|
20460
|
+
mcpServer
|
|
20461
|
+
};
|
|
20462
|
+
}
|
|
20463
|
+
function createHermesManualMeshCoordinatorSetup(meshId, workspace) {
|
|
20464
|
+
return {
|
|
20465
|
+
kind: "manual",
|
|
20466
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20467
|
+
configFormat: "hermes_config_yaml",
|
|
20468
|
+
configPathCommand: HERMES_MCP_CONFIG_PATH,
|
|
20469
|
+
requiresRestart: true,
|
|
20470
|
+
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.",
|
|
20471
|
+
template: renderMeshCoordinatorTemplate(
|
|
20472
|
+
"mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n",
|
|
20473
|
+
{
|
|
20474
|
+
meshId,
|
|
20475
|
+
workspace,
|
|
20476
|
+
serverName: DEFAULT_SERVER_NAME,
|
|
20477
|
+
adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND
|
|
20478
|
+
}
|
|
20479
|
+
)
|
|
20480
|
+
};
|
|
20481
|
+
}
|
|
20018
20482
|
function resolveMeshCoordinatorSetup(options) {
|
|
20019
20483
|
const { provider, meshId, workspace } = options;
|
|
20020
20484
|
const config = provider?.meshCoordinator;
|
|
@@ -20024,6 +20488,9 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20024
20488
|
reason: config?.reason || "Provider does not declare Repo Mesh coordinator support"
|
|
20025
20489
|
};
|
|
20026
20490
|
}
|
|
20491
|
+
if (isHermesProvider(provider, options.cliType)) {
|
|
20492
|
+
return resolveHermesMeshCoordinatorSetup(options);
|
|
20493
|
+
}
|
|
20027
20494
|
const mcpConfig = config.mcpConfig;
|
|
20028
20495
|
if (!mcpConfig || mcpConfig.mode === "none") {
|
|
20029
20496
|
return {
|
|
@@ -20033,8 +20500,8 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20033
20500
|
}
|
|
20034
20501
|
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME;
|
|
20035
20502
|
if (mcpConfig.mode === "auto_import") {
|
|
20036
|
-
const
|
|
20037
|
-
if (!
|
|
20503
|
+
const path27 = mcpConfig.path?.trim();
|
|
20504
|
+
if (!path27) {
|
|
20038
20505
|
return { kind: "unsupported", reason: "Provider auto-import MCP config is missing a config path" };
|
|
20039
20506
|
}
|
|
20040
20507
|
const mcpServer = resolveAdhdevMcpServerLaunch({
|
|
@@ -20045,13 +20512,13 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20045
20512
|
if (!mcpServer) {
|
|
20046
20513
|
return {
|
|
20047
20514
|
kind: "unsupported",
|
|
20048
|
-
reason: "Could not resolve the ADHDev MCP server entrypoint
|
|
20515
|
+
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
20049
20516
|
};
|
|
20050
20517
|
}
|
|
20051
20518
|
return {
|
|
20052
20519
|
kind: "auto_import",
|
|
20053
20520
|
serverName,
|
|
20054
|
-
configPath: (
|
|
20521
|
+
configPath: resolveMcpConfigPath(path27, workspace),
|
|
20055
20522
|
configFormat: mcpConfig.format,
|
|
20056
20523
|
mcpServer
|
|
20057
20524
|
};
|
|
@@ -20085,14 +20552,85 @@ function resolveMeshCoordinatorSetup(options) {
|
|
|
20085
20552
|
function renderMeshCoordinatorTemplate(template, values) {
|
|
20086
20553
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key) => values[key] || "");
|
|
20087
20554
|
}
|
|
20555
|
+
function resolveMcpConfigPath(configPath, workspace) {
|
|
20556
|
+
const trimmed = configPath.trim();
|
|
20557
|
+
if (trimmed === "~") return os17.homedir();
|
|
20558
|
+
if (trimmed.startsWith("~/")) return (0, import_node_path.join)(os17.homedir(), trimmed.slice(2));
|
|
20559
|
+
if ((0, import_node_path.isAbsolute)(trimmed)) return trimmed;
|
|
20560
|
+
return (0, import_node_path.join)(workspace, trimmed);
|
|
20561
|
+
}
|
|
20088
20562
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
20089
20563
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
20090
20564
|
if (!entryPath) return null;
|
|
20565
|
+
const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
|
|
20566
|
+
if (!nodeExecutable) return null;
|
|
20091
20567
|
return {
|
|
20092
|
-
command:
|
|
20568
|
+
command: nodeExecutable,
|
|
20093
20569
|
args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
|
|
20094
20570
|
};
|
|
20095
20571
|
}
|
|
20572
|
+
function resolveMcpNodeExecutable(explicitExecutable) {
|
|
20573
|
+
const explicit = explicitExecutable?.trim();
|
|
20574
|
+
if (explicit) return explicit;
|
|
20575
|
+
const candidates = [];
|
|
20576
|
+
const addCandidate = (candidate) => {
|
|
20577
|
+
const trimmed = candidate?.trim();
|
|
20578
|
+
if (!trimmed) return;
|
|
20579
|
+
const normalized = normalizeExistingPath(trimmed) || trimmed;
|
|
20580
|
+
if (!candidates.includes(normalized)) candidates.push(normalized);
|
|
20581
|
+
};
|
|
20582
|
+
addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE);
|
|
20583
|
+
addCandidate(process.env.ADHDEV_NODE_EXECUTABLE);
|
|
20584
|
+
addCandidate(process.env.npm_node_execpath);
|
|
20585
|
+
addNodeCandidatesFromPath(process.env.PATH, addCandidate);
|
|
20586
|
+
addNodeCandidatesFromNvm(os17.homedir(), addCandidate);
|
|
20587
|
+
addCandidate("/opt/homebrew/bin/node");
|
|
20588
|
+
addCandidate("/usr/local/bin/node");
|
|
20589
|
+
addCandidate("/usr/bin/node");
|
|
20590
|
+
addCandidate(process.execPath);
|
|
20591
|
+
for (const candidate of candidates) {
|
|
20592
|
+
if (nodeRuntimeSupportsWebSocket(candidate)) return candidate;
|
|
20593
|
+
}
|
|
20594
|
+
return null;
|
|
20595
|
+
}
|
|
20596
|
+
function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
20597
|
+
for (const entry of (pathValue || "").split(":")) {
|
|
20598
|
+
const dir = entry.trim();
|
|
20599
|
+
if (!dir) continue;
|
|
20600
|
+
addCandidate((0, import_node_path.join)(dir, "node"));
|
|
20601
|
+
}
|
|
20602
|
+
}
|
|
20603
|
+
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
20604
|
+
const versionsDir = (0, import_node_path.join)(homeDir, ".nvm", "versions", "node");
|
|
20605
|
+
try {
|
|
20606
|
+
const versionDirs = (0, import_node_fs3.readdirSync)(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
20607
|
+
for (const versionDir of versionDirs) {
|
|
20608
|
+
addCandidate((0, import_node_path.join)(versionsDir, versionDir, "bin", "node"));
|
|
20609
|
+
}
|
|
20610
|
+
} catch {
|
|
20611
|
+
}
|
|
20612
|
+
}
|
|
20613
|
+
function compareNodeVersionNamesDescending(a, b) {
|
|
20614
|
+
const parse = (value) => value.replace(/^v/, "").split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
20615
|
+
const left = parse(a);
|
|
20616
|
+
const right = parse(b);
|
|
20617
|
+
for (let i = 0; i < Math.max(left.length, right.length); i++) {
|
|
20618
|
+
const diff = (right[i] || 0) - (left[i] || 0);
|
|
20619
|
+
if (diff !== 0) return diff;
|
|
20620
|
+
}
|
|
20621
|
+
return b.localeCompare(a);
|
|
20622
|
+
}
|
|
20623
|
+
function nodeRuntimeSupportsWebSocket(nodeExecutable) {
|
|
20624
|
+
try {
|
|
20625
|
+
(0, import_node_child_process3.execFileSync)(nodeExecutable, ["-e", "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
|
|
20626
|
+
stdio: "ignore",
|
|
20627
|
+
timeout: 3e3
|
|
20628
|
+
});
|
|
20629
|
+
return true;
|
|
20630
|
+
} catch {
|
|
20631
|
+
return false;
|
|
20632
|
+
}
|
|
20633
|
+
}
|
|
20096
20634
|
function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
20097
20635
|
const explicit = explicitPath?.trim();
|
|
20098
20636
|
if (explicit) return normalizeExistingPath(explicit) || explicit;
|
|
@@ -20128,15 +20666,109 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
20128
20666
|
}
|
|
20129
20667
|
function normalizeExistingPath(filePath) {
|
|
20130
20668
|
try {
|
|
20131
|
-
if (!(0,
|
|
20132
|
-
return
|
|
20669
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return null;
|
|
20670
|
+
return import_node_fs3.realpathSync.native(filePath);
|
|
20133
20671
|
} catch {
|
|
20134
20672
|
return null;
|
|
20135
20673
|
}
|
|
20136
20674
|
}
|
|
20137
20675
|
|
|
20676
|
+
// src/mesh/mesh-events.ts
|
|
20677
|
+
init_mesh_config();
|
|
20678
|
+
init_logger();
|
|
20679
|
+
function readNonEmptyString(value) {
|
|
20680
|
+
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
20681
|
+
}
|
|
20682
|
+
function formatCompletionMetadata(event) {
|
|
20683
|
+
const parts = [
|
|
20684
|
+
readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : "",
|
|
20685
|
+
readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : "",
|
|
20686
|
+
readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : ""
|
|
20687
|
+
].filter(Boolean);
|
|
20688
|
+
return parts.length > 0 ? ` (${parts.join("; ")})` : "";
|
|
20689
|
+
}
|
|
20690
|
+
function buildMeshSystemMessage(args) {
|
|
20691
|
+
const metadata = formatCompletionMetadata(args.metadataEvent);
|
|
20692
|
+
if (args.event === "agent:generating_completed") {
|
|
20693
|
+
return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path; use mesh_read_chat once to review its final progress, but do not poll repeatedly.`;
|
|
20694
|
+
}
|
|
20695
|
+
if (args.event === "agent:waiting_approval") {
|
|
20696
|
+
return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
20697
|
+
}
|
|
20698
|
+
return "";
|
|
20699
|
+
}
|
|
20700
|
+
function injectMeshSystemMessage(components, args) {
|
|
20701
|
+
const coordinatorInstances = components.instanceManager.getByCategory("cli").filter((inst) => {
|
|
20702
|
+
const instState = inst.getState();
|
|
20703
|
+
if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
|
|
20704
|
+
if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
|
|
20705
|
+
return true;
|
|
20706
|
+
});
|
|
20707
|
+
if (coordinatorInstances.length === 0) return { success: true, forwarded: 0 };
|
|
20708
|
+
const messageText = buildMeshSystemMessage({
|
|
20709
|
+
event: args.event,
|
|
20710
|
+
nodeLabel: args.nodeLabel,
|
|
20711
|
+
metadataEvent: args.metadataEvent
|
|
20712
|
+
});
|
|
20713
|
+
if (!messageText) return { success: false, error: "unsupported mesh event" };
|
|
20714
|
+
for (const coord of coordinatorInstances) {
|
|
20715
|
+
const coordState = coord.getState();
|
|
20716
|
+
LOG.info("MeshEvents", `Forwarding mesh event to coordinator ${coordState.instanceId}`);
|
|
20717
|
+
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
20718
|
+
}
|
|
20719
|
+
return { success: true, forwarded: coordinatorInstances.length };
|
|
20720
|
+
}
|
|
20721
|
+
function handleMeshForwardEvent(components, payload) {
|
|
20722
|
+
const eventName = readNonEmptyString(payload.event);
|
|
20723
|
+
if (eventName !== "agent:generating_completed" && eventName !== "agent:waiting_approval") {
|
|
20724
|
+
return { success: false, error: "unsupported mesh event" };
|
|
20725
|
+
}
|
|
20726
|
+
const meshId = readNonEmptyString(payload.meshId);
|
|
20727
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
20728
|
+
const nodeId = readNonEmptyString(payload.nodeId);
|
|
20729
|
+
const workspace = readNonEmptyString(payload.workspace);
|
|
20730
|
+
const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
|
|
20731
|
+
return injectMeshSystemMessage(components, {
|
|
20732
|
+
meshId,
|
|
20733
|
+
nodeLabel,
|
|
20734
|
+
event: eventName,
|
|
20735
|
+
metadataEvent: {
|
|
20736
|
+
targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
|
|
20737
|
+
providerType: readNonEmptyString(payload.providerType),
|
|
20738
|
+
providerSessionId: readNonEmptyString(payload.providerSessionId)
|
|
20739
|
+
}
|
|
20740
|
+
});
|
|
20741
|
+
}
|
|
20742
|
+
function setupMeshEventForwarding(components) {
|
|
20743
|
+
components.instanceManager.onEvent((event) => {
|
|
20744
|
+
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
20745
|
+
const instanceId = readNonEmptyString(event.instanceId);
|
|
20746
|
+
if (!instanceId) return;
|
|
20747
|
+
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
20748
|
+
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
20749
|
+
const state = sourceInstance.getState();
|
|
20750
|
+
const workspace = readNonEmptyString(state.workspace);
|
|
20751
|
+
if (!workspace) return;
|
|
20752
|
+
const settings = state.settings && typeof state.settings === "object" ? state.settings : {};
|
|
20753
|
+
const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
|
|
20754
|
+
const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
|
|
20755
|
+
const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
|
|
20756
|
+
if (!meshId) return;
|
|
20757
|
+
const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
|
|
20758
|
+
const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
|
|
20759
|
+
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
|
|
20760
|
+
injectMeshSystemMessage(components, {
|
|
20761
|
+
meshId,
|
|
20762
|
+
sourceInstanceId: instanceId,
|
|
20763
|
+
nodeLabel,
|
|
20764
|
+
event: event.event,
|
|
20765
|
+
metadataEvent: event
|
|
20766
|
+
});
|
|
20767
|
+
});
|
|
20768
|
+
}
|
|
20769
|
+
|
|
20138
20770
|
// src/status/snapshot.ts
|
|
20139
|
-
var
|
|
20771
|
+
var os18 = __toESM(require("os"));
|
|
20140
20772
|
init_config();
|
|
20141
20773
|
init_terminal_screen();
|
|
20142
20774
|
init_logger();
|
|
@@ -20192,8 +20824,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20192
20824
|
}
|
|
20193
20825
|
function buildMachineInfo(profile = "full") {
|
|
20194
20826
|
const base = {
|
|
20195
|
-
hostname:
|
|
20196
|
-
platform:
|
|
20827
|
+
hostname: os18.hostname(),
|
|
20828
|
+
platform: os18.platform()
|
|
20197
20829
|
};
|
|
20198
20830
|
if (profile === "live") {
|
|
20199
20831
|
return base;
|
|
@@ -20202,23 +20834,23 @@ function buildMachineInfo(profile = "full") {
|
|
|
20202
20834
|
const memSnap2 = getHostMemorySnapshot();
|
|
20203
20835
|
return {
|
|
20204
20836
|
...base,
|
|
20205
|
-
arch:
|
|
20206
|
-
cpus:
|
|
20837
|
+
arch: os18.arch(),
|
|
20838
|
+
cpus: os18.cpus().length,
|
|
20207
20839
|
totalMem: memSnap2.totalMem,
|
|
20208
|
-
release:
|
|
20840
|
+
release: os18.release()
|
|
20209
20841
|
};
|
|
20210
20842
|
}
|
|
20211
20843
|
const memSnap = getHostMemorySnapshot();
|
|
20212
20844
|
return {
|
|
20213
20845
|
...base,
|
|
20214
|
-
arch:
|
|
20215
|
-
cpus:
|
|
20846
|
+
arch: os18.arch(),
|
|
20847
|
+
cpus: os18.cpus().length,
|
|
20216
20848
|
totalMem: memSnap.totalMem,
|
|
20217
20849
|
freeMem: memSnap.freeMem,
|
|
20218
20850
|
availableMem: memSnap.availableMem,
|
|
20219
|
-
loadavg:
|
|
20220
|
-
uptime:
|
|
20221
|
-
release:
|
|
20851
|
+
loadavg: os18.loadavg(),
|
|
20852
|
+
uptime: os18.uptime(),
|
|
20853
|
+
release: os18.release()
|
|
20222
20854
|
};
|
|
20223
20855
|
}
|
|
20224
20856
|
function parseMessageTime(value) {
|
|
@@ -20452,14 +21084,14 @@ function buildStatusSnapshot(options) {
|
|
|
20452
21084
|
var import_child_process8 = require("child_process");
|
|
20453
21085
|
var import_child_process9 = require("child_process");
|
|
20454
21086
|
var fs9 = __toESM(require("fs"));
|
|
20455
|
-
var
|
|
20456
|
-
var
|
|
21087
|
+
var os19 = __toESM(require("os"));
|
|
21088
|
+
var path21 = __toESM(require("path"));
|
|
20457
21089
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
20458
21090
|
function getUpgradeLogPath() {
|
|
20459
|
-
const home =
|
|
20460
|
-
const dir =
|
|
21091
|
+
const home = os19.homedir();
|
|
21092
|
+
const dir = path21.join(home, ".adhdev");
|
|
20461
21093
|
fs9.mkdirSync(dir, { recursive: true });
|
|
20462
|
-
return
|
|
21094
|
+
return path21.join(dir, "daemon-upgrade.log");
|
|
20463
21095
|
}
|
|
20464
21096
|
function appendUpgradeLog(message) {
|
|
20465
21097
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -20470,14 +21102,14 @@ function appendUpgradeLog(message) {
|
|
|
20470
21102
|
}
|
|
20471
21103
|
}
|
|
20472
21104
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
20473
|
-
const binDir =
|
|
21105
|
+
const binDir = path21.dirname(nodeExecutable);
|
|
20474
21106
|
if (platform10 === "win32") {
|
|
20475
|
-
const npmCliPath =
|
|
21107
|
+
const npmCliPath = path21.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
20476
21108
|
if (fs9.existsSync(npmCliPath)) {
|
|
20477
21109
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20478
21110
|
}
|
|
20479
21111
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
20480
|
-
const candidatePath =
|
|
21112
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20481
21113
|
if (fs9.existsSync(candidatePath)) {
|
|
20482
21114
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20483
21115
|
}
|
|
@@ -20485,7 +21117,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
20485
21117
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
20486
21118
|
}
|
|
20487
21119
|
for (const candidate of ["npm"]) {
|
|
20488
|
-
const candidatePath =
|
|
21120
|
+
const candidatePath = path21.join(binDir, candidate);
|
|
20489
21121
|
if (fs9.existsSync(candidatePath)) {
|
|
20490
21122
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
20491
21123
|
}
|
|
@@ -20502,13 +21134,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20502
21134
|
let currentDir = resolvedPath;
|
|
20503
21135
|
try {
|
|
20504
21136
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
20505
|
-
currentDir =
|
|
21137
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20506
21138
|
}
|
|
20507
21139
|
} catch {
|
|
20508
|
-
currentDir =
|
|
21140
|
+
currentDir = path21.dirname(resolvedPath);
|
|
20509
21141
|
}
|
|
20510
21142
|
while (true) {
|
|
20511
|
-
const packageJsonPath =
|
|
21143
|
+
const packageJsonPath = path21.join(currentDir, "package.json");
|
|
20512
21144
|
try {
|
|
20513
21145
|
if (fs9.existsSync(packageJsonPath)) {
|
|
20514
21146
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -20519,7 +21151,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20519
21151
|
}
|
|
20520
21152
|
} catch {
|
|
20521
21153
|
}
|
|
20522
|
-
const parentDir =
|
|
21154
|
+
const parentDir = path21.dirname(currentDir);
|
|
20523
21155
|
if (parentDir === currentDir) {
|
|
20524
21156
|
return null;
|
|
20525
21157
|
}
|
|
@@ -20527,13 +21159,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
20527
21159
|
}
|
|
20528
21160
|
}
|
|
20529
21161
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
20530
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
20531
|
-
if (
|
|
21162
|
+
const nodeModulesDir = packageName.startsWith("@") ? path21.dirname(path21.dirname(packageRoot)) : path21.dirname(packageRoot);
|
|
21163
|
+
if (path21.basename(nodeModulesDir) !== "node_modules") {
|
|
20532
21164
|
return null;
|
|
20533
21165
|
}
|
|
20534
|
-
const maybeLibDir =
|
|
20535
|
-
if (
|
|
20536
|
-
return
|
|
21166
|
+
const maybeLibDir = path21.dirname(nodeModulesDir);
|
|
21167
|
+
if (path21.basename(maybeLibDir) === "lib") {
|
|
21168
|
+
return path21.dirname(maybeLibDir);
|
|
20537
21169
|
}
|
|
20538
21170
|
return maybeLibDir;
|
|
20539
21171
|
}
|
|
@@ -20648,7 +21280,7 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
20648
21280
|
}
|
|
20649
21281
|
}
|
|
20650
21282
|
function stopSessionHostProcesses(appName) {
|
|
20651
|
-
const pidFile =
|
|
21283
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
20652
21284
|
try {
|
|
20653
21285
|
if (fs9.existsSync(pidFile)) {
|
|
20654
21286
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -20665,7 +21297,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
20665
21297
|
}
|
|
20666
21298
|
}
|
|
20667
21299
|
function removeDaemonPidFile() {
|
|
20668
|
-
const pidFile =
|
|
21300
|
+
const pidFile = path21.join(os19.homedir(), ".adhdev", "daemon.pid");
|
|
20669
21301
|
try {
|
|
20670
21302
|
fs9.unlinkSync(pidFile);
|
|
20671
21303
|
} catch {
|
|
@@ -20676,7 +21308,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20676
21308
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20677
21309
|
if (!npmRoot) return;
|
|
20678
21310
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
20679
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
21311
|
+
const binDir = process.platform === "win32" ? npmPrefix : path21.join(npmPrefix, "bin");
|
|
20680
21312
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
20681
21313
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
20682
21314
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -20684,25 +21316,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
20684
21316
|
}
|
|
20685
21317
|
if (pkgName.startsWith("@")) {
|
|
20686
21318
|
const [scope, name] = pkgName.split("/");
|
|
20687
|
-
const scopeDir =
|
|
21319
|
+
const scopeDir = path21.join(npmRoot, scope);
|
|
20688
21320
|
if (!fs9.existsSync(scopeDir)) return;
|
|
20689
21321
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
20690
21322
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
20691
|
-
fs9.rmSync(
|
|
20692
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
21323
|
+
fs9.rmSync(path21.join(scopeDir, entry), { recursive: true, force: true });
|
|
21324
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path21.join(scopeDir, entry)}`);
|
|
20693
21325
|
}
|
|
20694
21326
|
} else {
|
|
20695
21327
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
20696
21328
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
20697
|
-
fs9.rmSync(
|
|
20698
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
21329
|
+
fs9.rmSync(path21.join(npmRoot, entry), { recursive: true, force: true });
|
|
21330
|
+
appendUpgradeLog(`Removed stale staging dir: ${path21.join(npmRoot, entry)}`);
|
|
20699
21331
|
}
|
|
20700
21332
|
}
|
|
20701
21333
|
if (fs9.existsSync(binDir)) {
|
|
20702
21334
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
20703
21335
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
20704
|
-
fs9.rmSync(
|
|
20705
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
21336
|
+
fs9.rmSync(path21.join(binDir, entry), { recursive: true, force: true });
|
|
21337
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path21.join(binDir, entry)}`);
|
|
20706
21338
|
}
|
|
20707
21339
|
}
|
|
20708
21340
|
}
|
|
@@ -20803,6 +21435,56 @@ function normalizeReleaseChannel(value) {
|
|
|
20803
21435
|
function resolveUpgradeChannel(args) {
|
|
20804
21436
|
return normalizeReleaseChannel(args?.channel) || normalizeReleaseChannel(args?.updatePolicy?.channel) || normalizeReleaseChannel(args?.npmTag) || normalizeReleaseChannel(loadConfig().updateChannel) || "stable";
|
|
20805
21437
|
}
|
|
21438
|
+
function readProviderPriorityFromPolicy(policy) {
|
|
21439
|
+
const record = policy && typeof policy === "object" && !Array.isArray(policy) ? policy : {};
|
|
21440
|
+
const raw = record.providerPriority;
|
|
21441
|
+
if (!Array.isArray(raw)) return [];
|
|
21442
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21443
|
+
return raw.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean).filter((type) => {
|
|
21444
|
+
if (seen.has(type)) return false;
|
|
21445
|
+
seen.add(type);
|
|
21446
|
+
return true;
|
|
21447
|
+
});
|
|
21448
|
+
}
|
|
21449
|
+
async function resolveProviderTypeFromPriority(args) {
|
|
21450
|
+
if (!args.providerPriority.length) {
|
|
21451
|
+
return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
|
|
21452
|
+
}
|
|
21453
|
+
const failed = [];
|
|
21454
|
+
for (const requestedType of args.providerPriority) {
|
|
21455
|
+
const normalizedType = args.providerLoader.resolveAlias(requestedType);
|
|
21456
|
+
if (!args.providerLoader.isMachineProviderEnabled(normalizedType)) {
|
|
21457
|
+
failed.push(`${requestedType}: disabled`);
|
|
21458
|
+
continue;
|
|
21459
|
+
}
|
|
21460
|
+
const detected = await detectCLI(normalizedType, args.providerLoader, { includeVersion: false });
|
|
21461
|
+
args.providerLoader.setCliDetectionResults([{
|
|
21462
|
+
id: normalizedType,
|
|
21463
|
+
installed: !!detected,
|
|
21464
|
+
path: detected?.path
|
|
21465
|
+
}], false);
|
|
21466
|
+
args.onStatusChange?.();
|
|
21467
|
+
if (detected) return { providerType: normalizedType };
|
|
21468
|
+
failed.push(`${requestedType}: not detected`);
|
|
21469
|
+
}
|
|
21470
|
+
return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
|
|
21471
|
+
}
|
|
21472
|
+
function loadYamlModule() {
|
|
21473
|
+
return yaml;
|
|
21474
|
+
}
|
|
21475
|
+
function getMcpServersKey(format) {
|
|
21476
|
+
return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
|
|
21477
|
+
}
|
|
21478
|
+
function parseMeshCoordinatorMcpConfig(text, format) {
|
|
21479
|
+
if (!text.trim()) return {};
|
|
21480
|
+
if (format === "claude_mcp_json") return JSON.parse(text);
|
|
21481
|
+
const parsed = loadYamlModule().load(text);
|
|
21482
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
21483
|
+
}
|
|
21484
|
+
function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
21485
|
+
if (format === "claude_mcp_json") return JSON.stringify(config, null, 2);
|
|
21486
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
21487
|
+
}
|
|
20806
21488
|
var CHAT_COMMANDS = [
|
|
20807
21489
|
"send_chat",
|
|
20808
21490
|
"new_chat",
|
|
@@ -20901,6 +21583,154 @@ var DaemonCommandRouter = class {
|
|
|
20901
21583
|
constructor(deps) {
|
|
20902
21584
|
this.deps = deps;
|
|
20903
21585
|
}
|
|
21586
|
+
getCachedInlineMesh(meshId, inlineMesh) {
|
|
21587
|
+
if (inlineMesh && typeof inlineMesh === "object") {
|
|
21588
|
+
this.inlineMeshCache.set(meshId, inlineMesh);
|
|
21589
|
+
return inlineMesh;
|
|
21590
|
+
}
|
|
21591
|
+
return this.inlineMeshCache.get(meshId);
|
|
21592
|
+
}
|
|
21593
|
+
async getMeshForCommand(meshId, inlineMesh) {
|
|
21594
|
+
try {
|
|
21595
|
+
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21596
|
+
const mesh = getMesh3(meshId);
|
|
21597
|
+
if (mesh) return { mesh, inline: false };
|
|
21598
|
+
} catch {
|
|
21599
|
+
}
|
|
21600
|
+
const cached = this.getCachedInlineMesh(meshId, inlineMesh);
|
|
21601
|
+
return cached ? { mesh: cached, inline: true } : null;
|
|
21602
|
+
}
|
|
21603
|
+
updateInlineMeshNode(meshId, mesh, node) {
|
|
21604
|
+
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
21605
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
21606
|
+
if (idx >= 0) mesh.nodes[idx] = node;
|
|
21607
|
+
else mesh.nodes.push(node);
|
|
21608
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21609
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21610
|
+
}
|
|
21611
|
+
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
21612
|
+
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
21613
|
+
const idx = mesh.nodes.findIndex((entry) => entry?.id === nodeId || entry?.nodeId === nodeId);
|
|
21614
|
+
if (idx === -1) return false;
|
|
21615
|
+
mesh.nodes.splice(idx, 1);
|
|
21616
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21617
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21618
|
+
return true;
|
|
21619
|
+
}
|
|
21620
|
+
normalizeMeshSessionCleanupMode(value) {
|
|
21621
|
+
return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
|
|
21622
|
+
}
|
|
21623
|
+
sessionMatchesMeshNode(record, node, nodeId, sessionIds) {
|
|
21624
|
+
const sessionId = typeof record?.sessionId === "string" ? record.sessionId : "";
|
|
21625
|
+
if (!sessionId) return false;
|
|
21626
|
+
if (sessionIds?.size) return sessionIds.has(sessionId);
|
|
21627
|
+
const workspace = typeof node?.workspace === "string" ? node.workspace : "";
|
|
21628
|
+
if (workspace && record?.workspace === workspace) return true;
|
|
21629
|
+
if (record?.meta?.meshNodeId === nodeId) return true;
|
|
21630
|
+
return false;
|
|
21631
|
+
}
|
|
21632
|
+
isCompletedHostedSession(record) {
|
|
21633
|
+
return record?.lifecycle === "stopped" || record?.lifecycle === "failed" || record?.lifecycle === "interrupted";
|
|
21634
|
+
}
|
|
21635
|
+
async cleanupMeshSessions(args) {
|
|
21636
|
+
if (args.mode === "preserve") {
|
|
21637
|
+
return { success: true, mode: "preserve", matchedCount: 0, stoppedSessionIds: [], deletedSessionIds: [], skippedSessionIds: [] };
|
|
21638
|
+
}
|
|
21639
|
+
if (!this.deps.sessionHostControl) return { success: false, error: "Session host control unavailable" };
|
|
21640
|
+
const requestedSessionIds = Array.isArray(args.sessionIds) ? new Set(args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean)) : void 0;
|
|
21641
|
+
const sessions = await this.deps.sessionHostControl.listSessions();
|
|
21642
|
+
const matched = sessions.filter((record) => this.sessionMatchesMeshNode(record, args.node, args.nodeId, requestedSessionIds));
|
|
21643
|
+
const hasExplicitSessionIds = !!requestedSessionIds?.size;
|
|
21644
|
+
const stoppedSessionIds = [];
|
|
21645
|
+
const deletedSessionIds = [];
|
|
21646
|
+
const skippedSessionIds = [];
|
|
21647
|
+
const skippedLiveSessionIds = [];
|
|
21648
|
+
const deleteUnsupportedSessionIds = [];
|
|
21649
|
+
const recordsRemainSessionIds = [];
|
|
21650
|
+
const errors = [];
|
|
21651
|
+
const matchedBySurfaceKind = {
|
|
21652
|
+
live_runtime: 0,
|
|
21653
|
+
recovery_snapshot: 0,
|
|
21654
|
+
inactive_record: 0
|
|
21655
|
+
};
|
|
21656
|
+
for (const record of matched) {
|
|
21657
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21658
|
+
matchedBySurfaceKind[surfaceKind] += 1;
|
|
21659
|
+
}
|
|
21660
|
+
for (const record of matched) {
|
|
21661
|
+
const sessionId = String(record.sessionId);
|
|
21662
|
+
const completed = this.isCompletedHostedSession(record);
|
|
21663
|
+
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
21664
|
+
const liveRuntime = surfaceKind === "live_runtime";
|
|
21665
|
+
if (!hasExplicitSessionIds && liveRuntime) {
|
|
21666
|
+
skippedSessionIds.push(sessionId);
|
|
21667
|
+
skippedLiveSessionIds.push(sessionId);
|
|
21668
|
+
continue;
|
|
21669
|
+
}
|
|
21670
|
+
try {
|
|
21671
|
+
if (args.mode === "stop") {
|
|
21672
|
+
if (!completed) {
|
|
21673
|
+
if (!args.dryRun) await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21674
|
+
stoppedSessionIds.push(sessionId);
|
|
21675
|
+
} else {
|
|
21676
|
+
skippedSessionIds.push(sessionId);
|
|
21677
|
+
}
|
|
21678
|
+
continue;
|
|
21679
|
+
}
|
|
21680
|
+
if (args.mode === "delete_stopped") {
|
|
21681
|
+
if (completed) {
|
|
21682
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: false });
|
|
21683
|
+
deletedSessionIds.push(sessionId);
|
|
21684
|
+
} else {
|
|
21685
|
+
skippedSessionIds.push(sessionId);
|
|
21686
|
+
}
|
|
21687
|
+
continue;
|
|
21688
|
+
}
|
|
21689
|
+
if (args.mode === "stop_and_delete") {
|
|
21690
|
+
if (!args.dryRun) await this.deps.sessionHostControl.deleteSession(sessionId, { force: true });
|
|
21691
|
+
deletedSessionIds.push(sessionId);
|
|
21692
|
+
continue;
|
|
21693
|
+
}
|
|
21694
|
+
} catch (e) {
|
|
21695
|
+
const message = e?.message || String(e);
|
|
21696
|
+
if (message.includes("Unsupported session host request: delete_session") && (args.mode === "delete_stopped" || args.mode === "stop_and_delete")) {
|
|
21697
|
+
deleteUnsupportedSessionIds.push(sessionId);
|
|
21698
|
+
recordsRemainSessionIds.push(sessionId);
|
|
21699
|
+
if (args.mode === "stop_and_delete" && !completed) {
|
|
21700
|
+
try {
|
|
21701
|
+
await this.deps.sessionHostControl.stopSession(sessionId);
|
|
21702
|
+
stoppedSessionIds.push(sessionId);
|
|
21703
|
+
} catch (stopError) {
|
|
21704
|
+
errors.push({ sessionId, error: stopError?.message || String(stopError) });
|
|
21705
|
+
continue;
|
|
21706
|
+
}
|
|
21707
|
+
}
|
|
21708
|
+
skippedSessionIds.push(sessionId);
|
|
21709
|
+
continue;
|
|
21710
|
+
}
|
|
21711
|
+
errors.push({ sessionId, error: message });
|
|
21712
|
+
}
|
|
21713
|
+
}
|
|
21714
|
+
const deleteUnsupported = deleteUnsupportedSessionIds.length > 0;
|
|
21715
|
+
return {
|
|
21716
|
+
success: errors.length === 0,
|
|
21717
|
+
mode: args.mode,
|
|
21718
|
+
dryRun: args.dryRun === true,
|
|
21719
|
+
matchedCount: matched.length,
|
|
21720
|
+
matchedBySurfaceKind,
|
|
21721
|
+
stoppedSessionIds,
|
|
21722
|
+
deletedSessionIds,
|
|
21723
|
+
skippedSessionIds,
|
|
21724
|
+
skippedLiveSessionIds,
|
|
21725
|
+
...deleteUnsupported ? {
|
|
21726
|
+
deleteUnsupported: true,
|
|
21727
|
+
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
21728
|
+
deleteUnsupportedSessionIds,
|
|
21729
|
+
recordsRemainSessionIds
|
|
21730
|
+
} : {},
|
|
21731
|
+
...errors.length ? { errors } : {}
|
|
21732
|
+
};
|
|
21733
|
+
}
|
|
20904
21734
|
async traceSessionHostAction(action, args, run, summarizeResult) {
|
|
20905
21735
|
const interactionId = typeof args?._interactionId === "string" ? args._interactionId : void 0;
|
|
20906
21736
|
const sessionId = typeof args?.sessionId === "string" ? args.sessionId : void 0;
|
|
@@ -21020,6 +21850,9 @@ var DaemonCommandRouter = class {
|
|
|
21020
21850
|
async executeDaemonCommand(cmd, args) {
|
|
21021
21851
|
switch (cmd) {
|
|
21022
21852
|
// ─── CLI / ACP commands ───
|
|
21853
|
+
case "mesh_forward_event": {
|
|
21854
|
+
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
21855
|
+
}
|
|
21023
21856
|
case "launch_cli":
|
|
21024
21857
|
case "stop_cli":
|
|
21025
21858
|
case "set_cli_view_mode":
|
|
@@ -21564,7 +22397,26 @@ var DaemonCommandRouter = class {
|
|
|
21564
22397
|
if (!name) return { success: false, error: "name required" };
|
|
21565
22398
|
try {
|
|
21566
22399
|
const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21567
|
-
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch });
|
|
22400
|
+
const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
|
|
22401
|
+
return { success: true, mesh };
|
|
22402
|
+
} catch (e) {
|
|
22403
|
+
return { success: false, error: e.message };
|
|
22404
|
+
}
|
|
22405
|
+
}
|
|
22406
|
+
case "update_mesh": {
|
|
22407
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22408
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22409
|
+
try {
|
|
22410
|
+
const { updateMesh: updateMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22411
|
+
const patch = {};
|
|
22412
|
+
if (typeof args?.name === "string") patch.name = args.name;
|
|
22413
|
+
if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
|
|
22414
|
+
if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
|
|
22415
|
+
if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
|
|
22416
|
+
if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
|
|
22417
|
+
const mesh = updateMesh2(meshId, patch);
|
|
22418
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22419
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
21568
22420
|
return { success: true, mesh };
|
|
21569
22421
|
} catch (e) {
|
|
21570
22422
|
return { success: false, error: e.message };
|
|
@@ -21588,21 +22440,164 @@ var DaemonCommandRouter = class {
|
|
|
21588
22440
|
if (!workspace) return { success: false, error: "workspace required" };
|
|
21589
22441
|
try {
|
|
21590
22442
|
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
21591
|
-
const
|
|
22443
|
+
const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
|
|
22444
|
+
const readOnly = args?.readOnly === true;
|
|
22445
|
+
const policy = {
|
|
22446
|
+
...readOnly ? { readOnly: true } : {},
|
|
22447
|
+
...providerPriority.length ? { providerPriority } : {}
|
|
22448
|
+
};
|
|
22449
|
+
const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
|
|
21592
22450
|
if (!node) return { success: false, error: "Mesh not found" };
|
|
21593
22451
|
return { success: true, node };
|
|
21594
22452
|
} catch (e) {
|
|
21595
22453
|
return { success: false, error: e.message };
|
|
21596
22454
|
}
|
|
21597
22455
|
}
|
|
22456
|
+
case "update_mesh_node": {
|
|
22457
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22458
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22459
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22460
|
+
try {
|
|
22461
|
+
const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22462
|
+
const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
|
|
22463
|
+
if (Array.isArray(args?.providerPriority)) {
|
|
22464
|
+
const providerPriority = args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean);
|
|
22465
|
+
delete policy.provider_priority;
|
|
22466
|
+
if (providerPriority.length) {
|
|
22467
|
+
policy.providerPriority = providerPriority;
|
|
22468
|
+
} else {
|
|
22469
|
+
delete policy.providerPriority;
|
|
22470
|
+
}
|
|
22471
|
+
}
|
|
22472
|
+
const node = updateNode2(meshId, nodeId, { policy });
|
|
22473
|
+
if (!node) return { success: false, error: "Mesh node not found" };
|
|
22474
|
+
return { success: true, node };
|
|
22475
|
+
} catch (e) {
|
|
22476
|
+
return { success: false, error: e.message };
|
|
22477
|
+
}
|
|
22478
|
+
}
|
|
22479
|
+
case "cleanup_mesh_sessions": {
|
|
22480
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22481
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
22482
|
+
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
22483
|
+
try {
|
|
22484
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22485
|
+
const mesh = meshRecord?.mesh;
|
|
22486
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22487
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22488
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
|
|
22489
|
+
const mode = this.normalizeMeshSessionCleanupMode(args?.mode ?? mesh?.policy?.sessionCleanupOnNodeRemove);
|
|
22490
|
+
const sessionIds = Array.isArray(args?.sessionIds) ? args.sessionIds.map((id) => typeof id === "string" ? id.trim() : "").filter(Boolean) : void 0;
|
|
22491
|
+
const result = await this.cleanupMeshSessions({
|
|
22492
|
+
meshId,
|
|
22493
|
+
nodeId,
|
|
22494
|
+
node,
|
|
22495
|
+
mode,
|
|
22496
|
+
sessionIds,
|
|
22497
|
+
dryRun: args?.dryRun === true
|
|
22498
|
+
});
|
|
22499
|
+
return result;
|
|
22500
|
+
} catch (e) {
|
|
22501
|
+
return { success: false, error: e.message };
|
|
22502
|
+
}
|
|
22503
|
+
}
|
|
21598
22504
|
case "remove_mesh_node": {
|
|
21599
22505
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21600
22506
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
21601
22507
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
21602
22508
|
try {
|
|
21603
|
-
const
|
|
21604
|
-
const
|
|
21605
|
-
|
|
22509
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22510
|
+
const mesh = meshRecord?.mesh;
|
|
22511
|
+
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
22512
|
+
const sessionCleanupMode = this.normalizeMeshSessionCleanupMode(
|
|
22513
|
+
args?.sessionCleanupMode ?? args?.session_cleanup_mode ?? mesh?.policy?.sessionCleanupOnNodeRemove
|
|
22514
|
+
);
|
|
22515
|
+
let sessionCleanup;
|
|
22516
|
+
if (node && sessionCleanupMode !== "preserve") {
|
|
22517
|
+
sessionCleanup = await this.cleanupMeshSessions({ meshId, nodeId, node, mode: sessionCleanupMode });
|
|
22518
|
+
if (sessionCleanup.success === false) return { success: false, removed: false, sessionCleanup };
|
|
22519
|
+
}
|
|
22520
|
+
if (node?.isLocalWorktree && node.workspace) {
|
|
22521
|
+
try {
|
|
22522
|
+
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
22523
|
+
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
22524
|
+
if (repoRoot) {
|
|
22525
|
+
const { removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22526
|
+
await removeWorktree2(repoRoot, node.workspace);
|
|
22527
|
+
}
|
|
22528
|
+
} catch (e) {
|
|
22529
|
+
LOG.warn("MeshNode", `Worktree cleanup failed for ${nodeId}: ${e.message}`);
|
|
22530
|
+
}
|
|
22531
|
+
}
|
|
22532
|
+
let removed = false;
|
|
22533
|
+
if (meshRecord?.inline) {
|
|
22534
|
+
removed = this.removeInlineMeshNode(meshId, mesh, nodeId);
|
|
22535
|
+
} else {
|
|
22536
|
+
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22537
|
+
removed = removeNode3(meshId, nodeId);
|
|
22538
|
+
}
|
|
22539
|
+
return { success: true, removed, ...sessionCleanup ? { sessionCleanup } : {} };
|
|
22540
|
+
} catch (e) {
|
|
22541
|
+
return { success: false, error: e.message };
|
|
22542
|
+
}
|
|
22543
|
+
}
|
|
22544
|
+
case "clone_mesh_node": {
|
|
22545
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
22546
|
+
const sourceNodeId = typeof args?.sourceNodeId === "string" ? args.sourceNodeId.trim() : "";
|
|
22547
|
+
const branch = typeof args?.branch === "string" ? args.branch.trim() : "";
|
|
22548
|
+
const baseBranch = typeof args?.baseBranch === "string" ? args.baseBranch.trim() : void 0;
|
|
22549
|
+
if (!meshId) return { success: false, error: "meshId required" };
|
|
22550
|
+
if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
|
|
22551
|
+
if (!branch) return { success: false, error: "branch required" };
|
|
22552
|
+
try {
|
|
22553
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
22554
|
+
const mesh = meshRecord?.mesh;
|
|
22555
|
+
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
22556
|
+
const sourceNode = mesh.nodes?.find((n) => n.id === sourceNodeId || n.nodeId === sourceNodeId);
|
|
22557
|
+
if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
|
|
22558
|
+
const repoRoot = sourceNode.repoRoot || sourceNode.workspace;
|
|
22559
|
+
const { createWorktree: createWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
22560
|
+
const result = await createWorktree2({
|
|
22561
|
+
repoRoot,
|
|
22562
|
+
branch,
|
|
22563
|
+
baseBranch,
|
|
22564
|
+
meshName: mesh.name
|
|
22565
|
+
});
|
|
22566
|
+
let node;
|
|
22567
|
+
if (meshRecord.inline) {
|
|
22568
|
+
const { randomUUID: randomUUID8 } = await import("crypto");
|
|
22569
|
+
node = {
|
|
22570
|
+
id: `node_${randomUUID8().replace(/-/g, "")}`,
|
|
22571
|
+
workspace: result.worktreePath,
|
|
22572
|
+
repoRoot: result.worktreePath,
|
|
22573
|
+
daemonId: sourceNode.daemonId,
|
|
22574
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22575
|
+
policy: { ...sourceNode.policy || {} },
|
|
22576
|
+
isLocalWorktree: true,
|
|
22577
|
+
worktreeBranch: result.branch,
|
|
22578
|
+
clonedFromNodeId: sourceNodeId
|
|
22579
|
+
};
|
|
22580
|
+
this.updateInlineMeshNode(meshId, mesh, node);
|
|
22581
|
+
} else {
|
|
22582
|
+
const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
22583
|
+
node = addNode3(meshId, {
|
|
22584
|
+
workspace: result.worktreePath,
|
|
22585
|
+
repoRoot: result.worktreePath,
|
|
22586
|
+
daemonId: sourceNode.daemonId,
|
|
22587
|
+
userOverrides: { ...sourceNode.userOverrides || {} },
|
|
22588
|
+
isLocalWorktree: true,
|
|
22589
|
+
worktreeBranch: result.branch,
|
|
22590
|
+
clonedFromNodeId: sourceNodeId,
|
|
22591
|
+
policy: { ...sourceNode.policy || {} }
|
|
22592
|
+
});
|
|
22593
|
+
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
22594
|
+
}
|
|
22595
|
+
return {
|
|
22596
|
+
success: true,
|
|
22597
|
+
node,
|
|
22598
|
+
worktreePath: result.worktreePath,
|
|
22599
|
+
branch: result.branch
|
|
22600
|
+
};
|
|
21606
22601
|
} catch (e) {
|
|
21607
22602
|
return { success: false, error: e.message };
|
|
21608
22603
|
}
|
|
@@ -21610,7 +22605,7 @@ var DaemonCommandRouter = class {
|
|
|
21610
22605
|
// ─── Mesh Coordinator Launch ───
|
|
21611
22606
|
case "launch_mesh_coordinator": {
|
|
21612
22607
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
21613
|
-
|
|
22608
|
+
let cliType = typeof args?.cliType === "string" ? args.cliType.trim() : "";
|
|
21614
22609
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
21615
22610
|
try {
|
|
21616
22611
|
const { buildCoordinatorSystemPrompt: buildCoordinatorSystemPrompt2 } = await Promise.resolve().then(() => (init_coordinator_prompt(), coordinator_prompt_exports));
|
|
@@ -21638,9 +22633,29 @@ var DaemonCommandRouter = class {
|
|
|
21638
22633
|
}
|
|
21639
22634
|
const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
|
|
21640
22635
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
22636
|
+
if (!cliType) {
|
|
22637
|
+
const resolved = await resolveProviderTypeFromPriority({
|
|
22638
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || "coordinator"),
|
|
22639
|
+
providerPriority: readProviderPriorityFromPolicy(coordinatorNode.policy),
|
|
22640
|
+
providerLoader: this.deps.providerLoader,
|
|
22641
|
+
onStatusChange: this.deps.onStatusChange
|
|
22642
|
+
});
|
|
22643
|
+
if (!resolved.providerType) {
|
|
22644
|
+
return {
|
|
22645
|
+
success: false,
|
|
22646
|
+
code: "mesh_coordinator_provider_priority_unusable",
|
|
22647
|
+
error: resolved.error || "No usable provider found from node providerPriority",
|
|
22648
|
+
meshId,
|
|
22649
|
+
cliType,
|
|
22650
|
+
workspace
|
|
22651
|
+
};
|
|
22652
|
+
}
|
|
22653
|
+
cliType = resolved.providerType;
|
|
22654
|
+
}
|
|
21641
22655
|
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
21642
22656
|
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
21643
22657
|
provider: providerMeta,
|
|
22658
|
+
cliType,
|
|
21644
22659
|
meshId,
|
|
21645
22660
|
workspace
|
|
21646
22661
|
});
|
|
@@ -21665,7 +22680,8 @@ var DaemonCommandRouter = class {
|
|
|
21665
22680
|
meshCoordinatorSetup: coordinatorSetup
|
|
21666
22681
|
};
|
|
21667
22682
|
}
|
|
21668
|
-
|
|
22683
|
+
const configFormat = coordinatorSetup.configFormat;
|
|
22684
|
+
if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
|
|
21669
22685
|
return {
|
|
21670
22686
|
success: false,
|
|
21671
22687
|
code: "mesh_coordinator_unsupported",
|
|
@@ -21675,17 +22691,34 @@ var DaemonCommandRouter = class {
|
|
|
21675
22691
|
workspace
|
|
21676
22692
|
};
|
|
21677
22693
|
}
|
|
21678
|
-
|
|
21679
|
-
|
|
21680
|
-
|
|
21681
|
-
|
|
21682
|
-
|
|
21683
|
-
|
|
21684
|
-
|
|
21685
|
-
|
|
21686
|
-
|
|
21687
|
-
|
|
22694
|
+
let systemPrompt = "";
|
|
22695
|
+
try {
|
|
22696
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
|
|
22697
|
+
} catch (error) {
|
|
22698
|
+
const message = error?.message || String(error);
|
|
22699
|
+
LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
22700
|
+
return {
|
|
22701
|
+
success: false,
|
|
22702
|
+
code: "mesh_coordinator_prompt_failed",
|
|
22703
|
+
error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
|
|
22704
|
+
meshId,
|
|
22705
|
+
cliType,
|
|
22706
|
+
workspace
|
|
22707
|
+
};
|
|
21688
22708
|
}
|
|
22709
|
+
const { existsSync: existsSync23, readFileSync: readFileSync15, writeFileSync: writeFileSync13, copyFileSync: copyFileSync3, mkdirSync: mkdirSync15 } = await import("fs");
|
|
22710
|
+
const { dirname: dirname9 } = await import("path");
|
|
22711
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
22712
|
+
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
22713
|
+
const returnManualFallback = (message) => ({
|
|
22714
|
+
success: false,
|
|
22715
|
+
code: "mesh_coordinator_manual_mcp_setup_required",
|
|
22716
|
+
error: message,
|
|
22717
|
+
meshId,
|
|
22718
|
+
cliType,
|
|
22719
|
+
workspace,
|
|
22720
|
+
meshCoordinatorSetup: hermesManualFallback
|
|
22721
|
+
});
|
|
21689
22722
|
const mcpServerEntry = {
|
|
21690
22723
|
command: coordinatorSetup.mcpServer.command,
|
|
21691
22724
|
args: coordinatorSetup.mcpServer.args
|
|
@@ -21696,24 +22729,55 @@ var DaemonCommandRouter = class {
|
|
|
21696
22729
|
ADHDEV_MCP_TRANSPORT: "ipc"
|
|
21697
22730
|
};
|
|
21698
22731
|
}
|
|
22732
|
+
try {
|
|
22733
|
+
mkdirSync15(dirname9(mcpConfigPath), { recursive: true });
|
|
22734
|
+
} catch (error) {
|
|
22735
|
+
const message = `Could not prepare MCP config path for automatic setup: ${error?.message || error}`;
|
|
22736
|
+
LOG.error("MeshCoordinator", message);
|
|
22737
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22738
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
22739
|
+
}
|
|
22740
|
+
const hadExistingMcpConfig = existsSync23(mcpConfigPath);
|
|
22741
|
+
let existingMcpConfig = {};
|
|
22742
|
+
if (hadExistingMcpConfig) {
|
|
22743
|
+
try {
|
|
22744
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync15(mcpConfigPath, "utf-8"), configFormat);
|
|
22745
|
+
copyFileSync3(mcpConfigPath, mcpConfigPath + ".backup");
|
|
22746
|
+
} catch (error) {
|
|
22747
|
+
LOG.error("MeshCoordinator", `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
22748
|
+
return {
|
|
22749
|
+
success: false,
|
|
22750
|
+
code: "mesh_coordinator_config_parse_failed",
|
|
22751
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`
|
|
22752
|
+
};
|
|
22753
|
+
}
|
|
22754
|
+
}
|
|
22755
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
22756
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
21699
22757
|
const mcpConfig = {
|
|
21700
22758
|
...existingMcpConfig,
|
|
21701
|
-
|
|
21702
|
-
...
|
|
22759
|
+
[mcpServersKey]: {
|
|
22760
|
+
...existingServers && typeof existingServers === "object" && !Array.isArray(existingServers) ? existingServers : {},
|
|
21703
22761
|
[coordinatorSetup.serverName]: mcpServerEntry
|
|
21704
22762
|
}
|
|
21705
22763
|
};
|
|
21706
|
-
writeFileSync12(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
|
21707
|
-
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21708
|
-
let systemPrompt = "";
|
|
21709
22764
|
try {
|
|
21710
|
-
|
|
21711
|
-
} catch {
|
|
21712
|
-
|
|
22765
|
+
writeFileSync13(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), "utf-8");
|
|
22766
|
+
} catch (error) {
|
|
22767
|
+
const message = `Could not write MCP config for automatic setup: ${error?.message || error}`;
|
|
22768
|
+
LOG.error("MeshCoordinator", message);
|
|
22769
|
+
if (hermesManualFallback) return returnManualFallback(message);
|
|
22770
|
+
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
21713
22771
|
}
|
|
22772
|
+
LOG.info("MeshCoordinator", `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
21714
22773
|
const cliArgs = [];
|
|
22774
|
+
const launchEnv = {};
|
|
21715
22775
|
if (systemPrompt) {
|
|
21716
|
-
|
|
22776
|
+
if (configFormat === "hermes_config_yaml") {
|
|
22777
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
22778
|
+
} else {
|
|
22779
|
+
cliArgs.push("--append-system-prompt", systemPrompt);
|
|
22780
|
+
}
|
|
21717
22781
|
}
|
|
21718
22782
|
if (cliType === "claude-cli") {
|
|
21719
22783
|
cliArgs.push("--mcp-config", coordinatorSetup.configPath);
|
|
@@ -21722,6 +22786,7 @@ var DaemonCommandRouter = class {
|
|
|
21722
22786
|
cliType,
|
|
21723
22787
|
dir: workspace,
|
|
21724
22788
|
cliArgs: cliArgs.length > 0 ? cliArgs : void 0,
|
|
22789
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : void 0,
|
|
21725
22790
|
settings: {
|
|
21726
22791
|
meshCoordinatorFor: meshId
|
|
21727
22792
|
}
|
|
@@ -21901,6 +22966,12 @@ var DaemonStatusReporter = class {
|
|
|
21901
22966
|
if (providerType) {
|
|
21902
22967
|
payload.providerType = providerType;
|
|
21903
22968
|
}
|
|
22969
|
+
if (typeof event.providerSessionId === "string" && event.providerSessionId.trim()) {
|
|
22970
|
+
payload.providerSessionId = event.providerSessionId.trim();
|
|
22971
|
+
}
|
|
22972
|
+
if (typeof event.workspaceName === "string" && event.workspaceName.trim()) {
|
|
22973
|
+
payload.workspaceName = event.workspaceName.trim();
|
|
22974
|
+
}
|
|
21904
22975
|
if (typeof event.duration === "number" && Number.isFinite(event.duration)) {
|
|
21905
22976
|
payload.duration = event.duration;
|
|
21906
22977
|
}
|
|
@@ -23148,7 +24219,10 @@ var ProviderInstanceManager = class {
|
|
|
23148
24219
|
this.instances.get(id).dispose();
|
|
23149
24220
|
}
|
|
23150
24221
|
this.instances.set(id, instance);
|
|
23151
|
-
await instance.init(
|
|
24222
|
+
await instance.init({
|
|
24223
|
+
...context,
|
|
24224
|
+
emitProviderEvent: (event) => this.emitProviderEvent(instance.type, id, event)
|
|
24225
|
+
});
|
|
23152
24226
|
}
|
|
23153
24227
|
/**
|
|
23154
24228
|
* Instance remove
|
|
@@ -23310,6 +24384,17 @@ var ProviderInstanceManager = class {
|
|
|
23310
24384
|
onEvent(listener) {
|
|
23311
24385
|
this.eventListeners.push(listener);
|
|
23312
24386
|
}
|
|
24387
|
+
emitProviderEvent(providerType, instanceId, event) {
|
|
24388
|
+
const payload = {
|
|
24389
|
+
...event,
|
|
24390
|
+
providerType,
|
|
24391
|
+
instanceId: typeof event.instanceId === "string" && event.instanceId.trim() ? event.instanceId : instanceId,
|
|
24392
|
+
targetSessionId: typeof event.targetSessionId === "string" && event.targetSessionId.trim() ? event.targetSessionId : instanceId
|
|
24393
|
+
};
|
|
24394
|
+
for (const listener of this.eventListeners) {
|
|
24395
|
+
listener(payload);
|
|
24396
|
+
}
|
|
24397
|
+
}
|
|
23313
24398
|
emitPendingEvents(providerType, state, extra = {}) {
|
|
23314
24399
|
for (const event of state.pendingEvents) {
|
|
23315
24400
|
for (const listener of this.eventListeners) {
|
|
@@ -23382,11 +24467,11 @@ var ProviderInstanceManager = class {
|
|
|
23382
24467
|
|
|
23383
24468
|
// src/providers/version-archive.ts
|
|
23384
24469
|
var fs11 = __toESM(require("fs"));
|
|
23385
|
-
var
|
|
23386
|
-
var
|
|
24470
|
+
var path22 = __toESM(require("path"));
|
|
24471
|
+
var os20 = __toESM(require("os"));
|
|
23387
24472
|
var import_child_process10 = require("child_process");
|
|
23388
24473
|
var import_os3 = require("os");
|
|
23389
|
-
var ARCHIVE_PATH =
|
|
24474
|
+
var ARCHIVE_PATH = path22.join(os20.homedir(), ".adhdev", "version-history.json");
|
|
23390
24475
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
23391
24476
|
var VersionArchive = class {
|
|
23392
24477
|
history = {};
|
|
@@ -23433,7 +24518,7 @@ var VersionArchive = class {
|
|
|
23433
24518
|
}
|
|
23434
24519
|
save() {
|
|
23435
24520
|
try {
|
|
23436
|
-
fs11.mkdirSync(
|
|
24521
|
+
fs11.mkdirSync(path22.dirname(ARCHIVE_PATH), { recursive: true });
|
|
23437
24522
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
23438
24523
|
} catch {
|
|
23439
24524
|
}
|
|
@@ -23489,8 +24574,8 @@ function getVersion(binary, versionCommand) {
|
|
|
23489
24574
|
function checkPathExists2(paths) {
|
|
23490
24575
|
for (const p of paths) {
|
|
23491
24576
|
if (p.includes("*")) {
|
|
23492
|
-
const home =
|
|
23493
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
24577
|
+
const home = os20.homedir();
|
|
24578
|
+
const resolved = p.replace(/\*/g, home.split(path22.sep).pop() || "");
|
|
23494
24579
|
if (fs11.existsSync(resolved)) return resolved;
|
|
23495
24580
|
} else {
|
|
23496
24581
|
if (fs11.existsSync(p)) return p;
|
|
@@ -23500,7 +24585,7 @@ function checkPathExists2(paths) {
|
|
|
23500
24585
|
}
|
|
23501
24586
|
function getMacAppVersion(appPath) {
|
|
23502
24587
|
if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
23503
|
-
const plistPath =
|
|
24588
|
+
const plistPath = path22.join(appPath, "Contents", "Info.plist");
|
|
23504
24589
|
if (!fs11.existsSync(plistPath)) return null;
|
|
23505
24590
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
23506
24591
|
return raw || null;
|
|
@@ -23526,7 +24611,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23526
24611
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
23527
24612
|
let resolvedBin = cliBin;
|
|
23528
24613
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
23529
|
-
const bundled =
|
|
24614
|
+
const bundled = path22.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
23530
24615
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
23531
24616
|
}
|
|
23532
24617
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -23567,7 +24652,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
23567
24652
|
// src/daemon/dev-server.ts
|
|
23568
24653
|
var http2 = __toESM(require("http"));
|
|
23569
24654
|
var fs15 = __toESM(require("fs"));
|
|
23570
|
-
var
|
|
24655
|
+
var path26 = __toESM(require("path"));
|
|
23571
24656
|
init_config();
|
|
23572
24657
|
|
|
23573
24658
|
// src/daemon/scaffold-template.ts
|
|
@@ -23918,7 +25003,7 @@ init_logger();
|
|
|
23918
25003
|
|
|
23919
25004
|
// src/daemon/dev-cdp-handlers.ts
|
|
23920
25005
|
var fs12 = __toESM(require("fs"));
|
|
23921
|
-
var
|
|
25006
|
+
var path23 = __toESM(require("path"));
|
|
23922
25007
|
init_logger();
|
|
23923
25008
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
23924
25009
|
const body = await ctx.readBody(req);
|
|
@@ -24097,17 +25182,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
24097
25182
|
return;
|
|
24098
25183
|
}
|
|
24099
25184
|
let scriptsPath = "";
|
|
24100
|
-
const directScripts =
|
|
25185
|
+
const directScripts = path23.join(dir, "scripts.js");
|
|
24101
25186
|
if (fs12.existsSync(directScripts)) {
|
|
24102
25187
|
scriptsPath = directScripts;
|
|
24103
25188
|
} else {
|
|
24104
|
-
const scriptsDir =
|
|
25189
|
+
const scriptsDir = path23.join(dir, "scripts");
|
|
24105
25190
|
if (fs12.existsSync(scriptsDir)) {
|
|
24106
25191
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
24107
|
-
return fs12.statSync(
|
|
25192
|
+
return fs12.statSync(path23.join(scriptsDir, d)).isDirectory();
|
|
24108
25193
|
}).sort().reverse();
|
|
24109
25194
|
for (const ver of versions) {
|
|
24110
|
-
const p =
|
|
25195
|
+
const p = path23.join(scriptsDir, ver, "scripts.js");
|
|
24111
25196
|
if (fs12.existsSync(p)) {
|
|
24112
25197
|
scriptsPath = p;
|
|
24113
25198
|
break;
|
|
@@ -24936,7 +26021,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
24936
26021
|
|
|
24937
26022
|
// src/daemon/dev-cli-debug.ts
|
|
24938
26023
|
var fs13 = __toESM(require("fs"));
|
|
24939
|
-
var
|
|
26024
|
+
var path24 = __toESM(require("path"));
|
|
24940
26025
|
function slugifyFixtureName(value) {
|
|
24941
26026
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24942
26027
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -24946,11 +26031,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
24946
26031
|
if (!providerDir) {
|
|
24947
26032
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
24948
26033
|
}
|
|
24949
|
-
return
|
|
26034
|
+
return path24.join(providerDir, "fixtures");
|
|
24950
26035
|
}
|
|
24951
26036
|
function readCliFixture(ctx, type, name) {
|
|
24952
26037
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
24953
|
-
const filePath =
|
|
26038
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
24954
26039
|
if (!fs13.existsSync(filePath)) {
|
|
24955
26040
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
24956
26041
|
}
|
|
@@ -25118,7 +26203,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
|
|
|
25118
26203
|
if (!adapter) return null;
|
|
25119
26204
|
return { target, instance, adapter };
|
|
25120
26205
|
}
|
|
25121
|
-
function
|
|
26206
|
+
function sleep2(ms) {
|
|
25122
26207
|
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
25123
26208
|
}
|
|
25124
26209
|
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
@@ -25135,7 +26220,7 @@ async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
|
25135
26220
|
return bundle;
|
|
25136
26221
|
}
|
|
25137
26222
|
}
|
|
25138
|
-
await
|
|
26223
|
+
await sleep2(100);
|
|
25139
26224
|
}
|
|
25140
26225
|
return getCliTargetBundle(ctx, type, instanceId);
|
|
25141
26226
|
}
|
|
@@ -25191,7 +26276,7 @@ async function runCliExerciseInternal(ctx, body) {
|
|
|
25191
26276
|
const message = String(lastLaunchError.message || "");
|
|
25192
26277
|
const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
|
|
25193
26278
|
if (!retryable || attempt === 2) break;
|
|
25194
|
-
await
|
|
26279
|
+
await sleep2(1e3);
|
|
25195
26280
|
}
|
|
25196
26281
|
}
|
|
25197
26282
|
if (!launched) {
|
|
@@ -25254,16 +26339,16 @@ async function runCliExerciseInternal(ctx, body) {
|
|
|
25254
26339
|
const modal = debug?.activeModal || trace?.activeModal || null;
|
|
25255
26340
|
noteStatus(status);
|
|
25256
26341
|
if (resolveActiveModalIfNeeded(status, modal)) {
|
|
25257
|
-
await
|
|
26342
|
+
await sleep2(150);
|
|
25258
26343
|
continue;
|
|
25259
26344
|
}
|
|
25260
26345
|
const startupParseGate = !!debug?.startupParseGate;
|
|
25261
26346
|
if (status === "idle" && !startupParseGate) break;
|
|
25262
|
-
await
|
|
26347
|
+
await sleep2(150);
|
|
25263
26348
|
}
|
|
25264
26349
|
ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
|
|
25265
26350
|
while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
|
|
25266
|
-
await
|
|
26351
|
+
await sleep2(150);
|
|
25267
26352
|
bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
|
|
25268
26353
|
if (!bundle) {
|
|
25269
26354
|
throw new Error("CLI instance disappeared during exercise");
|
|
@@ -25717,7 +26802,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
25717
26802
|
},
|
|
25718
26803
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
25719
26804
|
};
|
|
25720
|
-
const filePath =
|
|
26805
|
+
const filePath = path24.join(fixtureDir, `${name}.json`);
|
|
25721
26806
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
25722
26807
|
ctx.json(res, 200, {
|
|
25723
26808
|
saved: true,
|
|
@@ -25741,7 +26826,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
25741
26826
|
return;
|
|
25742
26827
|
}
|
|
25743
26828
|
const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
25744
|
-
const fullPath =
|
|
26829
|
+
const fullPath = path24.join(fixtureDir, file);
|
|
25745
26830
|
try {
|
|
25746
26831
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
25747
26832
|
return {
|
|
@@ -25877,8 +26962,8 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
25877
26962
|
|
|
25878
26963
|
// src/daemon/dev-auto-implement.ts
|
|
25879
26964
|
var fs14 = __toESM(require("fs"));
|
|
25880
|
-
var
|
|
25881
|
-
var
|
|
26965
|
+
var path25 = __toESM(require("path"));
|
|
26966
|
+
var os21 = __toESM(require("os"));
|
|
25882
26967
|
function getAutoImplPid(ctx) {
|
|
25883
26968
|
const pid = ctx.autoImplProcess?.pid;
|
|
25884
26969
|
return typeof pid === "number" && pid > 0 ? pid : null;
|
|
@@ -25927,22 +27012,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
25927
27012
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
25928
27013
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
25929
27014
|
try {
|
|
25930
|
-
return fs14.statSync(
|
|
27015
|
+
return fs14.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
25931
27016
|
} catch {
|
|
25932
27017
|
return false;
|
|
25933
27018
|
}
|
|
25934
27019
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
25935
27020
|
if (versions.length === 0) return null;
|
|
25936
|
-
return
|
|
27021
|
+
return path25.join(scriptsDir, versions[0]);
|
|
25937
27022
|
}
|
|
25938
27023
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
25939
|
-
const canonicalUserDir =
|
|
25940
|
-
const desiredDir = requestedDir ?
|
|
25941
|
-
const upstreamRoot =
|
|
25942
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
27024
|
+
const canonicalUserDir = path25.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
27025
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
27026
|
+
const upstreamRoot = path25.resolve(ctx.providerLoader.getUpstreamDir());
|
|
27027
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
25943
27028
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
25944
27029
|
}
|
|
25945
|
-
if (
|
|
27030
|
+
if (path25.basename(desiredDir) !== type) {
|
|
25946
27031
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
25947
27032
|
}
|
|
25948
27033
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -25950,11 +27035,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
25950
27035
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
25951
27036
|
}
|
|
25952
27037
|
if (!fs14.existsSync(desiredDir)) {
|
|
25953
|
-
fs14.mkdirSync(
|
|
27038
|
+
fs14.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
25954
27039
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
25955
27040
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
25956
27041
|
}
|
|
25957
|
-
const providerJson =
|
|
27042
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
25958
27043
|
if (!fs14.existsSync(providerJson)) {
|
|
25959
27044
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
25960
27045
|
}
|
|
@@ -25965,13 +27050,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
25965
27050
|
const refDir = ctx.findProviderDir(referenceType);
|
|
25966
27051
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
25967
27052
|
const referenceScripts = {};
|
|
25968
|
-
const scriptsDir =
|
|
27053
|
+
const scriptsDir = path25.join(refDir, "scripts");
|
|
25969
27054
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
25970
27055
|
if (!latestDir) return referenceScripts;
|
|
25971
27056
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
25972
27057
|
if (!file.endsWith(".js")) continue;
|
|
25973
27058
|
try {
|
|
25974
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
27059
|
+
referenceScripts[file] = fs14.readFileSync(path25.join(latestDir, file), "utf-8");
|
|
25975
27060
|
} catch {
|
|
25976
27061
|
}
|
|
25977
27062
|
}
|
|
@@ -26079,9 +27164,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26079
27164
|
});
|
|
26080
27165
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
26081
27166
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
26082
|
-
const tmpDir =
|
|
27167
|
+
const tmpDir = path25.join(os21.tmpdir(), "adhdev-autoimpl");
|
|
26083
27168
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
26084
|
-
const promptFile =
|
|
27169
|
+
const promptFile = path25.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
26085
27170
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
26086
27171
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
26087
27172
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -26234,7 +27319,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26234
27319
|
const interactiveFlags = ["--yolo", "--interactive", "-i"];
|
|
26235
27320
|
const baseArgs = [...spawn4.args || []].filter((a) => !interactiveFlags.includes(a));
|
|
26236
27321
|
let shellCmd;
|
|
26237
|
-
const isWin =
|
|
27322
|
+
const isWin = os21.platform() === "win32";
|
|
26238
27323
|
const escapeArg = (a) => isWin ? `"${a.replace(/"/g, '""')}"` : `'${a.replace(/'/g, "'\\''")}'`;
|
|
26239
27324
|
const promptMode = autoImpl?.promptMode ?? "stdin";
|
|
26240
27325
|
const extraArgs = autoImpl?.extraArgs ?? [];
|
|
@@ -26273,7 +27358,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
26273
27358
|
try {
|
|
26274
27359
|
const pty = require("node-pty");
|
|
26275
27360
|
ctx.log(`Auto-implement spawn (PTY): ${shellCmd}`);
|
|
26276
|
-
const isWin2 =
|
|
27361
|
+
const isWin2 = os21.platform() === "win32";
|
|
26277
27362
|
child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
|
|
26278
27363
|
name: "xterm-256color",
|
|
26279
27364
|
cols: 120,
|
|
@@ -26513,7 +27598,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26513
27598
|
setMode: "set_mode.js"
|
|
26514
27599
|
};
|
|
26515
27600
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26516
|
-
const scriptsDir =
|
|
27601
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26517
27602
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26518
27603
|
if (latestScriptsDir) {
|
|
26519
27604
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26524,7 +27609,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26524
27609
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
26525
27610
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26526
27611
|
try {
|
|
26527
|
-
const content = fs14.readFileSync(
|
|
27612
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26528
27613
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26529
27614
|
lines.push("```javascript");
|
|
26530
27615
|
lines.push(content);
|
|
@@ -26541,7 +27626,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26541
27626
|
lines.push("");
|
|
26542
27627
|
for (const file of refFiles) {
|
|
26543
27628
|
try {
|
|
26544
|
-
const content = fs14.readFileSync(
|
|
27629
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26545
27630
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26546
27631
|
lines.push("```javascript");
|
|
26547
27632
|
lines.push(content);
|
|
@@ -26582,10 +27667,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
26582
27667
|
lines.push("");
|
|
26583
27668
|
}
|
|
26584
27669
|
}
|
|
26585
|
-
const docsDir =
|
|
27670
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26586
27671
|
const loadGuide = (name) => {
|
|
26587
27672
|
try {
|
|
26588
|
-
const p =
|
|
27673
|
+
const p = path25.join(docsDir, name);
|
|
26589
27674
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26590
27675
|
} catch {
|
|
26591
27676
|
}
|
|
@@ -26822,7 +27907,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26822
27907
|
parseApproval: "parse_approval.js"
|
|
26823
27908
|
};
|
|
26824
27909
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26825
|
-
const scriptsDir =
|
|
27910
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26826
27911
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
26827
27912
|
if (latestScriptsDir) {
|
|
26828
27913
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26834,7 +27919,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26834
27919
|
if (!file.endsWith(".js")) continue;
|
|
26835
27920
|
if (!targetFileNames.has(file)) continue;
|
|
26836
27921
|
try {
|
|
26837
|
-
const content = fs14.readFileSync(
|
|
27922
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26838
27923
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26839
27924
|
lines.push("```javascript");
|
|
26840
27925
|
lines.push(content);
|
|
@@ -26850,7 +27935,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26850
27935
|
lines.push("");
|
|
26851
27936
|
for (const file of refFiles) {
|
|
26852
27937
|
try {
|
|
26853
|
-
const content = fs14.readFileSync(
|
|
27938
|
+
const content = fs14.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26854
27939
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26855
27940
|
lines.push("```javascript");
|
|
26856
27941
|
lines.push(content);
|
|
@@ -26883,10 +27968,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
26883
27968
|
lines.push("");
|
|
26884
27969
|
}
|
|
26885
27970
|
}
|
|
26886
|
-
const docsDir =
|
|
27971
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26887
27972
|
const loadGuide = (name) => {
|
|
26888
27973
|
try {
|
|
26889
|
-
const p =
|
|
27974
|
+
const p = path25.join(docsDir, name);
|
|
26890
27975
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
26891
27976
|
} catch {
|
|
26892
27977
|
}
|
|
@@ -27333,8 +28418,8 @@ var DevServer = class _DevServer {
|
|
|
27333
28418
|
}
|
|
27334
28419
|
getEndpointList() {
|
|
27335
28420
|
return this.routes.map((r) => {
|
|
27336
|
-
const
|
|
27337
|
-
return `${r.method.padEnd(5)} ${
|
|
28421
|
+
const path27 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
28422
|
+
return `${r.method.padEnd(5)} ${path27}`;
|
|
27338
28423
|
});
|
|
27339
28424
|
}
|
|
27340
28425
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -27622,12 +28707,12 @@ var DevServer = class _DevServer {
|
|
|
27622
28707
|
// ─── DevConsole SPA ───
|
|
27623
28708
|
getConsoleDistDir() {
|
|
27624
28709
|
const candidates = [
|
|
27625
|
-
|
|
27626
|
-
|
|
27627
|
-
|
|
28710
|
+
path26.resolve(__dirname, "../../web-devconsole/dist"),
|
|
28711
|
+
path26.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
28712
|
+
path26.join(process.cwd(), "packages/web-devconsole/dist")
|
|
27628
28713
|
];
|
|
27629
28714
|
for (const dir of candidates) {
|
|
27630
|
-
if (fs15.existsSync(
|
|
28715
|
+
if (fs15.existsSync(path26.join(dir, "index.html"))) return dir;
|
|
27631
28716
|
}
|
|
27632
28717
|
return null;
|
|
27633
28718
|
}
|
|
@@ -27637,7 +28722,7 @@ var DevServer = class _DevServer {
|
|
|
27637
28722
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
27638
28723
|
return;
|
|
27639
28724
|
}
|
|
27640
|
-
const htmlPath =
|
|
28725
|
+
const htmlPath = path26.join(distDir, "index.html");
|
|
27641
28726
|
try {
|
|
27642
28727
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
27643
28728
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -27662,15 +28747,15 @@ var DevServer = class _DevServer {
|
|
|
27662
28747
|
this.json(res, 404, { error: "Not found" });
|
|
27663
28748
|
return;
|
|
27664
28749
|
}
|
|
27665
|
-
const safePath =
|
|
27666
|
-
const filePath =
|
|
28750
|
+
const safePath = path26.normalize(pathname).replace(/^\.\.\//, "");
|
|
28751
|
+
const filePath = path26.join(distDir, safePath);
|
|
27667
28752
|
if (!filePath.startsWith(distDir)) {
|
|
27668
28753
|
this.json(res, 403, { error: "Forbidden" });
|
|
27669
28754
|
return;
|
|
27670
28755
|
}
|
|
27671
28756
|
try {
|
|
27672
28757
|
const content = fs15.readFileSync(filePath);
|
|
27673
|
-
const ext =
|
|
28758
|
+
const ext = path26.extname(filePath);
|
|
27674
28759
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
27675
28760
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
27676
28761
|
res.end(content);
|
|
@@ -27783,9 +28868,9 @@ var DevServer = class _DevServer {
|
|
|
27783
28868
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27784
28869
|
if (entry.isDirectory()) {
|
|
27785
28870
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
27786
|
-
scan(
|
|
28871
|
+
scan(path26.join(d, entry.name), rel);
|
|
27787
28872
|
} else {
|
|
27788
|
-
const stat2 = fs15.statSync(
|
|
28873
|
+
const stat2 = fs15.statSync(path26.join(d, entry.name));
|
|
27789
28874
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
27790
28875
|
}
|
|
27791
28876
|
}
|
|
@@ -27808,7 +28893,7 @@ var DevServer = class _DevServer {
|
|
|
27808
28893
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27809
28894
|
return;
|
|
27810
28895
|
}
|
|
27811
|
-
const fullPath =
|
|
28896
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27812
28897
|
if (!fullPath.startsWith(dir)) {
|
|
27813
28898
|
this.json(res, 403, { error: "Forbidden" });
|
|
27814
28899
|
return;
|
|
@@ -27833,14 +28918,14 @@ var DevServer = class _DevServer {
|
|
|
27833
28918
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
27834
28919
|
return;
|
|
27835
28920
|
}
|
|
27836
|
-
const fullPath =
|
|
28921
|
+
const fullPath = path26.resolve(dir, path26.normalize(filePath));
|
|
27837
28922
|
if (!fullPath.startsWith(dir)) {
|
|
27838
28923
|
this.json(res, 403, { error: "Forbidden" });
|
|
27839
28924
|
return;
|
|
27840
28925
|
}
|
|
27841
28926
|
try {
|
|
27842
28927
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
27843
|
-
fs15.mkdirSync(
|
|
28928
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
27844
28929
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
27845
28930
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
27846
28931
|
this.providerLoader.reload();
|
|
@@ -27857,7 +28942,7 @@ var DevServer = class _DevServer {
|
|
|
27857
28942
|
return;
|
|
27858
28943
|
}
|
|
27859
28944
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
27860
|
-
const p =
|
|
28945
|
+
const p = path26.join(dir, name);
|
|
27861
28946
|
if (fs15.existsSync(p)) {
|
|
27862
28947
|
const source = fs15.readFileSync(p, "utf-8");
|
|
27863
28948
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -27878,8 +28963,8 @@ var DevServer = class _DevServer {
|
|
|
27878
28963
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
27879
28964
|
return;
|
|
27880
28965
|
}
|
|
27881
|
-
const target = fs15.existsSync(
|
|
27882
|
-
const targetPath =
|
|
28966
|
+
const target = fs15.existsSync(path26.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
28967
|
+
const targetPath = path26.join(dir, target);
|
|
27883
28968
|
try {
|
|
27884
28969
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
27885
28970
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -28026,7 +29111,7 @@ var DevServer = class _DevServer {
|
|
|
28026
29111
|
}
|
|
28027
29112
|
let targetDir;
|
|
28028
29113
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
28029
|
-
const jsonPath =
|
|
29114
|
+
const jsonPath = path26.join(targetDir, "provider.json");
|
|
28030
29115
|
if (fs15.existsSync(jsonPath)) {
|
|
28031
29116
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
28032
29117
|
return;
|
|
@@ -28038,8 +29123,8 @@ var DevServer = class _DevServer {
|
|
|
28038
29123
|
const createdFiles = ["provider.json"];
|
|
28039
29124
|
if (result.files) {
|
|
28040
29125
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
28041
|
-
const fullPath =
|
|
28042
|
-
fs15.mkdirSync(
|
|
29126
|
+
const fullPath = path26.join(targetDir, relPath);
|
|
29127
|
+
fs15.mkdirSync(path26.dirname(fullPath), { recursive: true });
|
|
28043
29128
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
28044
29129
|
createdFiles.push(relPath);
|
|
28045
29130
|
}
|
|
@@ -28092,22 +29177,22 @@ var DevServer = class _DevServer {
|
|
|
28092
29177
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
28093
29178
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
28094
29179
|
try {
|
|
28095
|
-
return fs15.statSync(
|
|
29180
|
+
return fs15.statSync(path26.join(scriptsDir, d)).isDirectory();
|
|
28096
29181
|
} catch {
|
|
28097
29182
|
return false;
|
|
28098
29183
|
}
|
|
28099
29184
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
28100
29185
|
if (versions.length === 0) return null;
|
|
28101
|
-
return
|
|
29186
|
+
return path26.join(scriptsDir, versions[0]);
|
|
28102
29187
|
}
|
|
28103
29188
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
28104
|
-
const canonicalUserDir =
|
|
28105
|
-
const desiredDir = requestedDir ?
|
|
28106
|
-
const upstreamRoot =
|
|
28107
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
29189
|
+
const canonicalUserDir = path26.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
29190
|
+
const desiredDir = requestedDir ? path26.resolve(requestedDir) : canonicalUserDir;
|
|
29191
|
+
const upstreamRoot = path26.resolve(this.providerLoader.getUpstreamDir());
|
|
29192
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path26.sep}`)) {
|
|
28108
29193
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
28109
29194
|
}
|
|
28110
|
-
if (
|
|
29195
|
+
if (path26.basename(desiredDir) !== type) {
|
|
28111
29196
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
28112
29197
|
}
|
|
28113
29198
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -28115,11 +29200,11 @@ var DevServer = class _DevServer {
|
|
|
28115
29200
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
28116
29201
|
}
|
|
28117
29202
|
if (!fs15.existsSync(desiredDir)) {
|
|
28118
|
-
fs15.mkdirSync(
|
|
29203
|
+
fs15.mkdirSync(path26.dirname(desiredDir), { recursive: true });
|
|
28119
29204
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
28120
29205
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
28121
29206
|
}
|
|
28122
|
-
const providerJson =
|
|
29207
|
+
const providerJson = path26.join(desiredDir, "provider.json");
|
|
28123
29208
|
if (!fs15.existsSync(providerJson)) {
|
|
28124
29209
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
28125
29210
|
}
|
|
@@ -28155,7 +29240,7 @@ var DevServer = class _DevServer {
|
|
|
28155
29240
|
setMode: "set_mode.js"
|
|
28156
29241
|
};
|
|
28157
29242
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28158
|
-
const scriptsDir =
|
|
29243
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28159
29244
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28160
29245
|
if (latestScriptsDir) {
|
|
28161
29246
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28166,7 +29251,7 @@ var DevServer = class _DevServer {
|
|
|
28166
29251
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
28167
29252
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
28168
29253
|
try {
|
|
28169
|
-
const content = fs15.readFileSync(
|
|
29254
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28170
29255
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28171
29256
|
lines.push("```javascript");
|
|
28172
29257
|
lines.push(content);
|
|
@@ -28183,7 +29268,7 @@ var DevServer = class _DevServer {
|
|
|
28183
29268
|
lines.push("");
|
|
28184
29269
|
for (const file of refFiles) {
|
|
28185
29270
|
try {
|
|
28186
|
-
const content = fs15.readFileSync(
|
|
29271
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28187
29272
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28188
29273
|
lines.push("```javascript");
|
|
28189
29274
|
lines.push(content);
|
|
@@ -28224,10 +29309,10 @@ var DevServer = class _DevServer {
|
|
|
28224
29309
|
lines.push("");
|
|
28225
29310
|
}
|
|
28226
29311
|
}
|
|
28227
|
-
const docsDir =
|
|
29312
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28228
29313
|
const loadGuide = (name) => {
|
|
28229
29314
|
try {
|
|
28230
|
-
const p =
|
|
29315
|
+
const p = path26.join(docsDir, name);
|
|
28231
29316
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28232
29317
|
} catch {
|
|
28233
29318
|
}
|
|
@@ -28401,7 +29486,7 @@ var DevServer = class _DevServer {
|
|
|
28401
29486
|
parseApproval: "parse_approval.js"
|
|
28402
29487
|
};
|
|
28403
29488
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
28404
|
-
const scriptsDir =
|
|
29489
|
+
const scriptsDir = path26.join(providerDir, "scripts");
|
|
28405
29490
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
28406
29491
|
if (latestScriptsDir) {
|
|
28407
29492
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -28413,7 +29498,7 @@ var DevServer = class _DevServer {
|
|
|
28413
29498
|
if (!file.endsWith(".js")) continue;
|
|
28414
29499
|
if (!targetFileNames.has(file)) continue;
|
|
28415
29500
|
try {
|
|
28416
|
-
const content = fs15.readFileSync(
|
|
29501
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28417
29502
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
28418
29503
|
lines.push("```javascript");
|
|
28419
29504
|
lines.push(content);
|
|
@@ -28429,7 +29514,7 @@ var DevServer = class _DevServer {
|
|
|
28429
29514
|
lines.push("");
|
|
28430
29515
|
for (const file of refFiles) {
|
|
28431
29516
|
try {
|
|
28432
|
-
const content = fs15.readFileSync(
|
|
29517
|
+
const content = fs15.readFileSync(path26.join(latestScriptsDir, file), "utf-8");
|
|
28433
29518
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
28434
29519
|
lines.push("```javascript");
|
|
28435
29520
|
lines.push(content);
|
|
@@ -28462,10 +29547,10 @@ var DevServer = class _DevServer {
|
|
|
28462
29547
|
lines.push("");
|
|
28463
29548
|
}
|
|
28464
29549
|
}
|
|
28465
|
-
const docsDir =
|
|
29550
|
+
const docsDir = path26.join(providerDir, "../../docs");
|
|
28466
29551
|
const loadGuide = (name) => {
|
|
28467
29552
|
try {
|
|
28468
|
-
const p =
|
|
29553
|
+
const p = path26.join(docsDir, name);
|
|
28469
29554
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
28470
29555
|
} catch {
|
|
28471
29556
|
}
|
|
@@ -29151,29 +30236,58 @@ function resolveSessionHostAppName(options = {}) {
|
|
|
29151
30236
|
var import_session_host_core4 = require("@adhdev/session-host-core");
|
|
29152
30237
|
var STARTUP_TIMEOUT_MS = DEFAULT_SESSION_HOST_READY_TIMEOUT_MS;
|
|
29153
30238
|
var STARTUP_POLL_MS = 200;
|
|
29154
|
-
|
|
30239
|
+
var SessionHostCompatibilityError = class extends Error {
|
|
30240
|
+
constructor(message) {
|
|
30241
|
+
super(message);
|
|
30242
|
+
this.name = "SessionHostCompatibilityError";
|
|
30243
|
+
}
|
|
30244
|
+
};
|
|
30245
|
+
function getMissingRequestTypes(diagnostics, requiredRequestTypes) {
|
|
30246
|
+
const supported = new Set(diagnostics?.supportedRequestTypes || []);
|
|
30247
|
+
return requiredRequestTypes.filter((requestType) => !supported.has(requestType));
|
|
30248
|
+
}
|
|
30249
|
+
async function assertRequiredRequestTypes(client, requiredRequestTypes) {
|
|
30250
|
+
if (requiredRequestTypes.length === 0) return;
|
|
30251
|
+
const response = await client.request({
|
|
30252
|
+
type: "get_host_diagnostics",
|
|
30253
|
+
payload: { includeSessions: false }
|
|
30254
|
+
});
|
|
30255
|
+
const missing = getMissingRequestTypes(response.success ? response.result : void 0, requiredRequestTypes);
|
|
30256
|
+
if (missing.length > 0) {
|
|
30257
|
+
const detail = response.success ? "" : ` (${response.error || "capability probe failed"})`;
|
|
30258
|
+
throw new SessionHostCompatibilityError(
|
|
30259
|
+
`Session host does not support required request types: ${missing.join(", ")}${detail}`
|
|
30260
|
+
);
|
|
30261
|
+
}
|
|
30262
|
+
}
|
|
30263
|
+
async function canConnect(endpoint, requiredRequestTypes = []) {
|
|
29155
30264
|
const client = new import_session_host_core4.SessionHostClient({ endpoint });
|
|
29156
30265
|
try {
|
|
29157
30266
|
await client.connect();
|
|
29158
|
-
await client
|
|
30267
|
+
await assertRequiredRequestTypes(client, requiredRequestTypes);
|
|
29159
30268
|
return true;
|
|
29160
|
-
} catch {
|
|
30269
|
+
} catch (error) {
|
|
30270
|
+
if (error instanceof SessionHostCompatibilityError) throw error;
|
|
29161
30271
|
return false;
|
|
30272
|
+
} finally {
|
|
30273
|
+
await client.close().catch(() => {
|
|
30274
|
+
});
|
|
29162
30275
|
}
|
|
29163
30276
|
}
|
|
29164
|
-
async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
|
|
30277
|
+
async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS, requiredRequestTypes = []) {
|
|
29165
30278
|
const deadline = Date.now() + timeoutMs;
|
|
29166
30279
|
while (Date.now() < deadline) {
|
|
29167
|
-
if (await canConnect(endpoint)) return;
|
|
30280
|
+
if (await canConnect(endpoint, requiredRequestTypes)) return;
|
|
29168
30281
|
await new Promise((resolve16) => setTimeout(resolve16, STARTUP_POLL_MS));
|
|
29169
30282
|
}
|
|
29170
30283
|
throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
|
|
29171
30284
|
}
|
|
29172
30285
|
async function ensureSessionHostReady(options) {
|
|
29173
30286
|
const endpoint = (0, import_session_host_core4.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
|
|
29174
|
-
|
|
30287
|
+
const requiredRequestTypes = options.requiredRequestTypes || [];
|
|
30288
|
+
if (await canConnect(endpoint, requiredRequestTypes)) return endpoint;
|
|
29175
30289
|
options.spawnHost();
|
|
29176
|
-
await waitForReady(endpoint, options.timeoutMs);
|
|
30290
|
+
await waitForReady(endpoint, options.timeoutMs, requiredRequestTypes);
|
|
29177
30291
|
return endpoint;
|
|
29178
30292
|
}
|
|
29179
30293
|
async function listHostedCliRuntimes(endpoint) {
|
|
@@ -29465,48 +30579,6 @@ var SessionRegistry = class {
|
|
|
29465
30579
|
// src/boot/daemon-lifecycle.ts
|
|
29466
30580
|
init_logger();
|
|
29467
30581
|
init_config();
|
|
29468
|
-
|
|
29469
|
-
// src/mesh/mesh-events.ts
|
|
29470
|
-
init_mesh_config();
|
|
29471
|
-
init_logger();
|
|
29472
|
-
function setupMeshEventForwarding(components) {
|
|
29473
|
-
components.instanceManager.onEvent((event) => {
|
|
29474
|
-
if (event.event !== "agent:generating_completed" && event.event !== "agent:waiting_approval") return;
|
|
29475
|
-
const instanceId = event.instanceId;
|
|
29476
|
-
if (!instanceId) return;
|
|
29477
|
-
const sourceInstance = components.instanceManager.getInstance(instanceId);
|
|
29478
|
-
if (!sourceInstance || sourceInstance.category !== "cli") return;
|
|
29479
|
-
const state = sourceInstance.getState();
|
|
29480
|
-
const workspace = state.workspace;
|
|
29481
|
-
if (!workspace) return;
|
|
29482
|
-
const mesh = getMeshByRepo(workspace);
|
|
29483
|
-
if (!mesh) return;
|
|
29484
|
-
const allInstances = components.instanceManager.getByCategory("cli");
|
|
29485
|
-
const coordinatorInstances = allInstances.filter((inst) => {
|
|
29486
|
-
const instState = inst.getState();
|
|
29487
|
-
if (instState.settings?.meshCoordinatorFor !== mesh.id) return false;
|
|
29488
|
-
if (instState.instanceId === instanceId) return false;
|
|
29489
|
-
return true;
|
|
29490
|
-
});
|
|
29491
|
-
if (coordinatorInstances.length === 0) return;
|
|
29492
|
-
const targetNode = mesh.nodes.find((n) => n.workspace === workspace);
|
|
29493
|
-
const nodeLabel = targetNode ? `Node '${targetNode.id}'` : `Agent at ${workspace}`;
|
|
29494
|
-
let messageText = "";
|
|
29495
|
-
if (event.event === "agent:generating_completed") {
|
|
29496
|
-
messageText = `[System] ${nodeLabel} has completed its task and is now idle. You may use mesh_read_chat to review its progress.`;
|
|
29497
|
-
} else if (event.event === "agent:waiting_approval") {
|
|
29498
|
-
messageText = `[System] ${nodeLabel} is waiting for approval to proceed. You may use mesh_read_chat and mesh_approve to handle it.`;
|
|
29499
|
-
}
|
|
29500
|
-
if (!messageText) return;
|
|
29501
|
-
for (const coord of coordinatorInstances) {
|
|
29502
|
-
const coordState = coord.getState();
|
|
29503
|
-
LOG.info("MeshEvents", `Forwarding event from ${workspace} to coordinator ${coordState.instanceId}`);
|
|
29504
|
-
coord.onEvent("send_message", { input: { text: messageText, textFallback: messageText } });
|
|
29505
|
-
}
|
|
29506
|
-
});
|
|
29507
|
-
}
|
|
29508
|
-
|
|
29509
|
-
// src/boot/daemon-lifecycle.ts
|
|
29510
30582
|
async function initDaemonComponents(config) {
|
|
29511
30583
|
installGlobalInterceptor();
|
|
29512
30584
|
const appConfig = loadConfig();
|
|
@@ -29813,12 +30885,14 @@ async function shutdownDaemonComponents(components) {
|
|
|
29813
30885
|
createGitWorkspaceMonitor,
|
|
29814
30886
|
createInteractionId,
|
|
29815
30887
|
createMesh,
|
|
30888
|
+
createWorktree,
|
|
29816
30889
|
deleteMesh,
|
|
29817
30890
|
detectAllVersions,
|
|
29818
30891
|
detectCLIs,
|
|
29819
30892
|
detectIDEs,
|
|
29820
30893
|
ensureSessionHostReady,
|
|
29821
30894
|
execNpmCommandSync,
|
|
30895
|
+
filterUserFacingChatMessages,
|
|
29822
30896
|
findCdpManager,
|
|
29823
30897
|
flattenMessageParts,
|
|
29824
30898
|
forwardAgentStreamsToIdeInstance,
|
|
@@ -29860,11 +30934,13 @@ async function shutdownDaemonComponents(components) {
|
|
|
29860
30934
|
isSessionHostLiveRuntime,
|
|
29861
30935
|
isSessionHostRecoverySnapshot,
|
|
29862
30936
|
isSetupComplete,
|
|
30937
|
+
isUserFacingChatMessage,
|
|
29863
30938
|
killIdeProcess,
|
|
29864
30939
|
launchIDE,
|
|
29865
30940
|
launchWithCdp,
|
|
29866
30941
|
listHostedCliRuntimes,
|
|
29867
30942
|
listMeshes,
|
|
30943
|
+
listWorktrees,
|
|
29868
30944
|
loadConfig,
|
|
29869
30945
|
loadState,
|
|
29870
30946
|
logCommand,
|
|
@@ -29884,6 +30960,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29884
30960
|
normalizeSessionModalFields,
|
|
29885
30961
|
parsePorcelainV2Status,
|
|
29886
30962
|
parseProviderSourceConfigUpdate,
|
|
30963
|
+
parseWorktreeListOutput,
|
|
29887
30964
|
partitionSessionHostDiagnosticsSessions,
|
|
29888
30965
|
partitionSessionHostRecords,
|
|
29889
30966
|
prepareSessionChatTailUpdate,
|
|
@@ -29893,6 +30970,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29893
30970
|
recordDebugTrace,
|
|
29894
30971
|
registerExtensionProviders,
|
|
29895
30972
|
removeNode,
|
|
30973
|
+
removeWorktree,
|
|
29896
30974
|
resetConfig,
|
|
29897
30975
|
resetDebugRuntimeConfig,
|
|
29898
30976
|
resetState,
|
|
@@ -29902,6 +30980,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
29902
30980
|
resolveGitRepository,
|
|
29903
30981
|
resolveSessionHostAppName,
|
|
29904
30982
|
resolveSessionHostAppNameResolution,
|
|
30983
|
+
resolveWorktreePath,
|
|
29905
30984
|
runAsyncBatch,
|
|
29906
30985
|
runGit,
|
|
29907
30986
|
saveConfig,
|