@anastops/mcp-server 1.1.2 → 2.0.0

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.
Files changed (45) hide show
  1. package/dist/handlers/handlers.base.d.ts +20 -4
  2. package/dist/handlers/handlers.base.d.ts.map +1 -1
  3. package/dist/handlers/handlers.base.js +32 -17
  4. package/dist/handlers/handlers.base.js.map +1 -1
  5. package/dist/handlers/index.d.ts +1 -1
  6. package/dist/handlers/index.d.ts.map +1 -1
  7. package/dist/handlers/index.js +84 -100
  8. package/dist/handlers/index.js.map +1 -1
  9. package/dist/handlers/tool-definitions.d.ts +701 -1673
  10. package/dist/handlers/tool-definitions.d.ts.map +1 -1
  11. package/dist/handlers/tool-definitions.js +459 -402
  12. package/dist/handlers/tool-definitions.js.map +1 -1
  13. package/dist/handlers/types.d.ts +1 -0
  14. package/dist/handlers/types.d.ts.map +1 -1
  15. package/dist/handlers/v3/agent-tools.d.ts +280 -0
  16. package/dist/handlers/v3/agent-tools.d.ts.map +1 -0
  17. package/dist/handlers/v3/agent-tools.js +460 -0
  18. package/dist/handlers/v3/agent-tools.js.map +1 -0
  19. package/dist/handlers/v3/index.d.ts +31 -0
  20. package/dist/handlers/v3/index.d.ts.map +1 -0
  21. package/dist/handlers/v3/index.js +56 -0
  22. package/dist/handlers/v3/index.js.map +1 -0
  23. package/dist/handlers/v3/routing-integration-example.d.ts +258 -0
  24. package/dist/handlers/v3/routing-integration-example.d.ts.map +1 -0
  25. package/dist/handlers/v3/routing-integration-example.js +454 -0
  26. package/dist/handlers/v3/routing-integration-example.js.map +1 -0
  27. package/dist/handlers/v3/routing-middleware.d.ts +191 -0
  28. package/dist/handlers/v3/routing-middleware.d.ts.map +1 -0
  29. package/dist/handlers/v3/routing-middleware.js +425 -0
  30. package/dist/handlers/v3/routing-middleware.js.map +1 -0
  31. package/dist/handlers/v3/session-tools.d.ts +269 -0
  32. package/dist/handlers/v3/session-tools.d.ts.map +1 -0
  33. package/dist/handlers/v3/session-tools.js +716 -0
  34. package/dist/handlers/v3/session-tools.js.map +1 -0
  35. package/dist/handlers/v3/task-tools.d.ts +18 -0
  36. package/dist/handlers/v3/task-tools.d.ts.map +1 -0
  37. package/dist/handlers/v3/task-tools.js +916 -0
  38. package/dist/handlers/v3/task-tools.js.map +1 -0
  39. package/dist/handlers/v3/utility-tools.d.ts +99 -0
  40. package/dist/handlers/v3/utility-tools.d.ts.map +1 -0
  41. package/dist/handlers/v3/utility-tools.js +878 -0
  42. package/dist/handlers/v3/utility-tools.js.map +1 -0
  43. package/dist/index.js +9 -1
  44. package/dist/index.js.map +1 -1
  45. package/package.json +1 -1
@@ -0,0 +1,716 @@
1
+ /**
2
+ * MCP v3.0 Session Management Tools
3
+ * Consolidated session management following aggressive consolidation plan
4
+ *
5
+ * Tools:
6
+ * - session_manage: Create, fork, archive, delete operations
7
+ * - session_query: Status, list, report query operations
8
+ * - session_queue_config: Configure and query queue settings
9
+ *
10
+ * @see docs/MCP-V3-AGGRESSIVE-CONSOLIDATION.md
11
+ */
12
+ import { SessionManager, SessionForkService, addBreadcrumb, } from '@anastops/core';
13
+ import { getPersistence } from '../../persistence.js';
14
+ import { safePersist, formatSessionReport, tasks, agents, artifacts } from '../handlers.base.js';
15
+ // Shared instances
16
+ const sessionManager = new SessionManager();
17
+ const forkService = new SessionForkService(sessionManager);
18
+ // ============================================================================
19
+ // TOOL SCHEMAS
20
+ // ============================================================================
21
+ /**
22
+ * session_manage tool schema
23
+ *
24
+ * Handles create, fork, archive, and delete operations on sessions.
25
+ *
26
+ * @example Create a new session
27
+ * ```typescript
28
+ * session_manage({
29
+ * operation: 'create',
30
+ * objective: 'Build authentication system',
31
+ * concurrency: 3,
32
+ * auto_execute: true
33
+ * })
34
+ * ```
35
+ *
36
+ * @example Fork a session
37
+ * ```typescript
38
+ * session_manage({
39
+ * operation: 'fork',
40
+ * session_id: 'abc123',
41
+ * reason: 'Explore OAuth approach'
42
+ * })
43
+ * ```
44
+ *
45
+ * @example Archive a session
46
+ * ```typescript
47
+ * session_manage({
48
+ * operation: 'archive',
49
+ * session_id: 'abc123'
50
+ * })
51
+ * ```
52
+ *
53
+ * @example Delete a session
54
+ * ```typescript
55
+ * session_manage({
56
+ * operation: 'delete',
57
+ * session_id: 'abc123',
58
+ * confirm: true
59
+ * })
60
+ * ```
61
+ */
62
+ export const sessionManageSchema = {
63
+ name: 'session_manage',
64
+ description: 'Manage sessions: create new sessions, fork existing sessions, archive completed sessions, or delete sessions permanently',
65
+ inputSchema: {
66
+ type: 'object',
67
+ properties: {
68
+ operation: {
69
+ type: 'string',
70
+ enum: ['create', 'fork', 'archive', 'delete'],
71
+ description: 'Operation to perform: create=spawn new session, fork=create alternative branch, archive=mark completed, delete=permanently remove',
72
+ },
73
+ // CREATE operation parameters
74
+ objective: {
75
+ type: 'string',
76
+ description: 'Required for create: High-level objective for the session',
77
+ },
78
+ context_files: {
79
+ type: 'array',
80
+ items: { type: 'string' },
81
+ description: 'For create: Array of file paths to include in session context',
82
+ },
83
+ parent_session: {
84
+ type: 'string',
85
+ description: 'For create: Parent session ID if this is a child session',
86
+ },
87
+ concurrency: {
88
+ type: 'number',
89
+ description: 'For create: Max concurrent running tasks (1-10, default: 1)',
90
+ },
91
+ auto_execute: {
92
+ type: 'boolean',
93
+ description: 'For create: Auto-execute queued tasks when slots available (default: false)',
94
+ },
95
+ // FORK operation parameters
96
+ session_id: {
97
+ type: 'string',
98
+ description: 'Required for fork/archive/delete: Session ID to operate on',
99
+ },
100
+ fork_point: {
101
+ type: 'number',
102
+ description: 'For fork: Task number to fork from (optional)',
103
+ },
104
+ reason: {
105
+ type: 'string',
106
+ description: 'For fork: Reason for forking (e.g., "Explore OAuth approach")',
107
+ },
108
+ // DELETE operation parameters
109
+ session_ids: {
110
+ type: 'array',
111
+ items: { type: 'string' },
112
+ description: 'For delete: Array of session IDs to delete (bulk deletion)',
113
+ },
114
+ status: {
115
+ type: 'string',
116
+ enum: ['active', 'completed', 'archived'],
117
+ description: 'For delete: Delete all sessions with this status',
118
+ },
119
+ older_than_days: {
120
+ type: 'number',
121
+ description: 'For delete: Delete sessions older than N days',
122
+ },
123
+ confirm: {
124
+ type: 'boolean',
125
+ description: 'Required for delete: Must be true to execute deletion (safety check)',
126
+ },
127
+ },
128
+ required: ['operation'],
129
+ },
130
+ };
131
+ /**
132
+ * session_query tool schema
133
+ *
134
+ * Queries session information: get status, list sessions, or generate reports.
135
+ *
136
+ * @example Get session status
137
+ * ```typescript
138
+ * session_query({
139
+ * operation: 'status',
140
+ * session_id: 'abc123'
141
+ * })
142
+ * ```
143
+ *
144
+ * @example List active sessions
145
+ * ```typescript
146
+ * session_query({
147
+ * operation: 'list',
148
+ * status_filter: 'active',
149
+ * format: 'table'
150
+ * })
151
+ * ```
152
+ *
153
+ * @example Generate session report
154
+ * ```typescript
155
+ * session_query({
156
+ * operation: 'report',
157
+ * session_id: 'abc123',
158
+ * include_output: true,
159
+ * include_artifacts: false
160
+ * })
161
+ * ```
162
+ */
163
+ export const sessionQuerySchema = {
164
+ name: 'session_query',
165
+ description: 'Query session information: get status for a specific session, list all sessions with filters, or generate comprehensive reports',
166
+ inputSchema: {
167
+ type: 'object',
168
+ properties: {
169
+ operation: {
170
+ type: 'string',
171
+ enum: ['status', 'list', 'report'],
172
+ description: 'Type of query: status=get session details, list=list sessions with filters, report=generate comprehensive report',
173
+ },
174
+ // STATUS operation parameters
175
+ session_id: {
176
+ type: 'string',
177
+ description: 'Required for status: Session ID to query. Optional for report: omit to get all sessions',
178
+ },
179
+ // LIST operation parameters
180
+ status_filter: {
181
+ type: 'string',
182
+ enum: ['active', 'completed', 'archived'],
183
+ description: 'For list/report: Filter sessions by status',
184
+ },
185
+ include_forks: {
186
+ type: 'boolean',
187
+ description: 'For list: Include forked sessions in results (default: false)',
188
+ },
189
+ limit: {
190
+ type: 'number',
191
+ description: 'For list/report: Maximum number of sessions to return (default: 20 for report)',
192
+ },
193
+ format: {
194
+ type: 'string',
195
+ enum: ['table', 'json'],
196
+ description: 'For list: Output format (table=ASCII table, json=raw JSON, default: json)',
197
+ },
198
+ // REPORT operation parameters
199
+ include_output: {
200
+ type: 'boolean',
201
+ description: 'For report: Include full task output content (default: true)',
202
+ },
203
+ include_artifacts: {
204
+ type: 'boolean',
205
+ description: 'For report: Include artifact content, not just metadata (default: false)',
206
+ },
207
+ },
208
+ required: ['operation'],
209
+ },
210
+ };
211
+ /**
212
+ * session_queue_config tool schema
213
+ *
214
+ * Configure queue settings or query queue status for a session.
215
+ *
216
+ * @example Configure queue settings
217
+ * ```typescript
218
+ * session_queue_config({
219
+ * operation: 'configure',
220
+ * session_id: 'abc123',
221
+ * concurrency: 5,
222
+ * auto_execute: true
223
+ * })
224
+ * ```
225
+ *
226
+ * @example Query queue status
227
+ * ```typescript
228
+ * session_queue_config({
229
+ * operation: 'status',
230
+ * session_id: 'abc123'
231
+ * })
232
+ * ```
233
+ */
234
+ export const sessionQueueConfigSchema = {
235
+ name: 'session_queue_config',
236
+ description: 'Configure session queue settings (concurrency, auto-execution) or query queue status (running/queued counts, available slots)',
237
+ inputSchema: {
238
+ type: 'object',
239
+ properties: {
240
+ operation: {
241
+ type: 'string',
242
+ enum: ['configure', 'status'],
243
+ description: 'Operation: configure=update queue settings, status=get queue status and ready tasks',
244
+ },
245
+ session_id: {
246
+ type: 'string',
247
+ description: 'Required: Session ID to configure or query',
248
+ },
249
+ // CONFIGURE operation parameters
250
+ concurrency: {
251
+ type: 'number',
252
+ description: 'For configure: Max concurrent running tasks (1-10)',
253
+ },
254
+ auto_execute: {
255
+ type: 'boolean',
256
+ description: 'For configure: Auto-execute queued tasks when slots available',
257
+ },
258
+ },
259
+ required: ['operation', 'session_id'],
260
+ },
261
+ };
262
+ // ============================================================================
263
+ // HANDLER IMPLEMENTATIONS
264
+ // ============================================================================
265
+ /**
266
+ * Validates operation-specific required fields
267
+ * Throws error if required fields are missing for the operation
268
+ */
269
+ function validateSessionManageArgs(operation, args) {
270
+ switch (operation) {
271
+ case 'create':
272
+ if (typeof args['objective'] !== 'string' || args['objective'] === '') {
273
+ throw new Error('operation=create requires: objective (string)');
274
+ }
275
+ break;
276
+ case 'fork':
277
+ if (typeof args['session_id'] !== 'string' || args['session_id'] === '') {
278
+ throw new Error('operation=fork requires: session_id (string)');
279
+ }
280
+ break;
281
+ case 'archive':
282
+ if (typeof args['session_id'] !== 'string' || args['session_id'] === '') {
283
+ throw new Error('operation=archive requires: session_id (string)');
284
+ }
285
+ break;
286
+ case 'delete': {
287
+ if (args['confirm'] !== true) {
288
+ throw new Error('operation=delete requires: confirm=true (safety check)');
289
+ }
290
+ // Must provide at least one filter: session_id, session_ids, status, or older_than_days
291
+ const hasFilter = (typeof args['session_id'] === 'string' && args['session_id'] !== '') ||
292
+ (Array.isArray(args['session_ids']) && args['session_ids'].length > 0) ||
293
+ (typeof args['status'] === 'string' && args['status'] !== '') ||
294
+ typeof args['older_than_days'] === 'number';
295
+ if (!hasFilter) {
296
+ throw new Error('operation=delete requires at least one filter: session_id, session_ids, status, or older_than_days');
297
+ }
298
+ break;
299
+ }
300
+ default:
301
+ throw new Error(`Unknown operation: ${operation}`);
302
+ }
303
+ }
304
+ function validateSessionQueryArgs(operation, args) {
305
+ switch (operation) {
306
+ case 'status':
307
+ if (typeof args['session_id'] !== 'string' || args['session_id'] === '') {
308
+ throw new Error('operation=status requires: session_id (string)');
309
+ }
310
+ break;
311
+ case 'list':
312
+ // No required fields for list - all optional
313
+ break;
314
+ case 'report':
315
+ // session_id is optional for report (omit to get all sessions)
316
+ break;
317
+ default:
318
+ throw new Error(`Unknown operation: ${operation}`);
319
+ }
320
+ }
321
+ function validateQueueConfigArgs(operation, args) {
322
+ // session_id is always required (enforced in schema)
323
+ if (typeof args['session_id'] !== 'string' || args['session_id'] === '') {
324
+ throw new Error('session_id (string) is required');
325
+ }
326
+ switch (operation) {
327
+ case 'configure':
328
+ // Validate concurrency if provided
329
+ if (args['concurrency'] !== undefined) {
330
+ const concurrency = args['concurrency'];
331
+ if (concurrency < 1 || concurrency > 10) {
332
+ throw new Error('concurrency must be between 1 and 10');
333
+ }
334
+ }
335
+ break;
336
+ case 'status':
337
+ // No additional validation needed
338
+ break;
339
+ default:
340
+ throw new Error(`Unknown operation: ${operation}`);
341
+ }
342
+ }
343
+ /**
344
+ * session_manage handler
345
+ * Routes to appropriate handler based on operation parameter
346
+ */
347
+ export async function handleSessionManage(args) {
348
+ const operation = args['operation'];
349
+ // Validate operation-specific required fields
350
+ validateSessionManageArgs(operation, args);
351
+ switch (operation) {
352
+ case 'create':
353
+ return handleSessionCreate(args);
354
+ case 'fork':
355
+ return handleSessionFork(args);
356
+ case 'archive':
357
+ return handleSessionArchive(args);
358
+ case 'delete':
359
+ return handleSessionDelete(args);
360
+ default:
361
+ throw new Error(`Unknown operation: ${operation}`);
362
+ }
363
+ }
364
+ /**
365
+ * session_query handler
366
+ * Routes to appropriate handler based on operation parameter
367
+ */
368
+ export async function handleSessionQuery(args) {
369
+ const operation = args['operation'];
370
+ // Validate operation-specific required fields
371
+ validateSessionQueryArgs(operation, args);
372
+ switch (operation) {
373
+ case 'status':
374
+ return handleSessionStatus(args);
375
+ case 'list':
376
+ return handleSessionList(args);
377
+ case 'report':
378
+ return handleSessionReport(args);
379
+ default:
380
+ throw new Error(`Unknown operation: ${operation}`);
381
+ }
382
+ }
383
+ /**
384
+ * session_queue_config handler
385
+ * Routes to configure or status operation
386
+ */
387
+ export async function handleSessionQueueConfig(args) {
388
+ const operation = args['operation'];
389
+ // Validate operation-specific required fields
390
+ validateQueueConfigArgs(operation, args);
391
+ switch (operation) {
392
+ case 'configure':
393
+ return handleQueueConfigure(args);
394
+ case 'status':
395
+ return handleQueueStatus(args);
396
+ default:
397
+ throw new Error(`Unknown operation: ${operation}`);
398
+ }
399
+ }
400
+ // ============================================================================
401
+ // OPERATION IMPLEMENTATIONS
402
+ // ============================================================================
403
+ /**
404
+ * Create a new session
405
+ */
406
+ function handleSessionCreate(args) {
407
+ const objective = args['objective'];
408
+ addBreadcrumb('Creating session', { objective }, 'info', 'session');
409
+ const session = sessionManager.spawn({
410
+ objective,
411
+ ...(args['context_files'] !== undefined && {
412
+ context_files: args['context_files'],
413
+ }),
414
+ ...(args['parent_session'] !== undefined && {
415
+ parent_session: args['parent_session'],
416
+ }),
417
+ ...(args['concurrency'] !== undefined && {
418
+ concurrency: args['concurrency'],
419
+ }),
420
+ ...(args['auto_execute'] !== undefined && {
421
+ auto_execute: args['auto_execute'],
422
+ }),
423
+ });
424
+ addBreadcrumb('Session created', { session_id: session.id }, 'info', 'session');
425
+ // Persist to MongoDB
426
+ safePersist(getPersistence().saveSession(session));
427
+ return Promise.resolve({
428
+ session_id: session.id,
429
+ objective: session.objective,
430
+ status: session.status,
431
+ queue_config: session.queue_config,
432
+ });
433
+ }
434
+ /**
435
+ * Fork an existing session
436
+ */
437
+ function handleSessionFork(args) {
438
+ const sessionId = args['session_id'];
439
+ const reason = args['reason'] ?? 'unknown';
440
+ addBreadcrumb('Forking session', { session_id: sessionId, reason }, 'info', 'session');
441
+ const forked = forkService.fork({
442
+ session_id: sessionId,
443
+ ...(args['fork_point'] !== undefined && {
444
+ fork_point: args['fork_point'],
445
+ }),
446
+ ...(args['reason'] !== undefined && { reason }),
447
+ });
448
+ addBreadcrumb('Session forked', { forked_session_id: forked.id, parent_id: forked.parent_session_id }, 'info', 'session');
449
+ // Persist to MongoDB
450
+ safePersist(getPersistence().saveSession(forked));
451
+ return Promise.resolve({
452
+ forked_session_id: forked.id,
453
+ parent_id: forked.parent_session_id,
454
+ fork_point: forked.fork_point,
455
+ });
456
+ }
457
+ /**
458
+ * Archive a session
459
+ */
460
+ function handleSessionArchive(args) {
461
+ const sessionId = args['session_id'];
462
+ const session = sessionManager.updateStatus(sessionId, 'archived');
463
+ // Persist to MongoDB
464
+ safePersist(getPersistence().saveSession(session));
465
+ return Promise.resolve({
466
+ session_id: session.id,
467
+ status: session.status,
468
+ });
469
+ }
470
+ /**
471
+ * Delete session(s) permanently
472
+ */
473
+ async function handleSessionDelete(args) {
474
+ const sessionId = args['session_id'];
475
+ const sessionIds = args['session_ids'];
476
+ const statusFilter = args['status'];
477
+ const olderThanDays = args['older_than_days'];
478
+ const persistence = getPersistence();
479
+ // Single session deletion
480
+ if (sessionId !== undefined && sessionId !== '') {
481
+ // Remove from in-memory cache
482
+ sessionManager.remove(sessionId);
483
+ // Remove related tasks from cache
484
+ for (const [taskId, task] of tasks.entries()) {
485
+ if (task.session_id === sessionId) {
486
+ tasks.delete(taskId);
487
+ }
488
+ }
489
+ // Remove related agents from cache
490
+ for (const [agentId, agent] of agents.entries()) {
491
+ if (agent.session_id === sessionId) {
492
+ agents.delete(agentId);
493
+ }
494
+ }
495
+ // Remove related artifacts from cache
496
+ for (const [artifactId, artifact] of artifacts.entries()) {
497
+ if (artifact.session_id === sessionId) {
498
+ artifacts.delete(artifactId);
499
+ }
500
+ }
501
+ const deleted = await persistence.deleteSession(sessionId);
502
+ return { deleted: deleted, session_id: sessionId };
503
+ }
504
+ // Build filters for bulk deletion
505
+ const filters = {};
506
+ if (sessionIds !== undefined && sessionIds.length > 0) {
507
+ filters.session_ids = sessionIds;
508
+ }
509
+ if (statusFilter !== undefined && statusFilter !== '') {
510
+ filters.status = statusFilter;
511
+ }
512
+ if (olderThanDays !== undefined) {
513
+ const cutoffDate = new Date();
514
+ cutoffDate.setDate(cutoffDate.getDate() - olderThanDays);
515
+ filters.older_than = cutoffDate;
516
+ }
517
+ const result = await persistence.deleteSessions(filters);
518
+ // Clean up in-memory caches for deleted sessions
519
+ for (const deletedId of result.session_ids) {
520
+ sessionManager.remove(deletedId);
521
+ for (const [taskId, task] of tasks.entries()) {
522
+ if (task.session_id === deletedId) {
523
+ tasks.delete(taskId);
524
+ }
525
+ }
526
+ for (const [agentId, agent] of agents.entries()) {
527
+ if (agent.session_id === deletedId) {
528
+ agents.delete(agentId);
529
+ }
530
+ }
531
+ for (const [artifactId, artifact] of artifacts.entries()) {
532
+ if (artifact.session_id === deletedId) {
533
+ artifacts.delete(artifactId);
534
+ }
535
+ }
536
+ }
537
+ return {
538
+ deleted_count: result.deleted_count,
539
+ session_ids: result.session_ids,
540
+ };
541
+ }
542
+ /**
543
+ * Get session status
544
+ */
545
+ function handleSessionStatus(args) {
546
+ const sessionId = args['session_id'];
547
+ const status = sessionManager.getStatus(sessionId);
548
+ // TOON encoding applied in handleToolCall
549
+ return Promise.resolve(status);
550
+ }
551
+ /**
552
+ * List sessions with filters
553
+ */
554
+ async function handleSessionList(args) {
555
+ // Get from in-memory first
556
+ const inMemorySessions = sessionManager.list({
557
+ ...(args['status_filter'] !== undefined && {
558
+ status: args['status_filter'],
559
+ }),
560
+ ...(args['include_forks'] !== undefined && {
561
+ include_forks: args['include_forks'],
562
+ }),
563
+ ...(args['limit'] !== undefined && {
564
+ limit: args['limit'],
565
+ }),
566
+ });
567
+ // Also get from MongoDB for persistence
568
+ const persistedSessions = await getPersistence().listSessions({
569
+ ...(args['status_filter'] !== undefined && {
570
+ status: args['status_filter'],
571
+ }),
572
+ ...(args['limit'] !== undefined && {
573
+ limit: args['limit'],
574
+ }),
575
+ });
576
+ // Merge: in-memory takes precedence, then add persisted ones not in memory
577
+ const inMemoryIds = new Set(inMemorySessions.map((s) => s.id));
578
+ const sessions = [
579
+ ...inMemorySessions,
580
+ ...persistedSessions.filter((s) => !inMemoryIds.has(s.id)),
581
+ ];
582
+ // Return raw result for table formatting to be applied in handleToolCall
583
+ const result = {
584
+ count: sessions.length,
585
+ sessions: sessions.map((s) => ({
586
+ id: s.id,
587
+ objective: s.objective,
588
+ status: s.status,
589
+ created_at: s.created_at,
590
+ })),
591
+ };
592
+ // Don't apply TOON encoding here - let handleToolCall handle formatting
593
+ return result;
594
+ }
595
+ /**
596
+ * Generate session report
597
+ */
598
+ async function handleSessionReport(args) {
599
+ const sessionId = args['session_id'];
600
+ const statusFilter = args['status_filter'];
601
+ const includeOutput = args['include_output'] ?? true;
602
+ const includeArtifactContent = args['include_artifacts'] ?? false;
603
+ const limit = args['limit'] ?? 20;
604
+ const persistence = getPersistence();
605
+ if (sessionId !== undefined && sessionId !== '') {
606
+ // Single session report
607
+ const report = await persistence.getSessionReport(sessionId);
608
+ if (report === null) {
609
+ throw new Error(`Session not found: ${sessionId}`);
610
+ }
611
+ return formatSessionReport(report, includeOutput, includeArtifactContent);
612
+ }
613
+ // All sessions report
614
+ const reportFilters = { limit };
615
+ if (statusFilter !== undefined) {
616
+ reportFilters.status = statusFilter;
617
+ }
618
+ const reports = await persistence.getAllSessionReports(reportFilters);
619
+ return {
620
+ total_sessions: reports.length,
621
+ sessions: reports.map((r) => formatSessionReport(r, includeOutput, includeArtifactContent)),
622
+ };
623
+ }
624
+ /**
625
+ * Configure queue settings
626
+ */
627
+ function handleQueueConfigure(args) {
628
+ const sessionId = args['session_id'];
629
+ const concurrency = args['concurrency'];
630
+ const autoExecute = args['auto_execute'];
631
+ // Build updates object
632
+ const updates = {};
633
+ if (concurrency !== undefined) {
634
+ updates.concurrency = concurrency;
635
+ }
636
+ if (autoExecute !== undefined) {
637
+ updates.auto_execute = autoExecute;
638
+ }
639
+ if (Object.keys(updates).length === 0) {
640
+ // No updates provided, just return current config
641
+ const session = sessionManager.getSession(sessionId);
642
+ return Promise.resolve({
643
+ session_id: sessionId,
644
+ queue_config: session.queue_config,
645
+ });
646
+ }
647
+ // Update queue config
648
+ const session = sessionManager.updateQueueConfig(sessionId, updates);
649
+ safePersist(getPersistence().saveSession(session));
650
+ return Promise.resolve({
651
+ session_id: sessionId,
652
+ queue_config: session.queue_config,
653
+ updated: true,
654
+ });
655
+ }
656
+ /**
657
+ * Get queue status
658
+ */
659
+ async function handleQueueStatus(args) {
660
+ const sessionId = args['session_id'];
661
+ const session = sessionManager.getSession(sessionId);
662
+ // Get tasks for the session
663
+ const sessionTasks = [];
664
+ for (const [, task] of tasks.entries()) {
665
+ if (task.session_id === sessionId) {
666
+ sessionTasks.push(task);
667
+ }
668
+ }
669
+ // Also get from MongoDB
670
+ const persistedTasks = await getPersistence().listTasks({ session_id: sessionId });
671
+ const inMemoryIds = new Set(sessionTasks.map((t) => t.id));
672
+ const allTasks = [...sessionTasks, ...persistedTasks.filter((t) => !inMemoryIds.has(t.id))];
673
+ // Count by status
674
+ const runningCount = allTasks.filter((t) => t.status === 'running').length;
675
+ const queuedCount = allTasks.filter((t) => t.status === 'queued').length;
676
+ const pendingCount = allTasks.filter((t) => t.status === 'pending').length;
677
+ const completedCount = allTasks.filter((t) => t.status === 'completed').length;
678
+ const failedCount = allTasks.filter((t) => t.status === 'failed').length;
679
+ const availableSlots = Math.max(0, session.queue_config.concurrency - runningCount);
680
+ // Find ready tasks (queued with met dependencies)
681
+ const queuedTasks = allTasks.filter((t) => t.status === 'queued');
682
+ const taskMap = new Map(allTasks.map((t) => [t.id, t]));
683
+ const readyTasks = queuedTasks
684
+ .filter((task) => {
685
+ if (task.dependencies.length === 0)
686
+ return true;
687
+ return task.dependencies.every((depId) => {
688
+ const depTask = taskMap.get(depId);
689
+ return depTask !== undefined && depTask.status === 'completed';
690
+ });
691
+ })
692
+ .sort((a, b) => {
693
+ // Sort by priority (higher first), then by created_at (earlier first)
694
+ if (a.priority !== b.priority)
695
+ return b.priority - a.priority;
696
+ return a.created_at.getTime() - b.created_at.getTime();
697
+ })
698
+ .slice(0, availableSlots)
699
+ .map((t) => t.id);
700
+ return {
701
+ session_id: sessionId,
702
+ queue_config: session.queue_config,
703
+ running_count: runningCount,
704
+ queued_count: queuedCount,
705
+ pending_count: pendingCount,
706
+ completed_count: completedCount,
707
+ failed_count: failedCount,
708
+ available_slots: availableSlots,
709
+ ready_tasks: readyTasks,
710
+ };
711
+ }
712
+ // ============================================================================
713
+ // EXPORTS
714
+ // ============================================================================
715
+ export { sessionManager, forkService };
716
+ //# sourceMappingURL=session-tools.js.map