adhdev 0.9.59 → 0.9.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/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 +341 -48
- 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,25 +152,43 @@ 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
164
|
description: "List all currently connected IDE and CLI agent sessions on the local machine.",
|
|
128
165
|
inputSchema: {
|
|
129
166
|
type: "object",
|
|
130
|
-
properties: {
|
|
167
|
+
properties: {
|
|
168
|
+
...FORMAT_PROP
|
|
169
|
+
},
|
|
131
170
|
required: []
|
|
132
171
|
}
|
|
133
172
|
};
|
|
134
|
-
async function listSessions(transport) {
|
|
173
|
+
async function listSessions(transport, args = {}) {
|
|
174
|
+
const asJson = args.format === "json";
|
|
135
175
|
if ("getStatus" in transport) {
|
|
136
176
|
const status = await transport.getStatus();
|
|
137
177
|
const sessions = status?.sessions ?? [];
|
|
178
|
+
if (asJson) {
|
|
179
|
+
return JSON.stringify({
|
|
180
|
+
sessions: sessions.map((s) => ({
|
|
181
|
+
id: s.id,
|
|
182
|
+
type: s.providerType ?? s.type ?? "unknown",
|
|
183
|
+
label: s.label ?? null,
|
|
184
|
+
status: s.status ?? s.agentStatus ?? null,
|
|
185
|
+
workspace: s.workspace ?? null
|
|
186
|
+
}))
|
|
187
|
+
}, null, 2);
|
|
188
|
+
}
|
|
138
189
|
if (sessions.length === 0) return "No active sessions.";
|
|
139
190
|
const lines2 = sessions.map((s) => {
|
|
140
|
-
const parts = [
|
|
141
|
-
`id: ${s.id}`,
|
|
142
|
-
`type: ${s.providerType ?? s.type ?? "unknown"}`
|
|
143
|
-
];
|
|
191
|
+
const parts = [`id: ${s.id}`, `type: ${s.providerType ?? s.type ?? "unknown"}`];
|
|
144
192
|
if (s.label) parts.push(`label: ${s.label}`);
|
|
145
193
|
if (s.agentStatus) parts.push(`status: ${s.agentStatus}`);
|
|
146
194
|
if (s.workspace) parts.push(`workspace: ${s.workspace}`);
|
|
@@ -151,6 +199,21 @@ ${lines2.join("\n")}`;
|
|
|
151
199
|
}
|
|
152
200
|
const data = await transport.listDaemons();
|
|
153
201
|
const daemons = data?.daemons ?? data ?? [];
|
|
202
|
+
if (asJson) {
|
|
203
|
+
const sessions = [];
|
|
204
|
+
for (const d of daemons) {
|
|
205
|
+
for (const s of d.sessions ?? []) {
|
|
206
|
+
sessions.push({
|
|
207
|
+
daemon_id: d.id,
|
|
208
|
+
id: s.id,
|
|
209
|
+
type: s.providerType ?? "unknown",
|
|
210
|
+
status: s.status ?? s.agentStatus ?? null,
|
|
211
|
+
workspace: s.workspace ?? null
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return JSON.stringify({ sessions }, null, 2);
|
|
216
|
+
}
|
|
154
217
|
if (daemons.length === 0) return "No connected daemons.";
|
|
155
218
|
const lines = [];
|
|
156
219
|
for (const d of daemons) {
|
|
@@ -160,9 +223,7 @@ ${lines2.join("\n")}`;
|
|
|
160
223
|
`daemon: ${d.id}, session: ${s.id}, type: ${s.providerType ?? "unknown"}${s.agentStatus ? `, status: ${s.agentStatus}` : ""}`
|
|
161
224
|
);
|
|
162
225
|
}
|
|
163
|
-
if (sessions.length === 0) {
|
|
164
|
-
lines.push(`daemon: ${d.id} (no sessions)`);
|
|
165
|
-
}
|
|
226
|
+
if (sessions.length === 0) lines.push(`daemon: ${d.id} (no sessions)`);
|
|
166
227
|
}
|
|
167
228
|
return lines.length > 0 ? `Sessions:
|
|
168
229
|
${lines.join("\n")}` : "No active sessions.";
|
|
@@ -186,7 +247,8 @@ var READ_CHAT_TOOL = {
|
|
|
186
247
|
daemon_id: {
|
|
187
248
|
type: "string",
|
|
188
249
|
description: "Daemon ID (cloud mode only). Omit for local mode."
|
|
189
|
-
}
|
|
250
|
+
},
|
|
251
|
+
...FORMAT_PROP
|
|
190
252
|
},
|
|
191
253
|
required: []
|
|
192
254
|
}
|
|
@@ -198,16 +260,30 @@ async function readChat(transport, args) {
|
|
|
198
260
|
...args.session_id ? { targetSessionId: args.session_id } : {},
|
|
199
261
|
limit
|
|
200
262
|
});
|
|
201
|
-
return formatChatResult(result2);
|
|
263
|
+
return formatChatResult(result2, args.session_id, args.format);
|
|
202
264
|
}
|
|
203
265
|
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
204
266
|
const targetId = args.session_id ? `${args.daemon_id}:session:${args.session_id}` : args.daemon_id;
|
|
205
267
|
const result = await transport.readChat(targetId, { limit, sessionId: args.session_id });
|
|
206
|
-
return formatChatResult(result);
|
|
268
|
+
return formatChatResult(result, args.session_id, args.format);
|
|
207
269
|
}
|
|
208
|
-
function formatChatResult(result) {
|
|
209
|
-
if (!result?.success && result?.error)
|
|
270
|
+
function formatChatResult(result, sessionId, format) {
|
|
271
|
+
if (!result?.success && result?.error) {
|
|
272
|
+
if (format === "json") return JSON.stringify({ error: result.error, messages: [] }, null, 2);
|
|
273
|
+
return `Error: ${result.error}`;
|
|
274
|
+
}
|
|
210
275
|
const messages = result?.messages ?? result?.data?.messages ?? [];
|
|
276
|
+
if (format === "json") {
|
|
277
|
+
return JSON.stringify({
|
|
278
|
+
session_id: sessionId ?? null,
|
|
279
|
+
messages: messages.slice(-50).map((m) => ({
|
|
280
|
+
role: m.role,
|
|
281
|
+
kind: m.kind ?? null,
|
|
282
|
+
content: typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((p) => typeof p === "string" ? p : p?.text ?? "").join("") : "",
|
|
283
|
+
timestamp: m.timestamp ?? null
|
|
284
|
+
}))
|
|
285
|
+
}, null, 2);
|
|
286
|
+
}
|
|
211
287
|
if (messages.length === 0) return "No messages in chat.";
|
|
212
288
|
const lines = messages.slice(-50).map((m) => {
|
|
213
289
|
const role = m.role === "user" ? "User" : m.role === "assistant" ? "Agent" : m.role;
|
|
@@ -343,7 +419,7 @@ async function screenshot(transport, args) {
|
|
|
343
419
|
// src/tools/git-status.ts
|
|
344
420
|
var GIT_STATUS_TOOL = {
|
|
345
421
|
name: "git_status",
|
|
346
|
-
description: "Get git repository status for a workspace on the
|
|
422
|
+
description: "Get git repository status for a workspace on the daemon machine.",
|
|
347
423
|
inputSchema: {
|
|
348
424
|
type: "object",
|
|
349
425
|
properties: {
|
|
@@ -354,23 +430,79 @@ var GIT_STATUS_TOOL = {
|
|
|
354
430
|
include_diff: {
|
|
355
431
|
type: "boolean",
|
|
356
432
|
description: "Include changed file list (default: true)."
|
|
357
|
-
}
|
|
433
|
+
},
|
|
434
|
+
daemon_id: {
|
|
435
|
+
type: "string",
|
|
436
|
+
description: "Daemon ID (cloud mode only)."
|
|
437
|
+
},
|
|
438
|
+
...FORMAT_PROP
|
|
358
439
|
},
|
|
359
440
|
required: ["workspace"]
|
|
360
441
|
}
|
|
361
442
|
};
|
|
362
443
|
async function gitStatus(transport, args) {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
444
|
+
let status;
|
|
445
|
+
let diffSummary;
|
|
446
|
+
if ("command" in transport) {
|
|
447
|
+
const statusResult = await transport.command("git_status", {
|
|
448
|
+
workspace: args.workspace
|
|
449
|
+
});
|
|
450
|
+
status = statusResult?.status ?? statusResult;
|
|
451
|
+
if (args.include_diff !== false) {
|
|
452
|
+
const diffResult = await transport.command("git_diff_summary", {
|
|
453
|
+
workspace: args.workspace
|
|
454
|
+
});
|
|
455
|
+
diffSummary = diffResult?.diffSummary ?? diffResult;
|
|
456
|
+
}
|
|
457
|
+
} else {
|
|
458
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
459
|
+
const result = await transport.gitStatus(
|
|
460
|
+
args.daemon_id,
|
|
461
|
+
args.workspace,
|
|
462
|
+
args.include_diff !== false
|
|
463
|
+
);
|
|
464
|
+
if (result?.error) {
|
|
465
|
+
if (args.format === "json") return JSON.stringify({ error: result.error }, null, 2);
|
|
466
|
+
return `Error: ${result.error}`;
|
|
467
|
+
}
|
|
468
|
+
status = result?.status;
|
|
469
|
+
diffSummary = result?.diff;
|
|
470
|
+
}
|
|
471
|
+
if (status?.success === false || status?.reason) {
|
|
472
|
+
const msg = status?.error ?? status?.reason ?? "unknown";
|
|
473
|
+
if (args.format === "json") return JSON.stringify({ error: msg }, null, 2);
|
|
474
|
+
return `Git error: ${msg}`;
|
|
475
|
+
}
|
|
476
|
+
if (!status?.isGitRepo) {
|
|
477
|
+
if (args.format === "json") return JSON.stringify({ error: `Not a git repository: ${args.workspace}` }, null, 2);
|
|
478
|
+
return `Not a git repository: ${args.workspace}`;
|
|
479
|
+
}
|
|
480
|
+
if (args.format === "json") {
|
|
481
|
+
const files = diffSummary?.files?.map((f) => ({
|
|
482
|
+
path: f.path,
|
|
483
|
+
old_path: f.oldPath ?? null,
|
|
484
|
+
status: f.status ?? "M",
|
|
485
|
+
insertions: f.insertions ?? 0,
|
|
486
|
+
deletions: f.deletions ?? 0
|
|
487
|
+
})) ?? [];
|
|
488
|
+
return JSON.stringify({
|
|
489
|
+
branch: status.branch ?? null,
|
|
490
|
+
head_commit: status.headCommit ?? null,
|
|
491
|
+
head_message: status.headMessage ?? null,
|
|
492
|
+
ahead: status.ahead ?? 0,
|
|
493
|
+
behind: status.behind ?? 0,
|
|
494
|
+
staged: status.staged ?? 0,
|
|
495
|
+
modified: status.modified ?? 0,
|
|
496
|
+
untracked: status.untracked ?? 0,
|
|
497
|
+
deleted: status.deleted ?? 0,
|
|
498
|
+
stash_count: status.stashCount ?? 0,
|
|
499
|
+
has_conflicts: status.hasConflicts ?? false,
|
|
500
|
+
dirty: status.dirty ?? false,
|
|
501
|
+
changed_files: files,
|
|
502
|
+
total_insertions: diffSummary?.totalInsertions ?? 0,
|
|
503
|
+
total_deletions: diffSummary?.totalDeletions ?? 0
|
|
504
|
+
}, null, 2);
|
|
372
505
|
}
|
|
373
|
-
if (!status?.isGitRepo) return `Not a git repository: ${args.workspace}`;
|
|
374
506
|
const lines = [];
|
|
375
507
|
if (status.branch) lines.push(`Branch: ${status.branch}`);
|
|
376
508
|
if (status.headCommit) {
|
|
@@ -385,26 +517,172 @@ async function gitStatus(transport, args) {
|
|
|
385
517
|
if (status.stashCount > 0) lines.push(`Stashes: ${status.stashCount}`);
|
|
386
518
|
if (status.hasConflicts) lines.push("Conflicts: YES");
|
|
387
519
|
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
|
-
}
|
|
520
|
+
if (diffSummary?.files?.length > 0) {
|
|
521
|
+
lines.push("");
|
|
522
|
+
lines.push(`Changed files (${diffSummary.files.length}):`);
|
|
523
|
+
for (const f of diffSummary.files.slice(0, 20)) {
|
|
524
|
+
lines.push(` ${f.status ?? "M"} ${f.path}${f.oldPath ? ` (was ${f.oldPath})` : ""}${f.insertions || f.deletions ? ` +${f.insertions ?? 0}/-${f.deletions ?? 0}` : ""}`);
|
|
525
|
+
}
|
|
526
|
+
if (diffSummary.files.length > 20) lines.push(` \u2026 and ${diffSummary.files.length - 20} more`);
|
|
527
|
+
if (diffSummary.totalInsertions || diffSummary.totalDeletions) {
|
|
528
|
+
lines.push(`Total: +${diffSummary.totalInsertions ?? 0}/-${diffSummary.totalDeletions ?? 0}`);
|
|
403
529
|
}
|
|
404
530
|
}
|
|
405
531
|
return lines.join("\n");
|
|
406
532
|
}
|
|
407
533
|
|
|
534
|
+
// src/tools/launch-session.ts
|
|
535
|
+
var LAUNCH_SESSION_TOOL = {
|
|
536
|
+
name: "launch_session",
|
|
537
|
+
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).",
|
|
538
|
+
inputSchema: {
|
|
539
|
+
type: "object",
|
|
540
|
+
properties: {
|
|
541
|
+
type: {
|
|
542
|
+
type: "string",
|
|
543
|
+
description: "Provider type to launch. CLI examples: hermes-cli, claude-cli, gemini-cli. ACP examples: claude-acp. IDE examples: cursor, vscode."
|
|
544
|
+
},
|
|
545
|
+
workspace: {
|
|
546
|
+
type: "string",
|
|
547
|
+
description: "Working directory for the session. Defaults to the daemon default workspace."
|
|
548
|
+
},
|
|
549
|
+
model: {
|
|
550
|
+
type: "string",
|
|
551
|
+
description: "Model override for ACP agents (e.g. claude-opus-4-7)."
|
|
552
|
+
},
|
|
553
|
+
daemon_id: {
|
|
554
|
+
type: "string",
|
|
555
|
+
description: "Daemon ID (cloud mode only). Required in cloud mode."
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
required: ["type"]
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
async function launchSession(transport, args) {
|
|
562
|
+
if ("command" in transport) {
|
|
563
|
+
const isCliOrAcp = args.type.includes("-cli") || args.type.includes("-acp") || args.type === "codex";
|
|
564
|
+
const commandType = isCliOrAcp ? "launch_cli" : "launch_ide";
|
|
565
|
+
const payload = isCliOrAcp ? { cliType: args.type, dir: args.workspace ?? "~", ...args.model ? { model: args.model } : {} } : { ideType: args.type, enableCdp: true };
|
|
566
|
+
const result2 = await transport.command(commandType, payload);
|
|
567
|
+
if (result2?.success === false) return `Error: ${result2.error ?? "launch failed"}`;
|
|
568
|
+
const id2 = result2?.id ?? result2?.sessionId;
|
|
569
|
+
return id2 ? `Session launched. id: ${id2}, type: ${args.type}` : `Launched: ${JSON.stringify(result2)}`;
|
|
570
|
+
}
|
|
571
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
572
|
+
const result = await transport.launch(args.daemon_id, {
|
|
573
|
+
type: args.type,
|
|
574
|
+
dir: args.workspace,
|
|
575
|
+
model: args.model
|
|
576
|
+
});
|
|
577
|
+
if (result?.success === false || result?.error) return `Error: ${result.error ?? "launch failed"}`;
|
|
578
|
+
const id = result?.id ?? result?.sessionId;
|
|
579
|
+
return id ? `Session launched. id: ${id}, type: ${args.type}` : `Launched: ${JSON.stringify(result)}`;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// src/tools/check-pending.ts
|
|
583
|
+
var CHECK_PENDING_TOOL = {
|
|
584
|
+
name: "check_pending",
|
|
585
|
+
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.",
|
|
586
|
+
inputSchema: {
|
|
587
|
+
type: "object",
|
|
588
|
+
properties: {
|
|
589
|
+
daemon_id: {
|
|
590
|
+
type: "string",
|
|
591
|
+
description: "Daemon ID to check (cloud mode). Omit to check all daemons."
|
|
592
|
+
},
|
|
593
|
+
...FORMAT_PROP
|
|
594
|
+
},
|
|
595
|
+
required: []
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
async function checkPending(transport, args) {
|
|
599
|
+
if ("getStatus" in transport) {
|
|
600
|
+
return checkPendingLocal(transport, args.format);
|
|
601
|
+
}
|
|
602
|
+
return checkPendingCloud(transport, args.daemon_id, args.format);
|
|
603
|
+
}
|
|
604
|
+
async function checkPendingLocal(transport, format) {
|
|
605
|
+
const status = await transport.getStatus();
|
|
606
|
+
const sessions = status?.sessions ?? [];
|
|
607
|
+
const pending = sessions.filter(
|
|
608
|
+
(s) => s.status === "waiting_approval" || s.agentStatus === "waiting_approval"
|
|
609
|
+
);
|
|
610
|
+
if (format === "json") {
|
|
611
|
+
return JSON.stringify({
|
|
612
|
+
pending: pending.map((s) => ({
|
|
613
|
+
session_id: s.id,
|
|
614
|
+
workspace: s.workspace ?? null,
|
|
615
|
+
type: s.providerType ?? null,
|
|
616
|
+
modal_message: s.activeChat?.activeModal?.message ?? null,
|
|
617
|
+
buttons: s.activeChat?.activeModal?.buttons ?? []
|
|
618
|
+
}))
|
|
619
|
+
}, null, 2);
|
|
620
|
+
}
|
|
621
|
+
if (pending.length === 0) return "No sessions waiting for approval.";
|
|
622
|
+
const lines = pending.map((s) => {
|
|
623
|
+
const modal = s.activeChat?.activeModal;
|
|
624
|
+
const parts = [`session_id: ${s.id}`];
|
|
625
|
+
if (s.workspace) parts.push(`workspace: ${s.workspace}`);
|
|
626
|
+
if (s.providerType) parts.push(`type: ${s.providerType}`);
|
|
627
|
+
if (modal?.message) parts.push(`prompt: ${modal.message}`);
|
|
628
|
+
if (modal?.buttons?.length) parts.push(`buttons: ${modal.buttons.join(", ")}`);
|
|
629
|
+
return parts.join("\n ");
|
|
630
|
+
});
|
|
631
|
+
return `Pending approvals (${pending.length}):
|
|
632
|
+
|
|
633
|
+
${lines.join("\n\n")}`;
|
|
634
|
+
}
|
|
635
|
+
async function checkPendingCloud(transport, daemonId, format) {
|
|
636
|
+
const pending = [];
|
|
637
|
+
if (daemonId) {
|
|
638
|
+
const daemonStatus = await transport.getDaemonStatus(daemonId);
|
|
639
|
+
const sessions = daemonStatus?.sessions ?? [];
|
|
640
|
+
for (const s of sessions) {
|
|
641
|
+
if (s.status === "waiting_approval") pending.push({ daemonId, session: s });
|
|
642
|
+
}
|
|
643
|
+
} else {
|
|
644
|
+
const data = await transport.listDaemons();
|
|
645
|
+
const daemons = data?.daemons ?? [];
|
|
646
|
+
for (let i = 0; i < daemons.length; i += 5) {
|
|
647
|
+
await Promise.allSettled(
|
|
648
|
+
daemons.slice(i, i + 5).map(async (d) => {
|
|
649
|
+
try {
|
|
650
|
+
const daemonStatus = await transport.getDaemonStatus(d.id);
|
|
651
|
+
const sessions = daemonStatus?.sessions ?? [];
|
|
652
|
+
for (const s of sessions) {
|
|
653
|
+
if (s.status === "waiting_approval") pending.push({ daemonId: d.id, session: s });
|
|
654
|
+
}
|
|
655
|
+
} catch {
|
|
656
|
+
}
|
|
657
|
+
})
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
if (format === "json") {
|
|
662
|
+
return JSON.stringify({
|
|
663
|
+
pending: pending.map(({ daemonId: dId, session: s }) => ({
|
|
664
|
+
daemon_id: dId,
|
|
665
|
+
session_id: s.id,
|
|
666
|
+
workspace: s.workspace ?? null,
|
|
667
|
+
type: s.providerType ?? null,
|
|
668
|
+
modal_message: null,
|
|
669
|
+
buttons: []
|
|
670
|
+
}))
|
|
671
|
+
}, null, 2);
|
|
672
|
+
}
|
|
673
|
+
if (pending.length === 0) return "No sessions waiting for approval.";
|
|
674
|
+
const lines = pending.map(({ daemonId: dId, session: s }) => {
|
|
675
|
+
const parts = [`daemon_id: ${dId}`, `session_id: ${s.id}`];
|
|
676
|
+
if (s.workspace) parts.push(`workspace: ${s.workspace}`);
|
|
677
|
+
if (s.providerType) parts.push(`type: ${s.providerType}`);
|
|
678
|
+
parts.push("(use read_chat to see the approval prompt)");
|
|
679
|
+
return parts.join("\n ");
|
|
680
|
+
});
|
|
681
|
+
return `Pending approvals (${pending.length}):
|
|
682
|
+
|
|
683
|
+
${lines.join("\n\n")}`;
|
|
684
|
+
}
|
|
685
|
+
|
|
408
686
|
// src/server.ts
|
|
409
687
|
async function startMcpServer(opts) {
|
|
410
688
|
const transport = opts.mode === "cloud" ? new CloudTransport({ apiKey: opts.apiKey, baseUrl: opts.baseUrl }) : new LocalTransport({ port: opts.port, password: opts.password });
|
|
@@ -418,14 +696,16 @@ async function startMcpServer(opts) {
|
|
|
418
696
|
const isLocal = opts.mode === "local";
|
|
419
697
|
const allTools = [
|
|
420
698
|
LIST_SESSIONS_TOOL,
|
|
699
|
+
LAUNCH_SESSION_TOOL,
|
|
700
|
+
CHECK_PENDING_TOOL,
|
|
421
701
|
READ_CHAT_TOOL,
|
|
422
702
|
SEND_CHAT_TOOL,
|
|
423
703
|
APPROVE_TOOL,
|
|
424
|
-
|
|
425
|
-
...isLocal ? [
|
|
704
|
+
GIT_STATUS_TOOL,
|
|
705
|
+
...isLocal ? [SCREENSHOT_TOOL] : []
|
|
426
706
|
];
|
|
427
707
|
const server = new import_server.Server(
|
|
428
|
-
{ name: "adhdev-mcp-server", version: "0.9.
|
|
708
|
+
{ name: "adhdev-mcp-server", version: "0.9.60" },
|
|
429
709
|
{ capabilities: { tools: {} } }
|
|
430
710
|
);
|
|
431
711
|
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => ({ tools: allTools }));
|
|
@@ -435,7 +715,7 @@ async function startMcpServer(opts) {
|
|
|
435
715
|
try {
|
|
436
716
|
switch (name) {
|
|
437
717
|
case "list_sessions": {
|
|
438
|
-
const text = await listSessions(transport);
|
|
718
|
+
const text = await listSessions(transport, { format: a.format });
|
|
439
719
|
return { content: [{ type: "text", text }] };
|
|
440
720
|
}
|
|
441
721
|
case "read_chat": {
|
|
@@ -461,7 +741,20 @@ async function startMcpServer(opts) {
|
|
|
461
741
|
return { content: [{ type: "text", text: result.text }] };
|
|
462
742
|
}
|
|
463
743
|
case "git_status": {
|
|
464
|
-
const text = await gitStatus(transport, { workspace: a.workspace, include_diff: a.include_diff });
|
|
744
|
+
const text = await gitStatus(transport, { workspace: a.workspace, include_diff: a.include_diff, daemon_id: a.daemon_id, format: a.format });
|
|
745
|
+
return { content: [{ type: "text", text }] };
|
|
746
|
+
}
|
|
747
|
+
case "launch_session": {
|
|
748
|
+
const text = await launchSession(transport, {
|
|
749
|
+
type: a.type,
|
|
750
|
+
workspace: a.workspace,
|
|
751
|
+
model: a.model,
|
|
752
|
+
daemon_id: a.daemon_id
|
|
753
|
+
});
|
|
754
|
+
return { content: [{ type: "text", text }] };
|
|
755
|
+
}
|
|
756
|
+
case "check_pending": {
|
|
757
|
+
const text = await checkPending(transport, { daemon_id: a.daemon_id, format: a.format });
|
|
465
758
|
return { content: [{ type: "text", text }] };
|
|
466
759
|
}
|
|
467
760
|
default:
|
|
@@ -530,8 +823,8 @@ Environment variables:
|
|
|
530
823
|
ADHDEV_API_KEY API key (cloud mode)
|
|
531
824
|
ADHDEV_PASSWORD Daemon password (local mode)
|
|
532
825
|
|
|
533
|
-
Local mode tools: list_sessions, read_chat, send_chat, approve,
|
|
534
|
-
Cloud mode tools: list_sessions, read_chat, send_chat, approve
|
|
826
|
+
Local mode tools: list_sessions, launch_session, check_pending, read_chat, send_chat, approve, git_status, screenshot
|
|
827
|
+
Cloud mode tools: list_sessions, launch_session, check_pending, read_chat, send_chat, approve, git_status
|
|
535
828
|
`.trim());
|
|
536
829
|
}
|
|
537
830
|
startMcpServer(parseArgs(process.argv)).catch((err) => {
|