adhdev 0.9.59 → 0.9.61
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/index.js +77 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +75 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/vendor/mcp-server/index.js +382 -69
- package/vendor/mcp-server/index.js.map +1 -1
package/package.json
CHANGED
|
@@ -75,6 +75,15 @@ var CloudTransport = class {
|
|
|
75
75
|
if (!res.ok) throw new Error(`Status failed: ${res.status}`);
|
|
76
76
|
return res.json();
|
|
77
77
|
}
|
|
78
|
+
/** Get all sessions for a daemon (returns CompactSessionEntry[]). */
|
|
79
|
+
async getDaemonStatus(daemonId) {
|
|
80
|
+
const res = await fetch(
|
|
81
|
+
`${this.baseUrl}/api/v1/daemons/${encodeURIComponent(daemonId)}/status`,
|
|
82
|
+
{ headers: this.headers() }
|
|
83
|
+
);
|
|
84
|
+
if (!res.ok) throw new Error(`Daemon status failed: ${res.status}`);
|
|
85
|
+
return res.json();
|
|
86
|
+
}
|
|
78
87
|
async readChat(targetId, opts = {}) {
|
|
79
88
|
const params = new URLSearchParams();
|
|
80
89
|
if (opts.limit) params.set("limit", String(opts.limit));
|
|
@@ -111,6 +120,27 @@ var CloudTransport = class {
|
|
|
111
120
|
if (!res.ok) throw new Error(`Approve failed: ${res.status}`);
|
|
112
121
|
return res.json();
|
|
113
122
|
}
|
|
123
|
+
async gitStatus(daemonId, workspace, includeDiff = true) {
|
|
124
|
+
const params = new URLSearchParams({ workspace, includeDiff: String(includeDiff) });
|
|
125
|
+
const res = await fetch(
|
|
126
|
+
`${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(daemonId)}/git-status?${params}`,
|
|
127
|
+
{ headers: this.headers() }
|
|
128
|
+
);
|
|
129
|
+
if (!res.ok) throw new Error(`Git status failed: ${res.status}`);
|
|
130
|
+
return res.json();
|
|
131
|
+
}
|
|
132
|
+
async launch(daemonId, opts) {
|
|
133
|
+
const res = await fetch(
|
|
134
|
+
`${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(daemonId)}/launch`,
|
|
135
|
+
{
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: this.headers(),
|
|
138
|
+
body: JSON.stringify(opts)
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
if (!res.ok) throw new Error(`Launch failed: ${res.status}`);
|
|
142
|
+
return res.json();
|
|
143
|
+
}
|
|
114
144
|
async ping() {
|
|
115
145
|
try {
|
|
116
146
|
await this.listDaemons();
|
|
@@ -122,50 +152,105 @@ var CloudTransport = class {
|
|
|
122
152
|
};
|
|
123
153
|
|
|
124
154
|
// src/tools/list-sessions.ts
|
|
155
|
+
var FORMAT_PROP = {
|
|
156
|
+
format: {
|
|
157
|
+
type: "string",
|
|
158
|
+
enum: ["text", "json"],
|
|
159
|
+
description: "Output format: 'text' (default, human-readable) or 'json' (structured, for programmatic use)."
|
|
160
|
+
}
|
|
161
|
+
};
|
|
125
162
|
var LIST_SESSIONS_TOOL = {
|
|
126
163
|
name: "list_sessions",
|
|
127
|
-
description: "List all
|
|
164
|
+
description: "List all connected agent sessions. In cloud mode, fetches session state from each daemon (data is sourced from daemon WS status reports, up to 30s stale). Pass daemon_id to scope to a single daemon.",
|
|
128
165
|
inputSchema: {
|
|
129
166
|
type: "object",
|
|
130
|
-
properties: {
|
|
167
|
+
properties: {
|
|
168
|
+
daemon_id: {
|
|
169
|
+
type: "string",
|
|
170
|
+
description: "Daemon ID (cloud mode only). Omit to list sessions across all daemons."
|
|
171
|
+
},
|
|
172
|
+
...FORMAT_PROP
|
|
173
|
+
},
|
|
131
174
|
required: []
|
|
132
175
|
}
|
|
133
176
|
};
|
|
134
|
-
async function listSessions(transport) {
|
|
177
|
+
async function listSessions(transport, args = {}) {
|
|
178
|
+
const asJson = args.format === "json";
|
|
135
179
|
if ("getStatus" in transport) {
|
|
136
180
|
const status = await transport.getStatus();
|
|
137
181
|
const sessions = status?.sessions ?? [];
|
|
182
|
+
if (asJson) {
|
|
183
|
+
return JSON.stringify({
|
|
184
|
+
sessions: sessions.map((s) => ({
|
|
185
|
+
id: s.id,
|
|
186
|
+
type: s.providerType ?? s.type ?? "unknown",
|
|
187
|
+
label: s.label ?? null,
|
|
188
|
+
status: s.status ?? s.agentStatus ?? null,
|
|
189
|
+
workspace: s.workspace ?? null
|
|
190
|
+
}))
|
|
191
|
+
}, null, 2);
|
|
192
|
+
}
|
|
138
193
|
if (sessions.length === 0) return "No active sessions.";
|
|
139
|
-
const
|
|
140
|
-
const parts = [
|
|
141
|
-
`id: ${s.id}`,
|
|
142
|
-
`type: ${s.providerType ?? s.type ?? "unknown"}`
|
|
143
|
-
];
|
|
194
|
+
const lines = sessions.map((s) => {
|
|
195
|
+
const parts = [`id: ${s.id}`, `type: ${s.providerType ?? s.type ?? "unknown"}`];
|
|
144
196
|
if (s.label) parts.push(`label: ${s.label}`);
|
|
145
|
-
if (s.agentStatus) parts.push(`status: ${s.agentStatus}`);
|
|
197
|
+
if (s.status ?? s.agentStatus) parts.push(`status: ${s.status ?? s.agentStatus}`);
|
|
146
198
|
if (s.workspace) parts.push(`workspace: ${s.workspace}`);
|
|
147
199
|
return parts.join(", ");
|
|
148
200
|
});
|
|
149
201
|
return `Sessions (${sessions.length}):
|
|
150
|
-
${
|
|
202
|
+
${lines.join("\n")}`;
|
|
151
203
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
for (const s of sessions) {
|
|
159
|
-
|
|
160
|
-
`daemon: ${d.id}, session: ${s.id}, type: ${s.providerType ?? "unknown"}${s.agentStatus ? `, status: ${s.agentStatus}` : ""}`
|
|
161
|
-
);
|
|
204
|
+
return listSessionsCloud(transport, args.daemon_id, asJson);
|
|
205
|
+
}
|
|
206
|
+
async function listSessionsCloud(transport, daemonId, asJson) {
|
|
207
|
+
const collected = [];
|
|
208
|
+
if (daemonId) {
|
|
209
|
+
const daemonStatus = await transport.getDaemonStatus(daemonId);
|
|
210
|
+
for (const s of daemonStatus?.sessions ?? []) {
|
|
211
|
+
collected.push({ daemonId, session: s });
|
|
162
212
|
}
|
|
163
|
-
|
|
164
|
-
|
|
213
|
+
} else {
|
|
214
|
+
const data = await transport.listDaemons();
|
|
215
|
+
const daemons = data?.daemons ?? [];
|
|
216
|
+
for (let i = 0; i < daemons.length; i += 5) {
|
|
217
|
+
await Promise.allSettled(
|
|
218
|
+
daemons.slice(i, i + 5).map(async (d) => {
|
|
219
|
+
try {
|
|
220
|
+
const daemonStatus = await transport.getDaemonStatus(d.id);
|
|
221
|
+
for (const s of daemonStatus?.sessions ?? []) {
|
|
222
|
+
collected.push({ daemonId: d.id, session: s });
|
|
223
|
+
}
|
|
224
|
+
} catch {
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
);
|
|
165
228
|
}
|
|
166
229
|
}
|
|
167
|
-
|
|
168
|
-
|
|
230
|
+
if (asJson) {
|
|
231
|
+
return JSON.stringify({
|
|
232
|
+
sessions: collected.map(({ daemonId: dId, session: s }) => ({
|
|
233
|
+
daemon_id: dId,
|
|
234
|
+
id: s.id,
|
|
235
|
+
type: s.providerType ?? "unknown",
|
|
236
|
+
status: s.status ?? null,
|
|
237
|
+
workspace: s.workspace ?? null
|
|
238
|
+
}))
|
|
239
|
+
}, null, 2);
|
|
240
|
+
}
|
|
241
|
+
if (collected.length === 0) return "No active sessions.";
|
|
242
|
+
const lines = collected.map(({ daemonId: dId, session: s }) => {
|
|
243
|
+
const parts = [
|
|
244
|
+
`daemon: ${dId}`,
|
|
245
|
+
`session: ${s.id}`,
|
|
246
|
+
`type: ${s.providerType ?? "unknown"}`
|
|
247
|
+
];
|
|
248
|
+
if (s.status) parts.push(`status: ${s.status}`);
|
|
249
|
+
if (s.workspace) parts.push(`workspace: ${s.workspace}`);
|
|
250
|
+
return parts.join(", ");
|
|
251
|
+
});
|
|
252
|
+
return `Sessions (${collected.length}):
|
|
253
|
+
${lines.join("\n")}`;
|
|
169
254
|
}
|
|
170
255
|
|
|
171
256
|
// src/tools/read-chat.ts
|
|
@@ -186,7 +271,8 @@ var READ_CHAT_TOOL = {
|
|
|
186
271
|
daemon_id: {
|
|
187
272
|
type: "string",
|
|
188
273
|
description: "Daemon ID (cloud mode only). Omit for local mode."
|
|
189
|
-
}
|
|
274
|
+
},
|
|
275
|
+
...FORMAT_PROP
|
|
190
276
|
},
|
|
191
277
|
required: []
|
|
192
278
|
}
|
|
@@ -198,16 +284,30 @@ async function readChat(transport, args) {
|
|
|
198
284
|
...args.session_id ? { targetSessionId: args.session_id } : {},
|
|
199
285
|
limit
|
|
200
286
|
});
|
|
201
|
-
return formatChatResult(result2);
|
|
287
|
+
return formatChatResult(result2, args.session_id, args.format);
|
|
202
288
|
}
|
|
203
289
|
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
204
290
|
const targetId = args.session_id ? `${args.daemon_id}:session:${args.session_id}` : args.daemon_id;
|
|
205
291
|
const result = await transport.readChat(targetId, { limit, sessionId: args.session_id });
|
|
206
|
-
return formatChatResult(result);
|
|
292
|
+
return formatChatResult(result, args.session_id, args.format);
|
|
207
293
|
}
|
|
208
|
-
function formatChatResult(result) {
|
|
209
|
-
if (!result?.success && result?.error)
|
|
294
|
+
function formatChatResult(result, sessionId, format) {
|
|
295
|
+
if (!result?.success && result?.error) {
|
|
296
|
+
if (format === "json") return JSON.stringify({ error: result.error, messages: [] }, null, 2);
|
|
297
|
+
return `Error: ${result.error}`;
|
|
298
|
+
}
|
|
210
299
|
const messages = result?.messages ?? result?.data?.messages ?? [];
|
|
300
|
+
if (format === "json") {
|
|
301
|
+
return JSON.stringify({
|
|
302
|
+
session_id: sessionId ?? null,
|
|
303
|
+
messages: messages.slice(-50).map((m) => ({
|
|
304
|
+
role: m.role,
|
|
305
|
+
kind: m.kind ?? null,
|
|
306
|
+
content: typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((p) => typeof p === "string" ? p : p?.text ?? "").join("") : "",
|
|
307
|
+
timestamp: m.timestamp ?? null
|
|
308
|
+
}))
|
|
309
|
+
}, null, 2);
|
|
310
|
+
}
|
|
211
311
|
if (messages.length === 0) return "No messages in chat.";
|
|
212
312
|
const lines = messages.slice(-50).map((m) => {
|
|
213
313
|
const role = m.role === "user" ? "User" : m.role === "assistant" ? "Agent" : m.role;
|
|
@@ -304,17 +404,13 @@ async function approve(transport, args) {
|
|
|
304
404
|
// src/tools/screenshot.ts
|
|
305
405
|
var SCREENSHOT_TOOL = {
|
|
306
406
|
name: "screenshot",
|
|
307
|
-
description: "Capture a screenshot of the current IDE window. Returns the image.",
|
|
407
|
+
description: "Capture a screenshot of the current IDE window. Returns the image. Local mode only \u2014 screenshots require direct P2P access to the daemon and are not available in cloud mode.",
|
|
308
408
|
inputSchema: {
|
|
309
409
|
type: "object",
|
|
310
410
|
properties: {
|
|
311
411
|
session_id: {
|
|
312
412
|
type: "string",
|
|
313
413
|
description: "Target session ID. Omit to use the active session."
|
|
314
|
-
},
|
|
315
|
-
daemon_id: {
|
|
316
|
-
type: "string",
|
|
317
|
-
description: "Daemon ID (cloud mode only)."
|
|
318
414
|
}
|
|
319
415
|
},
|
|
320
416
|
required: []
|
|
@@ -343,7 +439,7 @@ async function screenshot(transport, args) {
|
|
|
343
439
|
// src/tools/git-status.ts
|
|
344
440
|
var GIT_STATUS_TOOL = {
|
|
345
441
|
name: "git_status",
|
|
346
|
-
description: "Get git repository status for a workspace on the
|
|
442
|
+
description: "Get git repository status for a workspace on the daemon machine.",
|
|
347
443
|
inputSchema: {
|
|
348
444
|
type: "object",
|
|
349
445
|
properties: {
|
|
@@ -354,23 +450,79 @@ var GIT_STATUS_TOOL = {
|
|
|
354
450
|
include_diff: {
|
|
355
451
|
type: "boolean",
|
|
356
452
|
description: "Include changed file list (default: true)."
|
|
357
|
-
}
|
|
453
|
+
},
|
|
454
|
+
daemon_id: {
|
|
455
|
+
type: "string",
|
|
456
|
+
description: "Daemon ID (cloud mode only)."
|
|
457
|
+
},
|
|
458
|
+
...FORMAT_PROP
|
|
358
459
|
},
|
|
359
460
|
required: ["workspace"]
|
|
360
461
|
}
|
|
361
462
|
};
|
|
362
463
|
async function gitStatus(transport, args) {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
464
|
+
let status;
|
|
465
|
+
let diffSummary;
|
|
466
|
+
if ("command" in transport) {
|
|
467
|
+
const statusResult = await transport.command("git_status", {
|
|
468
|
+
workspace: args.workspace
|
|
469
|
+
});
|
|
470
|
+
status = statusResult?.status ?? statusResult;
|
|
471
|
+
if (args.include_diff !== false) {
|
|
472
|
+
const diffResult = await transport.command("git_diff_summary", {
|
|
473
|
+
workspace: args.workspace
|
|
474
|
+
});
|
|
475
|
+
diffSummary = diffResult?.diffSummary ?? diffResult;
|
|
476
|
+
}
|
|
477
|
+
} else {
|
|
478
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
479
|
+
const result = await transport.gitStatus(
|
|
480
|
+
args.daemon_id,
|
|
481
|
+
args.workspace,
|
|
482
|
+
args.include_diff !== false
|
|
483
|
+
);
|
|
484
|
+
if (result?.error) {
|
|
485
|
+
if (args.format === "json") return JSON.stringify({ error: result.error }, null, 2);
|
|
486
|
+
return `Error: ${result.error}`;
|
|
487
|
+
}
|
|
488
|
+
status = result?.status;
|
|
489
|
+
diffSummary = result?.diff;
|
|
490
|
+
}
|
|
491
|
+
if (status?.success === false || status?.reason) {
|
|
492
|
+
const msg = status?.error ?? status?.reason ?? "unknown";
|
|
493
|
+
if (args.format === "json") return JSON.stringify({ error: msg }, null, 2);
|
|
494
|
+
return `Git error: ${msg}`;
|
|
495
|
+
}
|
|
496
|
+
if (!status?.isGitRepo) {
|
|
497
|
+
if (args.format === "json") return JSON.stringify({ error: `Not a git repository: ${args.workspace}` }, null, 2);
|
|
498
|
+
return `Not a git repository: ${args.workspace}`;
|
|
499
|
+
}
|
|
500
|
+
if (args.format === "json") {
|
|
501
|
+
const files = diffSummary?.files?.map((f) => ({
|
|
502
|
+
path: f.path,
|
|
503
|
+
old_path: f.oldPath ?? null,
|
|
504
|
+
status: f.status ?? "M",
|
|
505
|
+
insertions: f.insertions ?? 0,
|
|
506
|
+
deletions: f.deletions ?? 0
|
|
507
|
+
})) ?? [];
|
|
508
|
+
return JSON.stringify({
|
|
509
|
+
branch: status.branch ?? null,
|
|
510
|
+
head_commit: status.headCommit ?? null,
|
|
511
|
+
head_message: status.headMessage ?? null,
|
|
512
|
+
ahead: status.ahead ?? 0,
|
|
513
|
+
behind: status.behind ?? 0,
|
|
514
|
+
staged: status.staged ?? 0,
|
|
515
|
+
modified: status.modified ?? 0,
|
|
516
|
+
untracked: status.untracked ?? 0,
|
|
517
|
+
deleted: status.deleted ?? 0,
|
|
518
|
+
stash_count: status.stashCount ?? 0,
|
|
519
|
+
has_conflicts: status.hasConflicts ?? false,
|
|
520
|
+
dirty: status.dirty ?? false,
|
|
521
|
+
changed_files: files,
|
|
522
|
+
total_insertions: diffSummary?.totalInsertions ?? 0,
|
|
523
|
+
total_deletions: diffSummary?.totalDeletions ?? 0
|
|
524
|
+
}, null, 2);
|
|
372
525
|
}
|
|
373
|
-
if (!status?.isGitRepo) return `Not a git repository: ${args.workspace}`;
|
|
374
526
|
const lines = [];
|
|
375
527
|
if (status.branch) lines.push(`Branch: ${status.branch}`);
|
|
376
528
|
if (status.headCommit) {
|
|
@@ -385,26 +537,172 @@ async function gitStatus(transport, args) {
|
|
|
385
537
|
if (status.stashCount > 0) lines.push(`Stashes: ${status.stashCount}`);
|
|
386
538
|
if (status.hasConflicts) lines.push("Conflicts: YES");
|
|
387
539
|
if (!status.dirty) lines.push("Working tree: clean");
|
|
388
|
-
if (
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
lines.push(` ${f.status ?? "M"} ${f.path}${f.oldPath ? ` (was ${f.oldPath})` : ""}${f.insertions || f.deletions ? ` +${f.insertions ?? 0}/-${f.deletions ?? 0}` : ""}`);
|
|
398
|
-
}
|
|
399
|
-
if (diffSummary.files.length > 20) lines.push(` \u2026 and ${diffSummary.files.length - 20} more`);
|
|
400
|
-
if (diffSummary.totalInsertions || diffSummary.totalDeletions) {
|
|
401
|
-
lines.push(`Total: +${diffSummary.totalInsertions ?? 0}/-${diffSummary.totalDeletions ?? 0}`);
|
|
402
|
-
}
|
|
540
|
+
if (diffSummary?.files?.length > 0) {
|
|
541
|
+
lines.push("");
|
|
542
|
+
lines.push(`Changed files (${diffSummary.files.length}):`);
|
|
543
|
+
for (const f of diffSummary.files.slice(0, 20)) {
|
|
544
|
+
lines.push(` ${f.status ?? "M"} ${f.path}${f.oldPath ? ` (was ${f.oldPath})` : ""}${f.insertions || f.deletions ? ` +${f.insertions ?? 0}/-${f.deletions ?? 0}` : ""}`);
|
|
545
|
+
}
|
|
546
|
+
if (diffSummary.files.length > 20) lines.push(` \u2026 and ${diffSummary.files.length - 20} more`);
|
|
547
|
+
if (diffSummary.totalInsertions || diffSummary.totalDeletions) {
|
|
548
|
+
lines.push(`Total: +${diffSummary.totalInsertions ?? 0}/-${diffSummary.totalDeletions ?? 0}`);
|
|
403
549
|
}
|
|
404
550
|
}
|
|
405
551
|
return lines.join("\n");
|
|
406
552
|
}
|
|
407
553
|
|
|
554
|
+
// src/tools/launch-session.ts
|
|
555
|
+
var LAUNCH_SESSION_TOOL = {
|
|
556
|
+
name: "launch_session",
|
|
557
|
+
description: "Launch a new agent session on the daemon. Supports CLI agents (e.g. hermes-cli, claude-cli, gemini-cli), ACP agents (e.g. claude-acp), and IDEs (e.g. cursor, vscode).",
|
|
558
|
+
inputSchema: {
|
|
559
|
+
type: "object",
|
|
560
|
+
properties: {
|
|
561
|
+
type: {
|
|
562
|
+
type: "string",
|
|
563
|
+
description: "Provider type to launch. CLI examples: hermes-cli, claude-cli, gemini-cli. ACP examples: claude-acp. IDE examples: cursor, vscode."
|
|
564
|
+
},
|
|
565
|
+
workspace: {
|
|
566
|
+
type: "string",
|
|
567
|
+
description: "Working directory for the session. Defaults to the daemon default workspace."
|
|
568
|
+
},
|
|
569
|
+
model: {
|
|
570
|
+
type: "string",
|
|
571
|
+
description: "Model override for ACP agents (e.g. claude-opus-4-7)."
|
|
572
|
+
},
|
|
573
|
+
daemon_id: {
|
|
574
|
+
type: "string",
|
|
575
|
+
description: "Daemon ID (cloud mode only). Required in cloud mode."
|
|
576
|
+
}
|
|
577
|
+
},
|
|
578
|
+
required: ["type"]
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
async function launchSession(transport, args) {
|
|
582
|
+
if ("command" in transport) {
|
|
583
|
+
const isCliOrAcp = args.type.includes("-cli") || args.type.includes("-acp") || args.type === "codex";
|
|
584
|
+
const commandType = isCliOrAcp ? "launch_cli" : "launch_ide";
|
|
585
|
+
const payload = isCliOrAcp ? { cliType: args.type, dir: args.workspace ?? "~", ...args.model ? { model: args.model } : {} } : { ideType: args.type, enableCdp: true };
|
|
586
|
+
const result2 = await transport.command(commandType, payload);
|
|
587
|
+
if (result2?.success === false) return `Error: ${result2.error ?? "launch failed"}`;
|
|
588
|
+
const id2 = result2?.id ?? result2?.sessionId;
|
|
589
|
+
return id2 ? `Session launched. id: ${id2}, type: ${args.type}` : `Launched: ${JSON.stringify(result2)}`;
|
|
590
|
+
}
|
|
591
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
592
|
+
const result = await transport.launch(args.daemon_id, {
|
|
593
|
+
type: args.type,
|
|
594
|
+
dir: args.workspace,
|
|
595
|
+
model: args.model
|
|
596
|
+
});
|
|
597
|
+
if (result?.success === false || result?.error) return `Error: ${result.error ?? "launch failed"}`;
|
|
598
|
+
const id = result?.id ?? result?.sessionId;
|
|
599
|
+
return id ? `Session launched. id: ${id}, type: ${args.type}` : `Launched: ${JSON.stringify(result)}`;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// src/tools/check-pending.ts
|
|
603
|
+
var CHECK_PENDING_TOOL = {
|
|
604
|
+
name: "check_pending",
|
|
605
|
+
description: "List all agent sessions currently waiting for user approval (tool-use confirmation). Returns session ID, daemon ID, workspace, and the approval prompt message when available. Use approve() with the session_id to approve or reject.",
|
|
606
|
+
inputSchema: {
|
|
607
|
+
type: "object",
|
|
608
|
+
properties: {
|
|
609
|
+
daemon_id: {
|
|
610
|
+
type: "string",
|
|
611
|
+
description: "Daemon ID to check (cloud mode). Omit to check all daemons."
|
|
612
|
+
},
|
|
613
|
+
...FORMAT_PROP
|
|
614
|
+
},
|
|
615
|
+
required: []
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
async function checkPending(transport, args) {
|
|
619
|
+
if ("getStatus" in transport) {
|
|
620
|
+
return checkPendingLocal(transport, args.format);
|
|
621
|
+
}
|
|
622
|
+
return checkPendingCloud(transport, args.daemon_id, args.format);
|
|
623
|
+
}
|
|
624
|
+
async function checkPendingLocal(transport, format) {
|
|
625
|
+
const status = await transport.getStatus();
|
|
626
|
+
const sessions = status?.sessions ?? [];
|
|
627
|
+
const pending = sessions.filter(
|
|
628
|
+
(s) => s.status === "waiting_approval" || s.agentStatus === "waiting_approval"
|
|
629
|
+
);
|
|
630
|
+
if (format === "json") {
|
|
631
|
+
return JSON.stringify({
|
|
632
|
+
pending: pending.map((s) => ({
|
|
633
|
+
session_id: s.id,
|
|
634
|
+
workspace: s.workspace ?? null,
|
|
635
|
+
type: s.providerType ?? null,
|
|
636
|
+
modal_message: s.activeChat?.activeModal?.message ?? null,
|
|
637
|
+
buttons: s.activeChat?.activeModal?.buttons ?? []
|
|
638
|
+
}))
|
|
639
|
+
}, null, 2);
|
|
640
|
+
}
|
|
641
|
+
if (pending.length === 0) return "No sessions waiting for approval.";
|
|
642
|
+
const lines = pending.map((s) => {
|
|
643
|
+
const modal = s.activeChat?.activeModal;
|
|
644
|
+
const parts = [`session_id: ${s.id}`];
|
|
645
|
+
if (s.workspace) parts.push(`workspace: ${s.workspace}`);
|
|
646
|
+
if (s.providerType) parts.push(`type: ${s.providerType}`);
|
|
647
|
+
if (modal?.message) parts.push(`prompt: ${modal.message}`);
|
|
648
|
+
if (modal?.buttons?.length) parts.push(`buttons: ${modal.buttons.join(", ")}`);
|
|
649
|
+
return parts.join("\n ");
|
|
650
|
+
});
|
|
651
|
+
return `Pending approvals (${pending.length}):
|
|
652
|
+
|
|
653
|
+
${lines.join("\n\n")}`;
|
|
654
|
+
}
|
|
655
|
+
async function checkPendingCloud(transport, daemonId, format) {
|
|
656
|
+
const pending = [];
|
|
657
|
+
if (daemonId) {
|
|
658
|
+
const daemonStatus = await transport.getDaemonStatus(daemonId);
|
|
659
|
+
const sessions = daemonStatus?.sessions ?? [];
|
|
660
|
+
for (const s of sessions) {
|
|
661
|
+
if (s.status === "waiting_approval") pending.push({ daemonId, session: s });
|
|
662
|
+
}
|
|
663
|
+
} else {
|
|
664
|
+
const data = await transport.listDaemons();
|
|
665
|
+
const daemons = data?.daemons ?? [];
|
|
666
|
+
for (let i = 0; i < daemons.length; i += 5) {
|
|
667
|
+
await Promise.allSettled(
|
|
668
|
+
daemons.slice(i, i + 5).map(async (d) => {
|
|
669
|
+
try {
|
|
670
|
+
const daemonStatus = await transport.getDaemonStatus(d.id);
|
|
671
|
+
const sessions = daemonStatus?.sessions ?? [];
|
|
672
|
+
for (const s of sessions) {
|
|
673
|
+
if (s.status === "waiting_approval") pending.push({ daemonId: d.id, session: s });
|
|
674
|
+
}
|
|
675
|
+
} catch {
|
|
676
|
+
}
|
|
677
|
+
})
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (format === "json") {
|
|
682
|
+
return JSON.stringify({
|
|
683
|
+
pending: pending.map(({ daemonId: dId, session: s }) => ({
|
|
684
|
+
daemon_id: dId,
|
|
685
|
+
session_id: s.id,
|
|
686
|
+
workspace: s.workspace ?? null,
|
|
687
|
+
type: s.providerType ?? null,
|
|
688
|
+
modal_message: null,
|
|
689
|
+
buttons: []
|
|
690
|
+
}))
|
|
691
|
+
}, null, 2);
|
|
692
|
+
}
|
|
693
|
+
if (pending.length === 0) return "No sessions waiting for approval.";
|
|
694
|
+
const lines = pending.map(({ daemonId: dId, session: s }) => {
|
|
695
|
+
const parts = [`daemon_id: ${dId}`, `session_id: ${s.id}`];
|
|
696
|
+
if (s.workspace) parts.push(`workspace: ${s.workspace}`);
|
|
697
|
+
if (s.providerType) parts.push(`type: ${s.providerType}`);
|
|
698
|
+
parts.push("(use read_chat to see the approval prompt)");
|
|
699
|
+
return parts.join("\n ");
|
|
700
|
+
});
|
|
701
|
+
return `Pending approvals (${pending.length}):
|
|
702
|
+
|
|
703
|
+
${lines.join("\n\n")}`;
|
|
704
|
+
}
|
|
705
|
+
|
|
408
706
|
// src/server.ts
|
|
409
707
|
async function startMcpServer(opts) {
|
|
410
708
|
const transport = opts.mode === "cloud" ? new CloudTransport({ apiKey: opts.apiKey, baseUrl: opts.baseUrl }) : new LocalTransport({ port: opts.port, password: opts.password });
|
|
@@ -418,14 +716,16 @@ async function startMcpServer(opts) {
|
|
|
418
716
|
const isLocal = opts.mode === "local";
|
|
419
717
|
const allTools = [
|
|
420
718
|
LIST_SESSIONS_TOOL,
|
|
719
|
+
LAUNCH_SESSION_TOOL,
|
|
720
|
+
CHECK_PENDING_TOOL,
|
|
421
721
|
READ_CHAT_TOOL,
|
|
422
722
|
SEND_CHAT_TOOL,
|
|
423
723
|
APPROVE_TOOL,
|
|
424
|
-
|
|
425
|
-
...isLocal ? [
|
|
724
|
+
GIT_STATUS_TOOL,
|
|
725
|
+
...isLocal ? [SCREENSHOT_TOOL] : []
|
|
426
726
|
];
|
|
427
727
|
const server = new import_server.Server(
|
|
428
|
-
{ name: "adhdev-mcp-server", version: "0.9.
|
|
728
|
+
{ name: "adhdev-mcp-server", version: "0.9.61" },
|
|
429
729
|
{ capabilities: { tools: {} } }
|
|
430
730
|
);
|
|
431
731
|
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => ({ tools: allTools }));
|
|
@@ -435,7 +735,7 @@ async function startMcpServer(opts) {
|
|
|
435
735
|
try {
|
|
436
736
|
switch (name) {
|
|
437
737
|
case "list_sessions": {
|
|
438
|
-
const text = await listSessions(transport);
|
|
738
|
+
const text = await listSessions(transport, { format: a.format, daemon_id: a.daemon_id });
|
|
439
739
|
return { content: [{ type: "text", text }] };
|
|
440
740
|
}
|
|
441
741
|
case "read_chat": {
|
|
@@ -452,7 +752,7 @@ async function startMcpServer(opts) {
|
|
|
452
752
|
return { content: [{ type: "text", text }] };
|
|
453
753
|
}
|
|
454
754
|
case "screenshot": {
|
|
455
|
-
const result = await screenshot(transport, { session_id: a.session_id
|
|
755
|
+
const result = await screenshot(transport, { session_id: a.session_id });
|
|
456
756
|
if (result.type === "image") {
|
|
457
757
|
return {
|
|
458
758
|
content: [{ type: "image", data: result.data, mimeType: result.mimeType }]
|
|
@@ -461,7 +761,20 @@ async function startMcpServer(opts) {
|
|
|
461
761
|
return { content: [{ type: "text", text: result.text }] };
|
|
462
762
|
}
|
|
463
763
|
case "git_status": {
|
|
464
|
-
const text = await gitStatus(transport, { workspace: a.workspace, include_diff: a.include_diff });
|
|
764
|
+
const text = await gitStatus(transport, { workspace: a.workspace, include_diff: a.include_diff, daemon_id: a.daemon_id, format: a.format });
|
|
765
|
+
return { content: [{ type: "text", text }] };
|
|
766
|
+
}
|
|
767
|
+
case "launch_session": {
|
|
768
|
+
const text = await launchSession(transport, {
|
|
769
|
+
type: a.type,
|
|
770
|
+
workspace: a.workspace,
|
|
771
|
+
model: a.model,
|
|
772
|
+
daemon_id: a.daemon_id
|
|
773
|
+
});
|
|
774
|
+
return { content: [{ type: "text", text }] };
|
|
775
|
+
}
|
|
776
|
+
case "check_pending": {
|
|
777
|
+
const text = await checkPending(transport, { daemon_id: a.daemon_id, format: a.format });
|
|
465
778
|
return { content: [{ type: "text", text }] };
|
|
466
779
|
}
|
|
467
780
|
default:
|
|
@@ -530,8 +843,8 @@ Environment variables:
|
|
|
530
843
|
ADHDEV_API_KEY API key (cloud mode)
|
|
531
844
|
ADHDEV_PASSWORD Daemon password (local mode)
|
|
532
845
|
|
|
533
|
-
Local mode tools: list_sessions, read_chat, send_chat, approve,
|
|
534
|
-
Cloud mode tools: list_sessions, read_chat, send_chat, approve
|
|
846
|
+
Local mode tools: list_sessions, launch_session, check_pending, read_chat, send_chat, approve, git_status, screenshot
|
|
847
|
+
Cloud mode tools: list_sessions, launch_session, check_pending, read_chat, send_chat, approve, git_status
|
|
535
848
|
`.trim());
|
|
536
849
|
}
|
|
537
850
|
startMcpServer(parseArgs(process.argv)).catch((err) => {
|