adhdev 0.9.57 → 0.9.59
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 +465 -454
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/vendor/mcp-server/index.js +542 -0
- package/vendor/mcp-server/index.js.map +1 -0
- package/vendor/mcp-server/package.json +7 -0
package/dist/index.js
CHANGED
|
@@ -59147,7 +59147,7 @@ var init_adhdev_daemon = __esm({
|
|
|
59147
59147
|
init_version();
|
|
59148
59148
|
init_src();
|
|
59149
59149
|
init_runtime_defaults();
|
|
59150
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.
|
|
59150
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.59" });
|
|
59151
59151
|
AdhdevDaemon = class _AdhdevDaemon {
|
|
59152
59152
|
localHttpServer = null;
|
|
59153
59153
|
localWss = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adhdev",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.59",
|
|
4
4
|
"description": "ADHDev — Agent Dashboard Hub for Dev. Remote-control AI coding agents from anywhere.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@adhdev/daemon-core": "*",
|
|
51
|
-
"@adhdev/mcp-server": "*",
|
|
52
51
|
"@adhdev/ghostty-vt-node": "*",
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
53
53
|
"@xterm/addon-serialize": "^0.14.0",
|
|
54
54
|
"@xterm/xterm": "^6.0.0",
|
|
55
55
|
"chalk": "^5.3.0",
|
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/server.ts
|
|
5
|
+
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
6
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
7
|
+
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
8
|
+
|
|
9
|
+
// src/transports/local.ts
|
|
10
|
+
var DEFAULT_PORT = 3847;
|
|
11
|
+
var LocalTransport = class {
|
|
12
|
+
baseUrl;
|
|
13
|
+
authHeader;
|
|
14
|
+
constructor(opts = {}) {
|
|
15
|
+
this.baseUrl = `http://localhost:${opts.port ?? DEFAULT_PORT}`;
|
|
16
|
+
this.authHeader = opts.password ? `Bearer ${opts.password}` : null;
|
|
17
|
+
}
|
|
18
|
+
headers() {
|
|
19
|
+
const h = { "Content-Type": "application/json" };
|
|
20
|
+
if (this.authHeader) h["Authorization"] = this.authHeader;
|
|
21
|
+
return h;
|
|
22
|
+
}
|
|
23
|
+
async getStatus() {
|
|
24
|
+
const res = await fetch(`${this.baseUrl}/api/v1/status`, { headers: this.headers() });
|
|
25
|
+
if (!res.ok) throw new Error(`Status fetch failed: ${res.status}`);
|
|
26
|
+
return res.json();
|
|
27
|
+
}
|
|
28
|
+
async command(type, args = {}) {
|
|
29
|
+
const res = await fetch(`${this.baseUrl}/api/v1/command`, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: this.headers(),
|
|
32
|
+
body: JSON.stringify({ type, ...args })
|
|
33
|
+
});
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
const text = await res.text().catch(() => res.statusText);
|
|
36
|
+
throw new Error(`Command ${type} failed: ${res.status} ${text}`);
|
|
37
|
+
}
|
|
38
|
+
return res.json();
|
|
39
|
+
}
|
|
40
|
+
async ping() {
|
|
41
|
+
try {
|
|
42
|
+
await this.getStatus();
|
|
43
|
+
return true;
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// src/transports/cloud.ts
|
|
51
|
+
var DEFAULT_BASE_URL = "https://api.adhf.dev";
|
|
52
|
+
var CloudTransport = class {
|
|
53
|
+
baseUrl;
|
|
54
|
+
apiKey;
|
|
55
|
+
constructor(opts) {
|
|
56
|
+
this.apiKey = opts.apiKey;
|
|
57
|
+
this.baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
|
|
58
|
+
}
|
|
59
|
+
headers() {
|
|
60
|
+
return {
|
|
61
|
+
"Content-Type": "application/json",
|
|
62
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async listDaemons() {
|
|
66
|
+
const res = await fetch(`${this.baseUrl}/api/v1/daemons`, { headers: this.headers() });
|
|
67
|
+
if (!res.ok) throw new Error(`List daemons failed: ${res.status}`);
|
|
68
|
+
return res.json();
|
|
69
|
+
}
|
|
70
|
+
async getStatus(targetId) {
|
|
71
|
+
const res = await fetch(
|
|
72
|
+
`${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(targetId)}/status`,
|
|
73
|
+
{ headers: this.headers() }
|
|
74
|
+
);
|
|
75
|
+
if (!res.ok) throw new Error(`Status failed: ${res.status}`);
|
|
76
|
+
return res.json();
|
|
77
|
+
}
|
|
78
|
+
async readChat(targetId, opts = {}) {
|
|
79
|
+
const params = new URLSearchParams();
|
|
80
|
+
if (opts.limit) params.set("limit", String(opts.limit));
|
|
81
|
+
if (opts.sessionId) params.set("sessionId", opts.sessionId);
|
|
82
|
+
const qs = params.toString() ? `?${params}` : "";
|
|
83
|
+
const res = await fetch(
|
|
84
|
+
`${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(targetId)}/chat${qs}`,
|
|
85
|
+
{ headers: this.headers() }
|
|
86
|
+
);
|
|
87
|
+
if (!res.ok) throw new Error(`Read chat failed: ${res.status}`);
|
|
88
|
+
return res.json();
|
|
89
|
+
}
|
|
90
|
+
async sendChat(targetId, message, opts = {}) {
|
|
91
|
+
const res = await fetch(
|
|
92
|
+
`${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(targetId)}/chat`,
|
|
93
|
+
{
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: this.headers(),
|
|
96
|
+
body: JSON.stringify({ message, ...opts })
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
if (!res.ok) throw new Error(`Send chat failed: ${res.status}`);
|
|
100
|
+
return res.json();
|
|
101
|
+
}
|
|
102
|
+
async approve(targetId, action, agentType) {
|
|
103
|
+
const res = await fetch(
|
|
104
|
+
`${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(targetId)}/approve`,
|
|
105
|
+
{
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: this.headers(),
|
|
108
|
+
body: JSON.stringify({ action, ...agentType ? { agentType } : {} })
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
if (!res.ok) throw new Error(`Approve failed: ${res.status}`);
|
|
112
|
+
return res.json();
|
|
113
|
+
}
|
|
114
|
+
async ping() {
|
|
115
|
+
try {
|
|
116
|
+
await this.listDaemons();
|
|
117
|
+
return true;
|
|
118
|
+
} catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// src/tools/list-sessions.ts
|
|
125
|
+
var LIST_SESSIONS_TOOL = {
|
|
126
|
+
name: "list_sessions",
|
|
127
|
+
description: "List all currently connected IDE and CLI agent sessions on the local machine.",
|
|
128
|
+
inputSchema: {
|
|
129
|
+
type: "object",
|
|
130
|
+
properties: {},
|
|
131
|
+
required: []
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
async function listSessions(transport) {
|
|
135
|
+
if ("getStatus" in transport) {
|
|
136
|
+
const status = await transport.getStatus();
|
|
137
|
+
const sessions = status?.sessions ?? [];
|
|
138
|
+
if (sessions.length === 0) return "No active sessions.";
|
|
139
|
+
const lines2 = sessions.map((s) => {
|
|
140
|
+
const parts = [
|
|
141
|
+
`id: ${s.id}`,
|
|
142
|
+
`type: ${s.providerType ?? s.type ?? "unknown"}`
|
|
143
|
+
];
|
|
144
|
+
if (s.label) parts.push(`label: ${s.label}`);
|
|
145
|
+
if (s.agentStatus) parts.push(`status: ${s.agentStatus}`);
|
|
146
|
+
if (s.workspace) parts.push(`workspace: ${s.workspace}`);
|
|
147
|
+
return parts.join(", ");
|
|
148
|
+
});
|
|
149
|
+
return `Sessions (${sessions.length}):
|
|
150
|
+
${lines2.join("\n")}`;
|
|
151
|
+
}
|
|
152
|
+
const data = await transport.listDaemons();
|
|
153
|
+
const daemons = data?.daemons ?? data ?? [];
|
|
154
|
+
if (daemons.length === 0) return "No connected daemons.";
|
|
155
|
+
const lines = [];
|
|
156
|
+
for (const d of daemons) {
|
|
157
|
+
const sessions = d.sessions ?? [];
|
|
158
|
+
for (const s of sessions) {
|
|
159
|
+
lines.push(
|
|
160
|
+
`daemon: ${d.id}, session: ${s.id}, type: ${s.providerType ?? "unknown"}${s.agentStatus ? `, status: ${s.agentStatus}` : ""}`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
if (sessions.length === 0) {
|
|
164
|
+
lines.push(`daemon: ${d.id} (no sessions)`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return lines.length > 0 ? `Sessions:
|
|
168
|
+
${lines.join("\n")}` : "No active sessions.";
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/tools/read-chat.ts
|
|
172
|
+
var READ_CHAT_TOOL = {
|
|
173
|
+
name: "read_chat",
|
|
174
|
+
description: "Read the current chat conversation from an IDE agent session. Returns recent messages.",
|
|
175
|
+
inputSchema: {
|
|
176
|
+
type: "object",
|
|
177
|
+
properties: {
|
|
178
|
+
session_id: {
|
|
179
|
+
type: "string",
|
|
180
|
+
description: "Target session ID (from list_sessions). Omit to use the active session."
|
|
181
|
+
},
|
|
182
|
+
limit: {
|
|
183
|
+
type: "number",
|
|
184
|
+
description: "Max messages to return (default: 50)."
|
|
185
|
+
},
|
|
186
|
+
daemon_id: {
|
|
187
|
+
type: "string",
|
|
188
|
+
description: "Daemon ID (cloud mode only). Omit for local mode."
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
required: []
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
async function readChat(transport, args) {
|
|
195
|
+
const limit = args.limit ?? 50;
|
|
196
|
+
if ("command" in transport) {
|
|
197
|
+
const result2 = await transport.command("read_chat", {
|
|
198
|
+
...args.session_id ? { targetSessionId: args.session_id } : {},
|
|
199
|
+
limit
|
|
200
|
+
});
|
|
201
|
+
return formatChatResult(result2);
|
|
202
|
+
}
|
|
203
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
204
|
+
const targetId = args.session_id ? `${args.daemon_id}:session:${args.session_id}` : args.daemon_id;
|
|
205
|
+
const result = await transport.readChat(targetId, { limit, sessionId: args.session_id });
|
|
206
|
+
return formatChatResult(result);
|
|
207
|
+
}
|
|
208
|
+
function formatChatResult(result) {
|
|
209
|
+
if (!result?.success && result?.error) return `Error: ${result.error}`;
|
|
210
|
+
const messages = result?.messages ?? result?.data?.messages ?? [];
|
|
211
|
+
if (messages.length === 0) return "No messages in chat.";
|
|
212
|
+
const lines = messages.slice(-50).map((m) => {
|
|
213
|
+
const role = m.role === "user" ? "User" : m.role === "assistant" ? "Agent" : m.role;
|
|
214
|
+
const content = typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((p) => typeof p === "string" ? p : p?.text ?? "").join("") : "";
|
|
215
|
+
const truncated = content.length > 500 ? `${content.slice(0, 500)}\u2026` : content;
|
|
216
|
+
return `[${role}] ${truncated}`;
|
|
217
|
+
});
|
|
218
|
+
return lines.join("\n\n");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/tools/send-chat.ts
|
|
222
|
+
var SEND_CHAT_TOOL = {
|
|
223
|
+
name: "send_chat",
|
|
224
|
+
description: "Send a message to an IDE agent session.",
|
|
225
|
+
inputSchema: {
|
|
226
|
+
type: "object",
|
|
227
|
+
properties: {
|
|
228
|
+
message: {
|
|
229
|
+
type: "string",
|
|
230
|
+
description: "The message to send to the agent."
|
|
231
|
+
},
|
|
232
|
+
session_id: {
|
|
233
|
+
type: "string",
|
|
234
|
+
description: "Target session ID (from list_sessions). Omit to use the active session."
|
|
235
|
+
},
|
|
236
|
+
daemon_id: {
|
|
237
|
+
type: "string",
|
|
238
|
+
description: "Daemon ID (cloud mode only). Omit for local mode."
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
required: ["message"]
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
async function sendChat(transport, args) {
|
|
245
|
+
if (!args.message?.trim()) throw new Error("message is required");
|
|
246
|
+
if ("command" in transport) {
|
|
247
|
+
const result2 = await transport.command("send_chat", {
|
|
248
|
+
message: args.message,
|
|
249
|
+
...args.session_id ? { targetSessionId: args.session_id } : {}
|
|
250
|
+
});
|
|
251
|
+
if (result2?.success === false) return `Error: ${result2.error ?? "send_chat failed"}`;
|
|
252
|
+
return "Message sent.";
|
|
253
|
+
}
|
|
254
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
255
|
+
const targetId = args.session_id ? `${args.daemon_id}:session:${args.session_id}` : args.daemon_id;
|
|
256
|
+
const result = await transport.sendChat(targetId, args.message, {
|
|
257
|
+
...args.session_id ? { sessionId: args.session_id } : {}
|
|
258
|
+
});
|
|
259
|
+
if (result?.success === false) return `Error: ${result.error ?? "send_chat failed"}`;
|
|
260
|
+
return "Message sent.";
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// src/tools/approve.ts
|
|
264
|
+
var APPROVE_TOOL = {
|
|
265
|
+
name: "approve",
|
|
266
|
+
description: "Approve or reject a pending agent action (e.g. file write, command execution).",
|
|
267
|
+
inputSchema: {
|
|
268
|
+
type: "object",
|
|
269
|
+
properties: {
|
|
270
|
+
action: {
|
|
271
|
+
type: "string",
|
|
272
|
+
enum: ["approve", "reject"],
|
|
273
|
+
description: "Whether to approve or reject the pending action."
|
|
274
|
+
},
|
|
275
|
+
session_id: {
|
|
276
|
+
type: "string",
|
|
277
|
+
description: "Target session ID. Omit to use the active session."
|
|
278
|
+
},
|
|
279
|
+
daemon_id: {
|
|
280
|
+
type: "string",
|
|
281
|
+
description: "Daemon ID (cloud mode only)."
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
required: ["action"]
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
async function approve(transport, args) {
|
|
288
|
+
const action = args.action === "reject" ? "reject" : "approve";
|
|
289
|
+
if ("command" in transport) {
|
|
290
|
+
const result2 = await transport.command("resolve_action", {
|
|
291
|
+
action,
|
|
292
|
+
...args.session_id ? { targetSessionId: args.session_id } : {}
|
|
293
|
+
});
|
|
294
|
+
if (result2?.success === false) return `Error: ${result2.error ?? "resolve_action failed"}`;
|
|
295
|
+
return `Action ${action}d.`;
|
|
296
|
+
}
|
|
297
|
+
if (!args.daemon_id) throw new Error("daemon_id is required in cloud mode");
|
|
298
|
+
const targetId = args.session_id ? `${args.daemon_id}:session:${args.session_id}` : args.daemon_id;
|
|
299
|
+
const result = await transport.approve(targetId, action);
|
|
300
|
+
if (result?.success === false) return `Error: ${result.error ?? "approve failed"}`;
|
|
301
|
+
return `Action ${action}d.`;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/tools/screenshot.ts
|
|
305
|
+
var SCREENSHOT_TOOL = {
|
|
306
|
+
name: "screenshot",
|
|
307
|
+
description: "Capture a screenshot of the current IDE window. Returns the image.",
|
|
308
|
+
inputSchema: {
|
|
309
|
+
type: "object",
|
|
310
|
+
properties: {
|
|
311
|
+
session_id: {
|
|
312
|
+
type: "string",
|
|
313
|
+
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
|
+
}
|
|
319
|
+
},
|
|
320
|
+
required: []
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
async function screenshot(transport, args) {
|
|
324
|
+
let result;
|
|
325
|
+
if ("command" in transport) {
|
|
326
|
+
result = await transport.command("screenshot", {
|
|
327
|
+
...args.session_id ? { targetSessionId: args.session_id } : {}
|
|
328
|
+
});
|
|
329
|
+
} else {
|
|
330
|
+
return { type: "text", text: "Screenshots are not available in cloud mode. Run adhdev mcp in local mode (requires standalone daemon)." };
|
|
331
|
+
}
|
|
332
|
+
if (result?.success === false) {
|
|
333
|
+
return { type: "text", text: `Error: ${result.error ?? "screenshot failed"}` };
|
|
334
|
+
}
|
|
335
|
+
const b64 = result?.base64 ?? result?.screenshot ?? result?.result;
|
|
336
|
+
if (!b64) {
|
|
337
|
+
return { type: "text", text: "Screenshot captured but no image data returned." };
|
|
338
|
+
}
|
|
339
|
+
const mimeType = result?.format === "png" ? "image/png" : "image/webp";
|
|
340
|
+
return { type: "image", data: b64, mimeType };
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/tools/git-status.ts
|
|
344
|
+
var GIT_STATUS_TOOL = {
|
|
345
|
+
name: "git_status",
|
|
346
|
+
description: "Get git repository status for a workspace on the local machine (local mode only).",
|
|
347
|
+
inputSchema: {
|
|
348
|
+
type: "object",
|
|
349
|
+
properties: {
|
|
350
|
+
workspace: {
|
|
351
|
+
type: "string",
|
|
352
|
+
description: "Absolute path to the workspace/repository directory."
|
|
353
|
+
},
|
|
354
|
+
include_diff: {
|
|
355
|
+
type: "boolean",
|
|
356
|
+
description: "Include changed file list (default: true)."
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
required: ["workspace"]
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
async function gitStatus(transport, args) {
|
|
363
|
+
if (!("command" in transport)) {
|
|
364
|
+
return "git_status is only available in local mode.";
|
|
365
|
+
}
|
|
366
|
+
const statusResult = await transport.command("git_status", {
|
|
367
|
+
workspace: args.workspace
|
|
368
|
+
});
|
|
369
|
+
const status = statusResult?.status ?? statusResult;
|
|
370
|
+
if (statusResult?.success === false || status?.reason) {
|
|
371
|
+
return `Git error: ${statusResult?.error ?? status?.reason ?? "unknown"}`;
|
|
372
|
+
}
|
|
373
|
+
if (!status?.isGitRepo) return `Not a git repository: ${args.workspace}`;
|
|
374
|
+
const lines = [];
|
|
375
|
+
if (status.branch) lines.push(`Branch: ${status.branch}`);
|
|
376
|
+
if (status.headCommit) {
|
|
377
|
+
lines.push(`HEAD: ${status.headCommit.slice(0, 7)}${status.headMessage ? ` \u2014 ${status.headMessage.slice(0, 80)}` : ""}`);
|
|
378
|
+
}
|
|
379
|
+
if (status.ahead > 0) lines.push(`Ahead: ${status.ahead}`);
|
|
380
|
+
if (status.behind > 0) lines.push(`Behind: ${status.behind}`);
|
|
381
|
+
if (status.staged > 0) lines.push(`Staged: ${status.staged}`);
|
|
382
|
+
if (status.modified > 0) lines.push(`Modified: ${status.modified}`);
|
|
383
|
+
if (status.untracked > 0) lines.push(`Untracked: ${status.untracked}`);
|
|
384
|
+
if (status.deleted > 0) lines.push(`Deleted: ${status.deleted}`);
|
|
385
|
+
if (status.stashCount > 0) lines.push(`Stashes: ${status.stashCount}`);
|
|
386
|
+
if (status.hasConflicts) lines.push("Conflicts: YES");
|
|
387
|
+
if (!status.dirty) lines.push("Working tree: clean");
|
|
388
|
+
if (args.include_diff !== false) {
|
|
389
|
+
const diffResult = await transport.command("git_diff_summary", {
|
|
390
|
+
workspace: args.workspace
|
|
391
|
+
});
|
|
392
|
+
const diffSummary = diffResult?.diffSummary ?? diffResult;
|
|
393
|
+
if (diffSummary?.files?.length > 0) {
|
|
394
|
+
lines.push("");
|
|
395
|
+
lines.push(`Changed files (${diffSummary.files.length}):`);
|
|
396
|
+
for (const f of diffSummary.files.slice(0, 20)) {
|
|
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
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return lines.join("\n");
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// src/server.ts
|
|
409
|
+
async function startMcpServer(opts) {
|
|
410
|
+
const transport = opts.mode === "cloud" ? new CloudTransport({ apiKey: opts.apiKey, baseUrl: opts.baseUrl }) : new LocalTransport({ port: opts.port, password: opts.password });
|
|
411
|
+
const alive = await transport.ping();
|
|
412
|
+
if (!alive) {
|
|
413
|
+
const hint = opts.mode === "local" ? `Make sure the standalone daemon is running (adhdev standalone or npx @adhdev/daemon-standalone).` : `Check your API key and network connectivity.`;
|
|
414
|
+
process.stderr.write(`[adhdev-mcp] Cannot reach ${opts.mode} daemon. ${hint}
|
|
415
|
+
`);
|
|
416
|
+
process.exit(1);
|
|
417
|
+
}
|
|
418
|
+
const isLocal = opts.mode === "local";
|
|
419
|
+
const allTools = [
|
|
420
|
+
LIST_SESSIONS_TOOL,
|
|
421
|
+
READ_CHAT_TOOL,
|
|
422
|
+
SEND_CHAT_TOOL,
|
|
423
|
+
APPROVE_TOOL,
|
|
424
|
+
SCREENSHOT_TOOL,
|
|
425
|
+
...isLocal ? [GIT_STATUS_TOOL] : []
|
|
426
|
+
];
|
|
427
|
+
const server = new import_server.Server(
|
|
428
|
+
{ name: "adhdev-mcp-server", version: "0.9.59" },
|
|
429
|
+
{ capabilities: { tools: {} } }
|
|
430
|
+
);
|
|
431
|
+
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => ({ tools: allTools }));
|
|
432
|
+
server.setRequestHandler(import_types.CallToolRequestSchema, async (req) => {
|
|
433
|
+
const { name, arguments: args } = req.params;
|
|
434
|
+
const a = args ?? {};
|
|
435
|
+
try {
|
|
436
|
+
switch (name) {
|
|
437
|
+
case "list_sessions": {
|
|
438
|
+
const text = await listSessions(transport);
|
|
439
|
+
return { content: [{ type: "text", text }] };
|
|
440
|
+
}
|
|
441
|
+
case "read_chat": {
|
|
442
|
+
const text = await readChat(transport, a);
|
|
443
|
+
return { content: [{ type: "text", text }] };
|
|
444
|
+
}
|
|
445
|
+
case "send_chat": {
|
|
446
|
+
const text = await sendChat(transport, { message: a.message, session_id: a.session_id, daemon_id: a.daemon_id });
|
|
447
|
+
return { content: [{ type: "text", text }] };
|
|
448
|
+
}
|
|
449
|
+
case "approve": {
|
|
450
|
+
const action = a.action === "reject" ? "reject" : "approve";
|
|
451
|
+
const text = await approve(transport, { action, session_id: a.session_id, daemon_id: a.daemon_id });
|
|
452
|
+
return { content: [{ type: "text", text }] };
|
|
453
|
+
}
|
|
454
|
+
case "screenshot": {
|
|
455
|
+
const result = await screenshot(transport, { session_id: a.session_id, daemon_id: a.daemon_id });
|
|
456
|
+
if (result.type === "image") {
|
|
457
|
+
return {
|
|
458
|
+
content: [{ type: "image", data: result.data, mimeType: result.mimeType }]
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
return { content: [{ type: "text", text: result.text }] };
|
|
462
|
+
}
|
|
463
|
+
case "git_status": {
|
|
464
|
+
const text = await gitStatus(transport, { workspace: a.workspace, include_diff: a.include_diff });
|
|
465
|
+
return { content: [{ type: "text", text }] };
|
|
466
|
+
}
|
|
467
|
+
default:
|
|
468
|
+
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
469
|
+
}
|
|
470
|
+
} catch (err) {
|
|
471
|
+
return {
|
|
472
|
+
content: [{ type: "text", text: `Error: ${err?.message ?? String(err)}` }],
|
|
473
|
+
isError: true
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
const stdioTransport = new import_stdio.StdioServerTransport();
|
|
478
|
+
await server.connect(stdioTransport);
|
|
479
|
+
process.stderr.write(`[adhdev-mcp] Server running in ${opts.mode} mode.
|
|
480
|
+
`);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/index.ts
|
|
484
|
+
function parseArgs(argv) {
|
|
485
|
+
const args = argv.slice(2);
|
|
486
|
+
let apiKey;
|
|
487
|
+
let baseUrl;
|
|
488
|
+
let port;
|
|
489
|
+
let password;
|
|
490
|
+
for (let i = 0; i < args.length; i++) {
|
|
491
|
+
const arg = args[i];
|
|
492
|
+
if ((arg === "--api-key" || arg === "-k") && args[i + 1]) {
|
|
493
|
+
apiKey = args[++i];
|
|
494
|
+
} else if (arg?.startsWith("--api-key=")) {
|
|
495
|
+
apiKey = arg.slice("--api-key=".length);
|
|
496
|
+
} else if (arg === "--base-url" && args[i + 1]) {
|
|
497
|
+
baseUrl = args[++i];
|
|
498
|
+
} else if (arg === "--port" && args[i + 1]) {
|
|
499
|
+
port = Number(args[++i]);
|
|
500
|
+
} else if (arg?.startsWith("--port=")) {
|
|
501
|
+
port = Number(arg.slice("--port=".length));
|
|
502
|
+
} else if (arg === "--password" && args[i + 1]) {
|
|
503
|
+
password = args[++i];
|
|
504
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
505
|
+
printHelp();
|
|
506
|
+
process.exit(0);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
if (!apiKey && process.env.ADHDEV_API_KEY) apiKey = process.env.ADHDEV_API_KEY;
|
|
510
|
+
if (!password && process.env.ADHDEV_PASSWORD) password = process.env.ADHDEV_PASSWORD;
|
|
511
|
+
const mode = apiKey ? "cloud" : "local";
|
|
512
|
+
return { mode, port, password, apiKey, baseUrl };
|
|
513
|
+
}
|
|
514
|
+
function printHelp() {
|
|
515
|
+
console.error(`
|
|
516
|
+
adhdev-mcp \u2014 ADHDev MCP Server
|
|
517
|
+
|
|
518
|
+
Usage:
|
|
519
|
+
adhdev-mcp Local mode (requires standalone daemon)
|
|
520
|
+
adhdev-mcp --api-key <key> Cloud mode (ADHDev cloud API)
|
|
521
|
+
|
|
522
|
+
Options:
|
|
523
|
+
--port <n> Standalone daemon port (default: 3847)
|
|
524
|
+
--password <pass> Standalone daemon password (if set)
|
|
525
|
+
--api-key <key> ADHDev cloud API key (switches to cloud mode)
|
|
526
|
+
--base-url <url> Override cloud API base URL
|
|
527
|
+
--help Show this help
|
|
528
|
+
|
|
529
|
+
Environment variables:
|
|
530
|
+
ADHDEV_API_KEY API key (cloud mode)
|
|
531
|
+
ADHDEV_PASSWORD Daemon password (local mode)
|
|
532
|
+
|
|
533
|
+
Local mode tools: list_sessions, read_chat, send_chat, approve, screenshot, git_status
|
|
534
|
+
Cloud mode tools: list_sessions, read_chat, send_chat, approve
|
|
535
|
+
`.trim());
|
|
536
|
+
}
|
|
537
|
+
startMcpServer(parseArgs(process.argv)).catch((err) => {
|
|
538
|
+
process.stderr.write(`[adhdev-mcp] Fatal: ${err?.message ?? err}
|
|
539
|
+
`);
|
|
540
|
+
process.exit(1);
|
|
541
|
+
});
|
|
542
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/transports/local.ts","../src/transports/cloud.ts","../src/tools/list-sessions.ts","../src/tools/read-chat.ts","../src/tools/send-chat.ts","../src/tools/approve.ts","../src/tools/screenshot.ts","../src/tools/git-status.ts","../src/index.ts"],"sourcesContent":["/**\n * ADHDev MCP Server\n *\n * Exposes IDE agent sessions as MCP tools via stdio transport.\n * Two modes:\n * local — talks to standalone daemon at localhost:3847\n * cloud — talks to ADHDev cloud API with an API key\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\n\nimport { LocalTransport } from './transports/local.js';\nimport { CloudTransport } from './transports/cloud.js';\n\nimport { LIST_SESSIONS_TOOL, listSessions } from './tools/list-sessions.js';\nimport { READ_CHAT_TOOL, readChat } from './tools/read-chat.js';\nimport { SEND_CHAT_TOOL, sendChat } from './tools/send-chat.js';\nimport { APPROVE_TOOL, approve } from './tools/approve.js';\nimport { SCREENSHOT_TOOL, screenshot } from './tools/screenshot.js';\nimport { GIT_STATUS_TOOL, gitStatus } from './tools/git-status.js';\n\nexport interface AdhdevMcpServerOptions {\n mode: 'local' | 'cloud';\n // local options\n port?: number;\n password?: string;\n // cloud options\n apiKey?: string;\n baseUrl?: string;\n}\n\nexport async function startMcpServer(opts: AdhdevMcpServerOptions): Promise<void> {\n const transport =\n opts.mode === 'cloud'\n ? new CloudTransport({ apiKey: opts.apiKey!, baseUrl: opts.baseUrl })\n : new LocalTransport({ port: opts.port, password: opts.password });\n\n // Verify connectivity before registering tools\n const alive = await transport.ping();\n if (!alive) {\n const hint =\n opts.mode === 'local'\n ? `Make sure the standalone daemon is running (adhdev standalone or npx @adhdev/daemon-standalone).`\n : `Check your API key and network connectivity.`;\n process.stderr.write(`[adhdev-mcp] Cannot reach ${opts.mode} daemon. ${hint}\\n`);\n process.exit(1);\n }\n\n const isLocal = opts.mode === 'local';\n\n const allTools = [\n LIST_SESSIONS_TOOL,\n READ_CHAT_TOOL,\n SEND_CHAT_TOOL,\n APPROVE_TOOL,\n SCREENSHOT_TOOL,\n ...(isLocal ? [GIT_STATUS_TOOL] : []),\n ];\n\n const server = new Server(\n { name: 'adhdev-mcp-server', version: '0.9.59' },\n { capabilities: { tools: {} } },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: allTools }));\n\n server.setRequestHandler(CallToolRequestSchema, async (req) => {\n const { name, arguments: args } = req.params;\n const a = (args ?? {}) as Record<string, any>;\n\n try {\n switch (name) {\n case 'list_sessions': {\n const text = await listSessions(transport);\n return { content: [{ type: 'text', text }] };\n }\n case 'read_chat': {\n const text = await readChat(transport, a);\n return { content: [{ type: 'text', text }] };\n }\n case 'send_chat': {\n const text = await sendChat(transport, { message: a.message, session_id: a.session_id, daemon_id: a.daemon_id });\n return { content: [{ type: 'text', text }] };\n }\n case 'approve': {\n const action = a.action === 'reject' ? 'reject' : 'approve';\n const text = await approve(transport, { action, session_id: a.session_id, daemon_id: a.daemon_id });\n return { content: [{ type: 'text', text }] };\n }\n case 'screenshot': {\n const result = await screenshot(transport, { session_id: a.session_id, daemon_id: a.daemon_id });\n if (result.type === 'image') {\n return {\n content: [{ type: 'image', data: result.data, mimeType: result.mimeType }],\n };\n }\n return { content: [{ type: 'text', text: result.text }] };\n }\n case 'git_status': {\n const text = await gitStatus(transport, { workspace: a.workspace, include_diff: a.include_diff });\n return { content: [{ type: 'text', text }] };\n }\n default:\n return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };\n }\n } catch (err: any) {\n return {\n content: [{ type: 'text', text: `Error: ${err?.message ?? String(err)}` }],\n isError: true,\n };\n }\n });\n\n const stdioTransport = new StdioServerTransport();\n await server.connect(stdioTransport);\n process.stderr.write(`[adhdev-mcp] Server running in ${opts.mode} mode.\\n`);\n}\n","/**\n * LocalTransport — HTTP client for standalone daemon at localhost:3847\n */\n\nconst DEFAULT_PORT = 3847;\n\nexport interface LocalTransportOptions {\n port?: number;\n password?: string;\n}\n\nexport class LocalTransport {\n private baseUrl: string;\n private authHeader: string | null;\n\n constructor(opts: LocalTransportOptions = {}) {\n this.baseUrl = `http://localhost:${opts.port ?? DEFAULT_PORT}`;\n this.authHeader = opts.password ? `Bearer ${opts.password}` : null;\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.authHeader) h['Authorization'] = this.authHeader;\n return h;\n }\n\n async getStatus(): Promise<any> {\n const res = await fetch(`${this.baseUrl}/api/v1/status`, { headers: this.headers() });\n if (!res.ok) throw new Error(`Status fetch failed: ${res.status}`);\n return res.json();\n }\n\n async command(type: string, args: Record<string, unknown> = {}): Promise<any> {\n const res = await fetch(`${this.baseUrl}/api/v1/command`, {\n method: 'POST',\n headers: this.headers(),\n body: JSON.stringify({ type, ...args }),\n });\n if (!res.ok) {\n const text = await res.text().catch(() => res.statusText);\n throw new Error(`Command ${type} failed: ${res.status} ${text}`);\n }\n return res.json();\n }\n\n async ping(): Promise<boolean> {\n try {\n await this.getStatus();\n return true;\n } catch {\n return false;\n }\n }\n}\n","/**\n * CloudTransport — HTTP client for ADHDev cloud API (api.adhf.dev)\n *\n * Uses shortcuts API: /api/v1/shortcuts/:targetId/*\n * Requires an API key (adk_*) with appropriate scopes.\n */\n\nconst DEFAULT_BASE_URL = 'https://api.adhf.dev';\n\nexport interface CloudTransportOptions {\n apiKey: string;\n baseUrl?: string;\n}\n\nexport class CloudTransport {\n private baseUrl: string;\n private apiKey: string;\n\n constructor(opts: CloudTransportOptions) {\n this.apiKey = opts.apiKey;\n this.baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;\n }\n\n private headers(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n };\n }\n\n async listDaemons(): Promise<any> {\n const res = await fetch(`${this.baseUrl}/api/v1/daemons`, { headers: this.headers() });\n if (!res.ok) throw new Error(`List daemons failed: ${res.status}`);\n return res.json();\n }\n\n async getStatus(targetId: string): Promise<any> {\n const res = await fetch(\n `${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(targetId)}/status`,\n { headers: this.headers() },\n );\n if (!res.ok) throw new Error(`Status failed: ${res.status}`);\n return res.json();\n }\n\n async readChat(targetId: string, opts: { limit?: number; sessionId?: string } = {}): Promise<any> {\n const params = new URLSearchParams();\n if (opts.limit) params.set('limit', String(opts.limit));\n if (opts.sessionId) params.set('sessionId', opts.sessionId);\n const qs = params.toString() ? `?${params}` : '';\n const res = await fetch(\n `${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(targetId)}/chat${qs}`,\n { headers: this.headers() },\n );\n if (!res.ok) throw new Error(`Read chat failed: ${res.status}`);\n return res.json();\n }\n\n async sendChat(targetId: string, message: string, opts: { sessionId?: string; ideType?: string } = {}): Promise<any> {\n const res = await fetch(\n `${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(targetId)}/chat`,\n {\n method: 'POST',\n headers: this.headers(),\n body: JSON.stringify({ message, ...opts }),\n },\n );\n if (!res.ok) throw new Error(`Send chat failed: ${res.status}`);\n return res.json();\n }\n\n async approve(targetId: string, action: 'approve' | 'reject', agentType?: string): Promise<any> {\n const res = await fetch(\n `${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(targetId)}/approve`,\n {\n method: 'POST',\n headers: this.headers(),\n body: JSON.stringify({ action, ...(agentType ? { agentType } : {}) }),\n },\n );\n if (!res.ok) throw new Error(`Approve failed: ${res.status}`);\n return res.json();\n }\n\n async ping(): Promise<boolean> {\n try {\n await this.listDaemons();\n return true;\n } catch {\n return false;\n }\n }\n}\n","import type { LocalTransport } from '../transports/local.js';\nimport type { CloudTransport } from '../transports/cloud.js';\n\nexport const LIST_SESSIONS_TOOL = {\n name: 'list_sessions',\n description: 'List all currently connected IDE and CLI agent sessions on the local machine.',\n inputSchema: {\n type: 'object' as const,\n properties: {},\n required: [],\n },\n};\n\nexport async function listSessions(transport: LocalTransport | CloudTransport): Promise<string> {\n if ('getStatus' in transport) {\n // LocalTransport\n const status = await (transport as LocalTransport).getStatus();\n const sessions: any[] = status?.sessions ?? [];\n if (sessions.length === 0) return 'No active sessions.';\n\n const lines = sessions.map((s: any) => {\n const parts = [\n `id: ${s.id}`,\n `type: ${s.providerType ?? s.type ?? 'unknown'}`,\n ];\n if (s.label) parts.push(`label: ${s.label}`);\n if (s.agentStatus) parts.push(`status: ${s.agentStatus}`);\n if (s.workspace) parts.push(`workspace: ${s.workspace}`);\n return parts.join(', ');\n });\n return `Sessions (${sessions.length}):\\n${lines.join('\\n')}`;\n }\n\n // CloudTransport\n const data = await (transport as CloudTransport).listDaemons();\n const daemons: any[] = data?.daemons ?? data ?? [];\n if (daemons.length === 0) return 'No connected daemons.';\n\n const lines: string[] = [];\n for (const d of daemons) {\n const sessions: any[] = d.sessions ?? [];\n for (const s of sessions) {\n lines.push(\n `daemon: ${d.id}, session: ${s.id}, type: ${s.providerType ?? 'unknown'}${s.agentStatus ? `, status: ${s.agentStatus}` : ''}`,\n );\n }\n if (sessions.length === 0) {\n lines.push(`daemon: ${d.id} (no sessions)`);\n }\n }\n return lines.length > 0 ? `Sessions:\\n${lines.join('\\n')}` : 'No active sessions.';\n}\n","import type { LocalTransport } from '../transports/local.js';\nimport type { CloudTransport } from '../transports/cloud.js';\n\nexport const READ_CHAT_TOOL = {\n name: 'read_chat',\n description: 'Read the current chat conversation from an IDE agent session. Returns recent messages.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n session_id: {\n type: 'string',\n description: 'Target session ID (from list_sessions). Omit to use the active session.',\n },\n limit: {\n type: 'number',\n description: 'Max messages to return (default: 50).',\n },\n daemon_id: {\n type: 'string',\n description: 'Daemon ID (cloud mode only). Omit for local mode.',\n },\n },\n required: [],\n },\n};\n\nexport async function readChat(\n transport: LocalTransport | CloudTransport,\n args: { session_id?: string; limit?: number; daemon_id?: string },\n): Promise<string> {\n const limit = args.limit ?? 50;\n\n if ('command' in transport) {\n // LocalTransport\n const result = await (transport as LocalTransport).command('read_chat', {\n ...(args.session_id ? { targetSessionId: args.session_id } : {}),\n limit,\n });\n return formatChatResult(result);\n }\n\n // CloudTransport\n if (!args.daemon_id) throw new Error('daemon_id is required in cloud mode');\n const targetId = args.session_id ? `${args.daemon_id}:session:${args.session_id}` : args.daemon_id;\n const result = await (transport as CloudTransport).readChat(targetId, { limit, sessionId: args.session_id });\n return formatChatResult(result);\n}\n\nfunction formatChatResult(result: any): string {\n if (!result?.success && result?.error) return `Error: ${result.error}`;\n\n const messages: any[] = result?.messages ?? result?.data?.messages ?? [];\n if (messages.length === 0) return 'No messages in chat.';\n\n const lines = messages.slice(-50).map((m: any) => {\n const role = m.role === 'user' ? 'User' : m.role === 'assistant' ? 'Agent' : m.role;\n const content = typeof m.content === 'string'\n ? m.content\n : Array.isArray(m.content)\n ? m.content.map((p: any) => (typeof p === 'string' ? p : p?.text ?? '')).join('')\n : '';\n const truncated = content.length > 500 ? `${content.slice(0, 500)}…` : content;\n return `[${role}] ${truncated}`;\n });\n\n return lines.join('\\n\\n');\n}\n","import type { LocalTransport } from '../transports/local.js';\nimport type { CloudTransport } from '../transports/cloud.js';\n\nexport const SEND_CHAT_TOOL = {\n name: 'send_chat',\n description: 'Send a message to an IDE agent session.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n message: {\n type: 'string',\n description: 'The message to send to the agent.',\n },\n session_id: {\n type: 'string',\n description: 'Target session ID (from list_sessions). Omit to use the active session.',\n },\n daemon_id: {\n type: 'string',\n description: 'Daemon ID (cloud mode only). Omit for local mode.',\n },\n },\n required: ['message'],\n },\n};\n\nexport async function sendChat(\n transport: LocalTransport | CloudTransport,\n args: { message: string; session_id?: string; daemon_id?: string },\n): Promise<string> {\n if (!args.message?.trim()) throw new Error('message is required');\n\n if ('command' in transport) {\n // LocalTransport\n const result = await (transport as LocalTransport).command('send_chat', {\n message: args.message,\n ...(args.session_id ? { targetSessionId: args.session_id } : {}),\n });\n if (result?.success === false) return `Error: ${result.error ?? 'send_chat failed'}`;\n return 'Message sent.';\n }\n\n // CloudTransport\n if (!args.daemon_id) throw new Error('daemon_id is required in cloud mode');\n const targetId = args.session_id ? `${args.daemon_id}:session:${args.session_id}` : args.daemon_id;\n const result = await (transport as CloudTransport).sendChat(targetId, args.message, {\n ...(args.session_id ? { sessionId: args.session_id } : {}),\n });\n if (result?.success === false) return `Error: ${result.error ?? 'send_chat failed'}`;\n return 'Message sent.';\n}\n","import type { LocalTransport } from '../transports/local.js';\nimport type { CloudTransport } from '../transports/cloud.js';\n\nexport const APPROVE_TOOL = {\n name: 'approve',\n description: 'Approve or reject a pending agent action (e.g. file write, command execution).',\n inputSchema: {\n type: 'object' as const,\n properties: {\n action: {\n type: 'string',\n enum: ['approve', 'reject'],\n description: 'Whether to approve or reject the pending action.',\n },\n session_id: {\n type: 'string',\n description: 'Target session ID. Omit to use the active session.',\n },\n daemon_id: {\n type: 'string',\n description: 'Daemon ID (cloud mode only).',\n },\n },\n required: ['action'],\n },\n};\n\nexport async function approve(\n transport: LocalTransport | CloudTransport,\n args: { action: 'approve' | 'reject'; session_id?: string; daemon_id?: string },\n): Promise<string> {\n const action = args.action === 'reject' ? 'reject' : 'approve';\n\n if ('command' in transport) {\n // LocalTransport\n const result = await (transport as LocalTransport).command('resolve_action', {\n action,\n ...(args.session_id ? { targetSessionId: args.session_id } : {}),\n });\n if (result?.success === false) return `Error: ${result.error ?? 'resolve_action failed'}`;\n return `Action ${action}d.`;\n }\n\n // CloudTransport\n if (!args.daemon_id) throw new Error('daemon_id is required in cloud mode');\n const targetId = args.session_id ? `${args.daemon_id}:session:${args.session_id}` : args.daemon_id;\n const result = await (transport as CloudTransport).approve(targetId, action);\n if (result?.success === false) return `Error: ${result.error ?? 'approve failed'}`;\n return `Action ${action}d.`;\n}\n","import type { LocalTransport } from '../transports/local.js';\nimport type { CloudTransport } from '../transports/cloud.js';\n\nexport const SCREENSHOT_TOOL = {\n name: 'screenshot',\n description: 'Capture a screenshot of the current IDE window. Returns the image.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n session_id: {\n type: 'string',\n description: 'Target session ID. Omit to use the active session.',\n },\n daemon_id: {\n type: 'string',\n description: 'Daemon ID (cloud mode only).',\n },\n },\n required: [],\n },\n};\n\nexport async function screenshot(\n transport: LocalTransport | CloudTransport,\n args: { session_id?: string; daemon_id?: string },\n): Promise<{ type: 'image'; data: string; mimeType: string } | { type: 'text'; text: string }> {\n let result: any;\n\n if ('command' in transport) {\n result = await (transport as LocalTransport).command('screenshot', {\n ...(args.session_id ? { targetSessionId: args.session_id } : {}),\n });\n } else {\n // CloudTransport: use shortcuts status endpoint — screenshot not on shortcuts, fall back to error\n return { type: 'text', text: 'Screenshots are not available in cloud mode. Run adhdev mcp in local mode (requires standalone daemon).' };\n }\n\n if (result?.success === false) {\n return { type: 'text', text: `Error: ${result.error ?? 'screenshot failed'}` };\n }\n\n const b64: string | undefined = result?.base64 ?? result?.screenshot ?? result?.result;\n if (!b64) {\n return { type: 'text', text: 'Screenshot captured but no image data returned.' };\n }\n\n const mimeType = result?.format === 'png' ? 'image/png' : 'image/webp';\n return { type: 'image', data: b64, mimeType };\n}\n","import type { LocalTransport } from '../transports/local.js';\nimport type { CloudTransport } from '../transports/cloud.js';\n\nexport const GIT_STATUS_TOOL = {\n name: 'git_status',\n description: 'Get git repository status for a workspace on the local machine (local mode only).',\n inputSchema: {\n type: 'object' as const,\n properties: {\n workspace: {\n type: 'string',\n description: 'Absolute path to the workspace/repository directory.',\n },\n include_diff: {\n type: 'boolean',\n description: 'Include changed file list (default: true).',\n },\n },\n required: ['workspace'],\n },\n};\n\nexport async function gitStatus(\n transport: LocalTransport | CloudTransport,\n args: { workspace: string; include_diff?: boolean },\n): Promise<string> {\n if (!('command' in transport)) {\n return 'git_status is only available in local mode.';\n }\n\n const statusResult = await (transport as LocalTransport).command('git_status', {\n workspace: args.workspace,\n });\n\n const status = statusResult?.status ?? statusResult;\n if (statusResult?.success === false || status?.reason) {\n return `Git error: ${statusResult?.error ?? status?.reason ?? 'unknown'}`;\n }\n\n if (!status?.isGitRepo) return `Not a git repository: ${args.workspace}`;\n\n const lines: string[] = [];\n if (status.branch) lines.push(`Branch: ${status.branch}`);\n if (status.headCommit) {\n lines.push(`HEAD: ${status.headCommit.slice(0, 7)}${status.headMessage ? ` — ${status.headMessage.slice(0, 80)}` : ''}`);\n }\n if (status.ahead > 0) lines.push(`Ahead: ${status.ahead}`);\n if (status.behind > 0) lines.push(`Behind: ${status.behind}`);\n if (status.staged > 0) lines.push(`Staged: ${status.staged}`);\n if (status.modified > 0) lines.push(`Modified: ${status.modified}`);\n if (status.untracked > 0) lines.push(`Untracked: ${status.untracked}`);\n if (status.deleted > 0) lines.push(`Deleted: ${status.deleted}`);\n if (status.stashCount > 0) lines.push(`Stashes: ${status.stashCount}`);\n if (status.hasConflicts) lines.push('Conflicts: YES');\n if (!status.dirty) lines.push('Working tree: clean');\n\n if (args.include_diff !== false) {\n const diffResult = await (transport as LocalTransport).command('git_diff_summary', {\n workspace: args.workspace,\n });\n const diffSummary = diffResult?.diffSummary ?? diffResult;\n if (diffSummary?.files?.length > 0) {\n lines.push('');\n lines.push(`Changed files (${diffSummary.files.length}):`);\n for (const f of diffSummary.files.slice(0, 20)) {\n lines.push(` ${f.status ?? 'M'} ${f.path}${f.oldPath ? ` (was ${f.oldPath})` : ''}${f.insertions || f.deletions ? ` +${f.insertions ?? 0}/-${f.deletions ?? 0}` : ''}`);\n }\n if (diffSummary.files.length > 20) lines.push(` … and ${diffSummary.files.length - 20} more`);\n if (diffSummary.totalInsertions || diffSummary.totalDeletions) {\n lines.push(`Total: +${diffSummary.totalInsertions ?? 0}/-${diffSummary.totalDeletions ?? 0}`);\n }\n }\n }\n\n return lines.join('\\n');\n}\n","/**\n * @adhdev/mcp-server — CLI entry point\n *\n * Usage:\n * npx @adhdev/mcp-server # local mode (localhost:3847)\n * npx @adhdev/mcp-server --port 4000 # custom port\n * npx @adhdev/mcp-server --api-key adk_xxx # cloud mode\n */\n\nimport { startMcpServer } from './server.js';\n\nfunction parseArgs(argv: string[]): {\n mode: 'local' | 'cloud';\n port?: number;\n password?: string;\n apiKey?: string;\n baseUrl?: string;\n} {\n const args = argv.slice(2);\n let apiKey: string | undefined;\n let baseUrl: string | undefined;\n let port: number | undefined;\n let password: string | undefined;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if ((arg === '--api-key' || arg === '-k') && args[i + 1]) {\n apiKey = args[++i];\n } else if (arg?.startsWith('--api-key=')) {\n apiKey = arg.slice('--api-key='.length);\n } else if (arg === '--base-url' && args[i + 1]) {\n baseUrl = args[++i];\n } else if (arg === '--port' && args[i + 1]) {\n port = Number(args[++i]);\n } else if (arg?.startsWith('--port=')) {\n port = Number(arg.slice('--port='.length));\n } else if (arg === '--password' && args[i + 1]) {\n password = args[++i];\n } else if (arg === '--help' || arg === '-h') {\n printHelp();\n process.exit(0);\n }\n }\n\n // Also accept env vars\n if (!apiKey && process.env.ADHDEV_API_KEY) apiKey = process.env.ADHDEV_API_KEY;\n if (!password && process.env.ADHDEV_PASSWORD) password = process.env.ADHDEV_PASSWORD;\n\n const mode = apiKey ? 'cloud' : 'local';\n return { mode, port, password, apiKey, baseUrl };\n}\n\nfunction printHelp(): void {\n console.error(`\nadhdev-mcp — ADHDev MCP Server\n\nUsage:\n adhdev-mcp Local mode (requires standalone daemon)\n adhdev-mcp --api-key <key> Cloud mode (ADHDev cloud API)\n\nOptions:\n --port <n> Standalone daemon port (default: 3847)\n --password <pass> Standalone daemon password (if set)\n --api-key <key> ADHDev cloud API key (switches to cloud mode)\n --base-url <url> Override cloud API base URL\n --help Show this help\n\nEnvironment variables:\n ADHDEV_API_KEY API key (cloud mode)\n ADHDEV_PASSWORD Daemon password (local mode)\n\nLocal mode tools: list_sessions, read_chat, send_chat, approve, screenshot, git_status\nCloud mode tools: list_sessions, read_chat, send_chat, approve\n`.trim());\n}\n\nstartMcpServer(parseArgs(process.argv)).catch((err) => {\n process.stderr.write(`[adhdev-mcp] Fatal: ${err?.message ?? err}\\n`);\n process.exit(1);\n});\n"],"mappings":"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","names":["lines","result","result","result"]}
|