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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adhdev",
3
- "version": "0.9.59",
3
+ "version": "0.9.61",
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": {
@@ -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 currently connected IDE and CLI agent sessions on the local machine.",
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 lines2 = sessions.map((s) => {
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
- ${lines2.join("\n")}`;
202
+ ${lines.join("\n")}`;
151
203
  }
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
- );
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
- if (sessions.length === 0) {
164
- lines.push(`daemon: ${d.id} (no sessions)`);
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
- return lines.length > 0 ? `Sessions:
168
- ${lines.join("\n")}` : "No active sessions.";
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) return `Error: ${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 local machine (local mode only).",
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
- 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"}`;
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 (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
- }
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
- SCREENSHOT_TOOL,
425
- ...isLocal ? [GIT_STATUS_TOOL] : []
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.59" },
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, daemon_id: a.daemon_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, screenshot, git_status
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) => {