@anastops/mcp-server 1.1.2 → 2.0.1

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 (57) 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 +5 -4
  6. package/dist/handlers/index.d.ts.map +1 -1
  7. package/dist/handlers/index.js +126 -135
  8. package/dist/handlers/index.js.map +1 -1
  9. package/dist/handlers/tool-definitions.d.ts +1016 -1564
  10. package/dist/handlers/tool-definitions.d.ts.map +1 -1
  11. package/dist/handlers/tool-definitions.js +617 -388
  12. package/dist/handlers/tool-definitions.js.map +1 -1
  13. package/dist/handlers/types.d.ts +34 -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 +303 -0
  32. package/dist/handlers/v3/session-tools.d.ts.map +1 -0
  33. package/dist/handlers/v3/session-tools.js +945 -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 +1947 -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/handlers.d.ts +1 -1
  44. package/dist/handlers.d.ts.map +1 -1
  45. package/dist/handlers.js +1 -1
  46. package/dist/handlers.js.map +1 -1
  47. package/dist/index.js +12 -2
  48. package/dist/index.js.map +1 -1
  49. package/dist/persistence.d.ts +11 -0
  50. package/dist/persistence.d.ts.map +1 -1
  51. package/dist/persistence.js +77 -0
  52. package/dist/persistence.js.map +1 -1
  53. package/dist/schemas.d.ts +95 -8
  54. package/dist/schemas.d.ts.map +1 -1
  55. package/dist/schemas.js +97 -2
  56. package/dist/schemas.js.map +1 -1
  57. package/package.json +3 -3
@@ -0,0 +1,878 @@
1
+ /**
2
+ * Anastops MCP v3.0 - Consolidated Utility and Data Management Tools
3
+ *
4
+ * This module implements the aggressive consolidation plan for v3.0:
5
+ * - Data tools: 6 → 2 (data_manage, data_query)
6
+ * - Utility tools: 3 → 1 (system_query)
7
+ * - Lock tools: 3 → 1 (lock_manage)
8
+ * - Monitoring tools: 3 → 1 (session_monitoring)
9
+ * - Config tools: 2 → 1 (config_manage)
10
+ *
11
+ * Total reduction: 17 tools → 6 tools (65% reduction)
12
+ */
13
+ import { nanoid } from 'nanoid';
14
+ import { getArtifact, safePersist } from '../utils.js';
15
+ /* ========================================================================
16
+ * DATA MANAGEMENT TOOLS (2 tools)
17
+ * Consolidates: memory_store, memory_retrieve, artifact_save, artifact_get,
18
+ * artifact_list, context_optimize
19
+ * ======================================================================== */
20
+ /**
21
+ * Data Management Tool - Write Operations
22
+ *
23
+ * Handles all data write operations:
24
+ * - store: Store data in memory (replaces memory_store)
25
+ * - save: Save artifact (replaces artifact_save)
26
+ * - optimize: Optimize context for token reduction (replaces context_optimize)
27
+ */
28
+ export const dataManageTool = {
29
+ name: 'data_manage',
30
+ description: 'Manage data operations: store memory, save artifacts, or optimize context. Use operation="store" for memory storage, operation="save" for artifact creation, operation="optimize" for context token reduction.',
31
+ inputSchema: {
32
+ type: 'object',
33
+ properties: {
34
+ operation: {
35
+ type: 'string',
36
+ enum: ['store', 'save', 'optimize'],
37
+ description: 'Operation type: store=memory storage, save=artifact creation, optimize=context optimization',
38
+ },
39
+ // For memory_store operation
40
+ key: {
41
+ type: 'string',
42
+ description: 'For store operation: memory key to store value under',
43
+ },
44
+ value: {
45
+ description: 'For store operation: value to store (any JSON-serializable type)',
46
+ },
47
+ // For artifact_save operation
48
+ session_id: {
49
+ type: 'string',
50
+ description: 'Required for save/optimize operations: session ID',
51
+ },
52
+ artifact_type: {
53
+ type: 'string',
54
+ enum: ['code', 'document', 'data', 'config', 'test', 'other'],
55
+ description: 'For save operation: artifact type classification',
56
+ },
57
+ name: {
58
+ type: 'string',
59
+ description: 'For save operation: artifact name/filename',
60
+ },
61
+ content: {
62
+ type: 'string',
63
+ description: 'For save operation: artifact content',
64
+ },
65
+ // For context_optimize operation
66
+ objective: {
67
+ type: 'string',
68
+ description: 'For optimize operation: session objective for context optimization',
69
+ },
70
+ phase: {
71
+ type: 'string',
72
+ description: 'For optimize operation: current phase of work',
73
+ },
74
+ progress: {
75
+ type: 'number',
76
+ description: 'For optimize operation: progress percentage (0-1)',
77
+ },
78
+ messages: {
79
+ type: 'array',
80
+ description: 'For optimize operation: messages to optimize',
81
+ },
82
+ },
83
+ required: ['operation'],
84
+ },
85
+ };
86
+ /**
87
+ * Data Query Tool - Read Operations
88
+ *
89
+ * Handles all data read operations:
90
+ * - retrieve: Retrieve data from memory (replaces memory_retrieve)
91
+ * - get: Get single artifact by ID (replaces artifact_get)
92
+ * - list: List all artifacts for session (replaces artifact_list)
93
+ */
94
+ export const dataQueryTool = {
95
+ name: 'data_query',
96
+ description: 'Query data: retrieve memory, get artifacts, or list artifacts. Use operation="retrieve" for memory lookup, operation="get" for single artifact, operation="list" for all session artifacts.',
97
+ inputSchema: {
98
+ type: 'object',
99
+ properties: {
100
+ operation: {
101
+ type: 'string',
102
+ enum: ['retrieve', 'get', 'list'],
103
+ description: 'Operation type: retrieve=memory lookup, get=single artifact, list=all artifacts',
104
+ },
105
+ // For memory_retrieve operation
106
+ key: {
107
+ type: 'string',
108
+ description: 'For retrieve operation: memory key to lookup',
109
+ },
110
+ // For artifact_get operation
111
+ artifact_id: {
112
+ type: 'string',
113
+ description: 'For get operation: artifact ID to retrieve',
114
+ },
115
+ // For artifact_list operation
116
+ session_id: {
117
+ type: 'string',
118
+ description: 'Required for list operation: session ID to list artifacts from',
119
+ },
120
+ artifact_type: {
121
+ type: 'string',
122
+ enum: ['code', 'document', 'data', 'config', 'test', 'other'],
123
+ description: 'For list operation: optional filter by artifact type',
124
+ },
125
+ },
126
+ required: ['operation'],
127
+ },
128
+ };
129
+ /* ========================================================================
130
+ * UTILITY TOOLS (4 tools)
131
+ * Consolidates system utilities, locks, monitoring, and config
132
+ * ======================================================================== */
133
+ /**
134
+ * System Query Tool
135
+ *
136
+ * Handles all system-level query operations:
137
+ * - health: Check system health (replaces health_check)
138
+ * - providers: List available AI providers (replaces provider_list)
139
+ * - metrics: Get system metrics (replaces metrics_get)
140
+ */
141
+ export const systemQueryTool = {
142
+ name: 'system_query',
143
+ description: 'Query system information: health status, available providers, or system metrics. Use operation="health" for health checks, operation="providers" for provider list, operation="metrics" for system metrics.',
144
+ inputSchema: {
145
+ type: 'object',
146
+ properties: {
147
+ operation: {
148
+ type: 'string',
149
+ enum: ['health', 'providers', 'metrics'],
150
+ description: 'Operation type: health=system health, providers=available providers, metrics=system metrics',
151
+ },
152
+ // For health_check operation
153
+ include_providers: {
154
+ type: 'boolean',
155
+ description: 'For health operation: include provider status in health check',
156
+ },
157
+ // For provider_list operation
158
+ filter_healthy: {
159
+ type: 'boolean',
160
+ description: 'For providers operation: only show healthy providers',
161
+ },
162
+ include_capabilities: {
163
+ type: 'boolean',
164
+ description: 'For providers operation: include provider capabilities',
165
+ },
166
+ // For metrics_get operation
167
+ metric_type: {
168
+ type: 'string',
169
+ enum: ['routing', 'tokens', 'costs', 'all'],
170
+ description: 'For metrics operation: type of metrics to retrieve',
171
+ },
172
+ },
173
+ },
174
+ };
175
+ /**
176
+ * Lock Management Tool
177
+ *
178
+ * Handles all file lock operations:
179
+ * - acquire: Acquire a file lock (replaces lock_acquire)
180
+ * - release: Release a file lock (replaces lock_release)
181
+ * - status: Check lock status (replaces lock_status)
182
+ */
183
+ export const lockManageTool = {
184
+ name: 'lock_manage',
185
+ description: 'Manage file locks: acquire, release, or check status. Use operation="acquire" to lock a file, operation="release" to unlock, operation="status" to check lock state.',
186
+ inputSchema: {
187
+ type: 'object',
188
+ properties: {
189
+ operation: {
190
+ type: 'string',
191
+ enum: ['acquire', 'release', 'status'],
192
+ description: 'Operation type: acquire=lock file, release=unlock file, status=check lock',
193
+ },
194
+ session_id: {
195
+ type: 'string',
196
+ description: 'Required for acquire/release, optional for status: session ID',
197
+ },
198
+ file_path: {
199
+ type: 'string',
200
+ description: 'Required for acquire/release, optional for status: file path to lock',
201
+ },
202
+ ttl: {
203
+ type: 'number',
204
+ description: 'For acquire operation: lock TTL in milliseconds (default: 300000)',
205
+ },
206
+ },
207
+ required: ['operation'],
208
+ },
209
+ };
210
+ /**
211
+ * Session Monitoring Tool
212
+ *
213
+ * Handles all session monitoring operations:
214
+ * - cost: Get cost breakdown (replaces session_cost)
215
+ * - metrics: Get request/token metrics (replaces session_metrics)
216
+ * - throttle: Check rate limit status (replaces session_throttle)
217
+ */
218
+ export const sessionMonitoringTool = {
219
+ name: 'session_monitoring',
220
+ description: 'Monitor session activity: cost breakdown, token metrics, or rate limits. Use operation="cost" for costs, operation="metrics" for token usage, operation="throttle" for rate limits.',
221
+ inputSchema: {
222
+ type: 'object',
223
+ properties: {
224
+ operation: {
225
+ type: 'string',
226
+ enum: ['cost', 'metrics', 'throttle'],
227
+ description: 'Operation type: cost=cost breakdown, metrics=token usage, throttle=rate limits',
228
+ },
229
+ session_id: {
230
+ type: 'string',
231
+ description: 'Required for all operations: session ID to monitor',
232
+ },
233
+ provider: {
234
+ type: 'string',
235
+ description: 'For throttle operation: specific provider to check',
236
+ },
237
+ },
238
+ required: ['operation', 'session_id'],
239
+ },
240
+ };
241
+ /**
242
+ * Configuration Management Tool
243
+ *
244
+ * Handles all configuration operations:
245
+ * - get: Get configuration value (replaces config_get)
246
+ * - set: Set configuration value (replaces config_set)
247
+ */
248
+ export const configManageTool = {
249
+ name: 'config_manage',
250
+ description: 'Manage configuration: get or set values. Use operation="get" to retrieve config, operation="set" to update config.',
251
+ inputSchema: {
252
+ type: 'object',
253
+ properties: {
254
+ operation: {
255
+ type: 'string',
256
+ enum: ['get', 'set'],
257
+ description: 'Operation type: get=retrieve value, set=update value',
258
+ },
259
+ key: {
260
+ type: 'string',
261
+ description: 'Required for both operations: configuration key',
262
+ },
263
+ value: {
264
+ description: 'Required for set operation: value to set (any JSON-serializable type)',
265
+ },
266
+ },
267
+ required: ['operation', 'key'],
268
+ },
269
+ };
270
+ /* ========================================================================
271
+ * HANDLER IMPLEMENTATIONS
272
+ * ======================================================================== */
273
+ /**
274
+ * Handle data_manage operations
275
+ */
276
+ export function handleDataManage(args, context) {
277
+ const operation = args['operation'];
278
+ switch (operation) {
279
+ case 'store': {
280
+ // Validate required parameters
281
+ if (typeof args['key'] !== 'string') {
282
+ throw new Error('Missing required parameter: key (string)');
283
+ }
284
+ if (args['value'] === undefined) {
285
+ throw new Error('Missing required parameter: value');
286
+ }
287
+ // Build storage key (session-scoped if session_id provided)
288
+ const key = args['session_id'] !== undefined
289
+ ? `${String(args['session_id'])}:${String(args['key'])}`
290
+ : String(args['key']);
291
+ // Store in memory
292
+ context.memoryStore.set(key, {
293
+ value: args['value'],
294
+ stored_at: new Date(),
295
+ });
296
+ return {
297
+ operation: 'store',
298
+ key,
299
+ stored: true,
300
+ timestamp: new Date(),
301
+ };
302
+ }
303
+ case 'save': {
304
+ // Validate required parameters
305
+ if (typeof args['session_id'] !== 'string') {
306
+ throw new Error('Missing required parameter: session_id (string)');
307
+ }
308
+ if (typeof args['artifact_type'] !== 'string') {
309
+ throw new Error('Missing required parameter: artifact_type (string)');
310
+ }
311
+ if (typeof args['name'] !== 'string') {
312
+ throw new Error('Missing required parameter: name (string)');
313
+ }
314
+ if (typeof args['content'] !== 'string') {
315
+ throw new Error('Missing required parameter: content (string)');
316
+ }
317
+ // Create artifact
318
+ const artifactId = nanoid(21);
319
+ const now = new Date();
320
+ const content = String(args['content']);
321
+ const artifactTypeArg = args['artifact_type'];
322
+ const artifactType = typeof artifactTypeArg === 'string' ? artifactTypeArg : 'other';
323
+ const sessionId = String(args['session_id']);
324
+ const name = String(args['name']);
325
+ const artifact = {
326
+ id: artifactId,
327
+ session_id: sessionId,
328
+ task_id: null,
329
+ type: artifactType,
330
+ name,
331
+ extension: '',
332
+ content,
333
+ content_hash: '',
334
+ size_bytes: content.length,
335
+ summary: content.slice(0, 200),
336
+ token_count: Math.ceil(content.length / 4),
337
+ relevance_score: 50,
338
+ metadata: {},
339
+ created_at: now,
340
+ updated_at: now,
341
+ };
342
+ // Store in memory
343
+ context.artifacts.set(artifactId, artifact);
344
+ // Persist to MongoDB
345
+ safePersist(context.getPersistence().saveArtifact(artifact));
346
+ return {
347
+ operation: 'save',
348
+ artifact_id: artifact.id,
349
+ name: artifact.name,
350
+ type: artifact.type,
351
+ size_bytes: artifact.size_bytes,
352
+ created_at: artifact.created_at,
353
+ };
354
+ }
355
+ case 'optimize': {
356
+ // Validate required parameters
357
+ if (typeof args['session_id'] !== 'string') {
358
+ throw new Error('Missing required parameter: session_id (string)');
359
+ }
360
+ if (typeof args['objective'] !== 'string') {
361
+ throw new Error('Missing required parameter: objective (string)');
362
+ }
363
+ if (typeof args['phase'] !== 'string') {
364
+ throw new Error('Missing required parameter: phase (string)');
365
+ }
366
+ if (typeof args['progress'] !== 'number') {
367
+ throw new Error('Missing required parameter: progress (number)');
368
+ }
369
+ if (!Array.isArray(args['messages'])) {
370
+ throw new Error('Missing required parameter: messages (array)');
371
+ }
372
+ // Placeholder for context optimization
373
+ // In production, this would use ContextOptimizer from @anastops/core
374
+ return {
375
+ operation: 'optimize',
376
+ session_id: args['session_id'],
377
+ original_tokens: 1000,
378
+ optimized_tokens: 500,
379
+ reduction_percent: 50,
380
+ minimal_context: args['messages'],
381
+ };
382
+ }
383
+ default:
384
+ throw new Error(`Unknown data_manage operation: ${String(operation)}`);
385
+ }
386
+ }
387
+ /**
388
+ * Handle data_query operations
389
+ */
390
+ export async function handleDataQuery(args, context) {
391
+ const operation = args['operation'];
392
+ switch (operation) {
393
+ case 'retrieve': {
394
+ // Validate required parameters
395
+ if (typeof args['key'] !== 'string') {
396
+ throw new Error('Missing required parameter: key (string)');
397
+ }
398
+ // Retrieve from memory
399
+ const key = String(args['key']);
400
+ const data = context.memoryStore.get(key);
401
+ if (data === undefined) {
402
+ throw new Error(`Key not found: ${key}`);
403
+ }
404
+ return {
405
+ operation: 'retrieve',
406
+ key: args['key'],
407
+ found: true,
408
+ data,
409
+ };
410
+ }
411
+ case 'get': {
412
+ // Validate required parameters
413
+ if (typeof args['artifact_id'] !== 'string') {
414
+ throw new Error('Missing required parameter: artifact_id (string)');
415
+ }
416
+ // Get artifact
417
+ const artifactId = String(args['artifact_id']);
418
+ const artifact = await getArtifact(artifactId, context);
419
+ if (artifact === null) {
420
+ throw new Error(`Artifact not found: ${artifactId}`);
421
+ }
422
+ return {
423
+ operation: 'get',
424
+ ...artifact,
425
+ };
426
+ }
427
+ case 'list': {
428
+ // Validate required parameters
429
+ if (typeof args['session_id'] !== 'string') {
430
+ throw new Error('Missing required parameter: session_id (string)');
431
+ }
432
+ const sessionId = String(args['session_id']);
433
+ const artifactTypeArg = args['artifact_type'];
434
+ const typeFilter = typeof artifactTypeArg === 'string' ? artifactTypeArg : undefined;
435
+ // Get from in-memory cache first
436
+ const inMemoryArtifacts = [];
437
+ for (const [, artifact] of context.artifacts.entries()) {
438
+ if (artifact.session_id === sessionId) {
439
+ if (typeFilter === undefined || artifact.type === typeFilter) {
440
+ inMemoryArtifacts.push(artifact);
441
+ }
442
+ }
443
+ }
444
+ // Also get from MongoDB for persistence
445
+ const persistedArtifacts = await context.getPersistence().listArtifacts({
446
+ session_id: sessionId,
447
+ ...(typeFilter !== undefined && { type: typeFilter }),
448
+ });
449
+ // Merge: in-memory takes precedence
450
+ const inMemoryIds = new Set(inMemoryArtifacts.map((a) => a.id));
451
+ const sessionArtifacts = [
452
+ ...inMemoryArtifacts,
453
+ ...persistedArtifacts.filter((a) => !inMemoryIds.has(a.id)),
454
+ ];
455
+ return {
456
+ operation: 'list',
457
+ session_id: sessionId,
458
+ count: sessionArtifacts.length,
459
+ ...(typeFilter !== undefined && { type_filter: typeFilter }),
460
+ artifacts: sessionArtifacts.map((a) => ({
461
+ id: a.id,
462
+ name: a.name,
463
+ type: a.type,
464
+ size_bytes: a.size_bytes,
465
+ created_at: a.created_at,
466
+ })),
467
+ };
468
+ }
469
+ default:
470
+ throw new Error(`Unknown data_query operation: ${String(operation)}`);
471
+ }
472
+ }
473
+ /**
474
+ * Handle system_query operations
475
+ */
476
+ export async function handleSystemQuery(args, context) {
477
+ const operation = args['operation'] ?? 'health';
478
+ switch (operation) {
479
+ case 'health': {
480
+ // Check MongoDB persistence health
481
+ const persistence = context.getPersistence();
482
+ const isMongoConnected = persistence.isConnected();
483
+ const result = {
484
+ operation: 'health',
485
+ status: isMongoConnected ? 'healthy' : 'degraded',
486
+ timestamp: new Date(),
487
+ components: {
488
+ core: 'healthy',
489
+ router: 'healthy',
490
+ persistence: isMongoConnected ? 'connected' : 'disconnected',
491
+ },
492
+ };
493
+ if (!isMongoConnected) {
494
+ result['warning'] =
495
+ 'MongoDB is not connected. Run "docker ps | grep anastops-mongodb" to verify containers are running.';
496
+ }
497
+ if (args['include_providers'] === true) {
498
+ const providerHealth = {};
499
+ for (const adapter of context.registry.list()) {
500
+ const health = await adapter.healthCheck();
501
+ providerHealth[adapter.type] = {
502
+ healthy: health.healthy,
503
+ error: health.error,
504
+ };
505
+ }
506
+ result['providers'] = providerHealth;
507
+ }
508
+ return result;
509
+ }
510
+ case 'providers': {
511
+ const providers = [];
512
+ for (const adapter of context.registry.list()) {
513
+ const health = await adapter.healthCheck();
514
+ if (args['filter_healthy'] === true && !health.healthy)
515
+ continue;
516
+ const info = {
517
+ type: adapter.type,
518
+ name: adapter.name,
519
+ healthy: health.healthy,
520
+ };
521
+ if (args['include_capabilities'] === true) {
522
+ const caps = await adapter.getCapabilities();
523
+ info['capabilities'] = caps;
524
+ }
525
+ providers.push(info);
526
+ }
527
+ return {
528
+ operation: 'providers',
529
+ count: providers.length,
530
+ providers,
531
+ };
532
+ }
533
+ case 'metrics': {
534
+ // Placeholder metrics
535
+ return {
536
+ operation: 'metrics',
537
+ routing: {
538
+ tier_distribution: {},
539
+ provider_stats: {},
540
+ },
541
+ tokens: {
542
+ total: 0,
543
+ by_provider: {},
544
+ },
545
+ costs: {
546
+ total: 0,
547
+ by_provider: {},
548
+ },
549
+ };
550
+ }
551
+ default:
552
+ throw new Error(`Unknown system_query operation: ${String(operation)}`);
553
+ }
554
+ }
555
+ /**
556
+ * Handle lock_manage operations
557
+ */
558
+ export function handleLockManage(args, context) {
559
+ const operation = args['operation'];
560
+ switch (operation) {
561
+ case 'acquire': {
562
+ // Validate required parameters
563
+ if (typeof args['session_id'] !== 'string') {
564
+ throw new Error('Missing required parameter: session_id (string)');
565
+ }
566
+ if (typeof args['file_path'] !== 'string') {
567
+ throw new Error('Missing required parameter: file_path (string)');
568
+ }
569
+ const sessionId = String(args['session_id']);
570
+ const filePath = String(args['file_path']);
571
+ const ttlArg = args['ttl'];
572
+ const ttl = typeof ttlArg === 'number' ? ttlArg : 300000;
573
+ // In-memory lock implementation (Redis-based in production)
574
+ const lockKey = `lock:${filePath}`;
575
+ const existingLock = context.memoryStore.get(lockKey);
576
+ if (existingLock !== undefined) {
577
+ const lockData = existingLock.value;
578
+ // Check if lock is expired
579
+ if (lockData.expires_at > Date.now() && lockData.session_id !== sessionId) {
580
+ return {
581
+ operation: 'acquire',
582
+ session_id: sessionId,
583
+ file_path: filePath,
584
+ acquired: false,
585
+ owner: lockData.session_id,
586
+ ttl,
587
+ };
588
+ }
589
+ }
590
+ // Acquire lock
591
+ context.memoryStore.set(lockKey, {
592
+ value: { session_id: sessionId, expires_at: Date.now() + ttl },
593
+ stored_at: new Date(),
594
+ });
595
+ return {
596
+ operation: 'acquire',
597
+ session_id: sessionId,
598
+ file_path: filePath,
599
+ acquired: true,
600
+ ttl,
601
+ };
602
+ }
603
+ case 'release': {
604
+ // Validate required parameters
605
+ if (typeof args['session_id'] !== 'string') {
606
+ throw new Error('Missing required parameter: session_id (string)');
607
+ }
608
+ if (typeof args['file_path'] !== 'string') {
609
+ throw new Error('Missing required parameter: file_path (string)');
610
+ }
611
+ const relSessionId = String(args['session_id']);
612
+ const relFilePath = String(args['file_path']);
613
+ const lockKey = `lock:${relFilePath}`;
614
+ const existingLock = context.memoryStore.get(lockKey);
615
+ if (existingLock !== undefined) {
616
+ const lockData = existingLock.value;
617
+ if (lockData.session_id === relSessionId) {
618
+ context.memoryStore.delete(lockKey);
619
+ return {
620
+ operation: 'release',
621
+ session_id: relSessionId,
622
+ file_path: relFilePath,
623
+ released: true,
624
+ };
625
+ }
626
+ return {
627
+ operation: 'release',
628
+ session_id: relSessionId,
629
+ file_path: relFilePath,
630
+ released: false,
631
+ error: 'Lock is held by another session',
632
+ };
633
+ }
634
+ return {
635
+ operation: 'release',
636
+ session_id: relSessionId,
637
+ file_path: relFilePath,
638
+ released: true,
639
+ message: 'Lock did not exist',
640
+ };
641
+ }
642
+ case 'status': {
643
+ const sessionId = args['session_id'];
644
+ const filePath = args['file_path'];
645
+ if (filePath !== undefined) {
646
+ const lockKey = `lock:${filePath}`;
647
+ const existingLock = context.memoryStore.get(lockKey);
648
+ if (existingLock !== undefined) {
649
+ const lockData = existingLock.value;
650
+ const isExpired = lockData.expires_at <= Date.now();
651
+ return {
652
+ operation: 'status',
653
+ file_path: filePath,
654
+ is_locked: !isExpired,
655
+ owner: isExpired ? null : lockData.session_id,
656
+ expires_at: lockData.expires_at,
657
+ };
658
+ }
659
+ return {
660
+ operation: 'status',
661
+ file_path: filePath,
662
+ is_locked: false,
663
+ owner: null,
664
+ };
665
+ }
666
+ if (sessionId !== undefined) {
667
+ // List all locks held by this session
668
+ const sessionLocks = [];
669
+ for (const [key, data] of context.memoryStore.entries()) {
670
+ if (key.startsWith('lock:')) {
671
+ const lockData = data.value;
672
+ if (lockData.session_id === sessionId && lockData.expires_at > Date.now()) {
673
+ sessionLocks.push({
674
+ file_path: key.replace('lock:', ''),
675
+ expires_at: lockData.expires_at,
676
+ });
677
+ }
678
+ }
679
+ }
680
+ return {
681
+ operation: 'status',
682
+ session_id: sessionId,
683
+ lock_count: sessionLocks.length,
684
+ locks: sessionLocks,
685
+ };
686
+ }
687
+ throw new Error('Must provide either session_id or file_path for lock status');
688
+ }
689
+ default:
690
+ throw new Error(`Unknown lock_manage operation: ${String(operation)}`);
691
+ }
692
+ }
693
+ /**
694
+ * Handle session_monitoring operations
695
+ */
696
+ export function handleSessionMonitoring(args, context) {
697
+ const operation = args['operation'];
698
+ // Validate session_id (required for all operations)
699
+ if (typeof args['session_id'] !== 'string') {
700
+ throw new Error('Missing required parameter: session_id (string)');
701
+ }
702
+ const sessionId = String(args['session_id']);
703
+ switch (operation) {
704
+ case 'cost': {
705
+ // Aggregate cost from task token_usage
706
+ let totalCost = 0;
707
+ for (const [, task] of context.tasks.entries()) {
708
+ if (task.session_id === sessionId && task.token_usage !== undefined) {
709
+ totalCost += task.token_usage.cost ?? 0;
710
+ }
711
+ }
712
+ return {
713
+ operation: 'cost',
714
+ session_id: sessionId,
715
+ total_cost_usd: totalCost,
716
+ currency: 'USD',
717
+ };
718
+ }
719
+ case 'metrics': {
720
+ // Aggregate metrics from tasks
721
+ let requestCount = 0;
722
+ let inputTokens = 0;
723
+ let outputTokens = 0;
724
+ let totalTokens = 0;
725
+ for (const [, task] of context.tasks.entries()) {
726
+ if (task.session_id === sessionId) {
727
+ requestCount++;
728
+ if (task.token_usage !== undefined) {
729
+ inputTokens += task.token_usage.prompt_tokens ?? 0;
730
+ outputTokens += task.token_usage.completion_tokens ?? 0;
731
+ totalTokens += task.token_usage.total_tokens ?? 0;
732
+ }
733
+ }
734
+ }
735
+ return {
736
+ operation: 'metrics',
737
+ session_id: sessionId,
738
+ request_count: requestCount,
739
+ token_usage: {
740
+ input: inputTokens,
741
+ output: outputTokens,
742
+ total: totalTokens,
743
+ },
744
+ };
745
+ }
746
+ case 'throttle': {
747
+ const provider = args['provider'] ?? 'claude';
748
+ // In-memory rate limit tracking (Redis-based in production)
749
+ const rateKey = `rate:${sessionId}:${provider}`;
750
+ const rateData = context.memoryStore.get(rateKey);
751
+ // Default limits per provider (requests per minute)
752
+ const defaultLimit = 30;
753
+ const limits = {
754
+ claude: 50,
755
+ openai: 60,
756
+ gemini: 60,
757
+ };
758
+ const limit = limits[provider] ?? defaultLimit;
759
+ if (rateData !== undefined) {
760
+ const data = rateData.value;
761
+ const windowSize = 60000; // 1 minute
762
+ const now = Date.now();
763
+ if (now - data.window_start > windowSize) {
764
+ // Window expired, reset
765
+ return {
766
+ operation: 'throttle',
767
+ session_id: sessionId,
768
+ provider,
769
+ usage_percent: 0,
770
+ current_count: 0,
771
+ limit,
772
+ throttled: false,
773
+ blocked: false,
774
+ };
775
+ }
776
+ const usagePercent = (data.count / limit) * 100;
777
+ return {
778
+ operation: 'throttle',
779
+ session_id: sessionId,
780
+ provider,
781
+ usage_percent: Math.min(100, usagePercent),
782
+ current_count: data.count,
783
+ limit,
784
+ throttled: usagePercent >= 85,
785
+ blocked: usagePercent >= 95,
786
+ };
787
+ }
788
+ return {
789
+ operation: 'throttle',
790
+ session_id: sessionId,
791
+ provider,
792
+ usage_percent: 0,
793
+ current_count: 0,
794
+ limit,
795
+ throttled: false,
796
+ blocked: false,
797
+ };
798
+ }
799
+ default:
800
+ throw new Error(`Unknown session_monitoring operation: ${String(operation)}`);
801
+ }
802
+ }
803
+ /**
804
+ * Handle config_manage operations
805
+ */
806
+ export function handleConfigManage(args, _context) {
807
+ const operation = args['operation'];
808
+ // Validate key (required for both operations)
809
+ if (typeof args['key'] !== 'string') {
810
+ throw new Error('Missing required parameter: key (string)');
811
+ }
812
+ switch (operation) {
813
+ case 'get': {
814
+ // Placeholder config
815
+ const config = {
816
+ default_provider: 'claude',
817
+ default_timeout: 600000, // 10 minutes
818
+ context_budget: 1600,
819
+ };
820
+ const configKey = String(args['key']);
821
+ return {
822
+ operation: 'get',
823
+ key: configKey,
824
+ value: config[configKey],
825
+ };
826
+ }
827
+ case 'set': {
828
+ // Validate value (required for set)
829
+ if (args['value'] === undefined) {
830
+ throw new Error('Missing required parameter: value for set operation');
831
+ }
832
+ return {
833
+ operation: 'set',
834
+ key: args['key'],
835
+ value: args['value'],
836
+ updated: true,
837
+ };
838
+ }
839
+ default:
840
+ throw new Error(`Unknown config_manage operation: ${String(operation)}`);
841
+ }
842
+ }
843
+ /* ========================================================================
844
+ * EXPORTS
845
+ * ======================================================================== */
846
+ /**
847
+ * All v3.0 utility and data tool definitions
848
+ */
849
+ export const toolDefinitions = [
850
+ dataManageTool,
851
+ dataQueryTool,
852
+ systemQueryTool,
853
+ lockManageTool,
854
+ sessionMonitoringTool,
855
+ configManageTool,
856
+ ];
857
+ /**
858
+ * Main handler router for all v3.0 utility and data tools
859
+ */
860
+ export async function handleTool(name, args, context) {
861
+ switch (name) {
862
+ case 'data_manage':
863
+ return handleDataManage(args, context);
864
+ case 'data_query':
865
+ return handleDataQuery(args, context);
866
+ case 'system_query':
867
+ return handleSystemQuery(args, context);
868
+ case 'lock_manage':
869
+ return handleLockManage(args, context);
870
+ case 'session_monitoring':
871
+ return handleSessionMonitoring(args, context);
872
+ case 'config_manage':
873
+ return handleConfigManage(args, context);
874
+ default:
875
+ throw new Error(`Unknown v3.0 utility/data tool: ${name}`);
876
+ }
877
+ }
878
+ //# sourceMappingURL=utility-tools.js.map