@jaypie/mcp 0.3.4 → 0.4.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 (52) hide show
  1. package/dist/createMcpServer.d.ts +7 -1
  2. package/dist/index.js +22 -2088
  3. package/dist/index.js.map +1 -1
  4. package/dist/suite.js +1197 -7
  5. package/dist/suite.js.map +1 -1
  6. package/package.json +1 -2
  7. package/release-notes/fabric/0.1.3.md +25 -0
  8. package/release-notes/fabric/0.1.4.md +42 -0
  9. package/release-notes/mcp/0.4.0.md +27 -0
  10. package/release-notes/testkit/1.2.15.md +23 -0
  11. package/skills/fabric.md +30 -3
  12. package/dist/aws-B3dW_-bD.js +0 -1202
  13. package/dist/aws-B3dW_-bD.js.map +0 -1
  14. package/prompts/Branch_Management.md +0 -34
  15. package/prompts/Development_Process.md +0 -89
  16. package/prompts/Jaypie_Agent_Rules.md +0 -110
  17. package/prompts/Jaypie_Auth0_Express_Mongoose.md +0 -736
  18. package/prompts/Jaypie_Browser_and_Frontend_Web_Packages.md +0 -18
  19. package/prompts/Jaypie_CDK_Constructs_and_Patterns.md +0 -430
  20. package/prompts/Jaypie_CICD_with_GitHub_Actions.md +0 -371
  21. package/prompts/Jaypie_Commander_CLI_Package.md +0 -166
  22. package/prompts/Jaypie_Core_Errors_and_Logging.md +0 -39
  23. package/prompts/Jaypie_DynamoDB_Package.md +0 -774
  24. package/prompts/Jaypie_Eslint_NPM_Package.md +0 -78
  25. package/prompts/Jaypie_Express_Package.md +0 -630
  26. package/prompts/Jaypie_Fabric_Commander.md +0 -411
  27. package/prompts/Jaypie_Fabric_LLM.md +0 -312
  28. package/prompts/Jaypie_Fabric_Lambda.md +0 -308
  29. package/prompts/Jaypie_Fabric_MCP.md +0 -316
  30. package/prompts/Jaypie_Fabric_Package.md +0 -599
  31. package/prompts/Jaypie_Fabricator.md +0 -617
  32. package/prompts/Jaypie_Ideal_Project_Structure.md +0 -78
  33. package/prompts/Jaypie_Init_CICD_with_GitHub_Actions.md +0 -1186
  34. package/prompts/Jaypie_Init_Express_on_Lambda.md +0 -115
  35. package/prompts/Jaypie_Init_Jaypie_CDK_Package.md +0 -35
  36. package/prompts/Jaypie_Init_Lambda_Package.md +0 -505
  37. package/prompts/Jaypie_Init_Monorepo_Project.md +0 -44
  38. package/prompts/Jaypie_Init_Project_Subpackage.md +0 -65
  39. package/prompts/Jaypie_Legacy_Patterns.md +0 -15
  40. package/prompts/Jaypie_Llm_Calls.md +0 -449
  41. package/prompts/Jaypie_Llm_Tools.md +0 -155
  42. package/prompts/Jaypie_MCP_Package.md +0 -281
  43. package/prompts/Jaypie_Mocks_and_Testkit.md +0 -137
  44. package/prompts/Jaypie_Repokit.md +0 -103
  45. package/prompts/Jaypie_Scrub.md +0 -177
  46. package/prompts/Jaypie_Streaming.md +0 -467
  47. package/prompts/Templates_CDK_Subpackage.md +0 -115
  48. package/prompts/Templates_Express_Subpackage.md +0 -187
  49. package/prompts/Templates_Project_Monorepo.md +0 -326
  50. package/prompts/Templates_Project_Subpackage.md +0 -93
  51. package/prompts/Write_Efficient_Prompt_Guides.md +0 -48
  52. package/prompts/Write_and_Maintain_Engaging_Readme.md +0 -67
package/dist/suite.js CHANGED
@@ -4,15 +4,1205 @@ import * as path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import matter from 'gray-matter';
6
6
  import { gt } from 'semver';
7
- import { g as getDatadogCredentials, s as searchDatadogLogs, a as aggregateDatadogLogs, l as listDatadogMonitors, b as getDatadogSyntheticResults, c as listDatadogSynthetics, q as queryDatadogMetrics, d as searchDatadogRum, e as debugLlmCall, f as listLlmProviders, h as listAwsProfiles, i as listStepFunctionExecutions, j as stopStepFunctionExecution, k as listLambdaFunctions, m as getLambdaFunction, n as filterLogEvents, o as listS3Objects, p as describeStack, r as describeDynamoDBTable, t as scanDynamoDB, u as queryDynamoDB, v as getDynamoDBItem, w as listSQSQueues, x as getSQSQueueAttributes, y as receiveSQSMessage, z as purgeSQSQueue } from './aws-B3dW_-bD.js';
8
- import 'node:https';
9
- import '@jaypie/llm';
10
- import 'node:child_process';
11
- import 'node:os';
7
+ import * as https from 'node:https';
8
+ import { Llm } from '@jaypie/llm';
9
+ import { spawn } from 'node:child_process';
10
+ import * as os from 'node:os';
11
+
12
+ /**
13
+ * Datadog API integration module
14
+ */
15
+ const nullLogger$1 = {
16
+ info: () => { },
17
+ error: () => { },
18
+ };
19
+ /**
20
+ * Get Datadog credentials from environment variables
21
+ */
22
+ function getDatadogCredentials() {
23
+ const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY;
24
+ const appKey = process.env.DATADOG_APP_KEY ||
25
+ process.env.DATADOG_APPLICATION_KEY ||
26
+ process.env.DD_APP_KEY ||
27
+ process.env.DD_APPLICATION_KEY;
28
+ if (!apiKey || !appKey) {
29
+ return null;
30
+ }
31
+ return { apiKey, appKey };
32
+ }
33
+ /**
34
+ * Build query string from environment variables and options
35
+ */
36
+ function buildDatadogQuery(options) {
37
+ const ddEnv = process.env.DD_ENV;
38
+ const ddService = process.env.DD_SERVICE;
39
+ const ddSource = process.env.DD_SOURCE;
40
+ const ddQuery = process.env.DD_QUERY;
41
+ const queryParts = [];
42
+ // Add source (parameter > env var > default 'lambda')
43
+ const effectiveSource = options.source || ddSource || "lambda";
44
+ queryParts.push(`source:${effectiveSource}`);
45
+ // Add env (parameter > env var)
46
+ const effectiveEnv = options.env || ddEnv;
47
+ if (effectiveEnv) {
48
+ queryParts.push(`env:${effectiveEnv}`);
49
+ }
50
+ // Add service (parameter > env var)
51
+ const effectiveService = options.service || ddService;
52
+ if (effectiveService) {
53
+ queryParts.push(`service:${effectiveService}`);
54
+ }
55
+ // Add base query from DD_QUERY if available
56
+ if (ddQuery) {
57
+ queryParts.push(ddQuery);
58
+ }
59
+ // Add user-provided query terms
60
+ if (options.query) {
61
+ queryParts.push(options.query);
62
+ }
63
+ return queryParts.join(" ");
64
+ }
65
+ /**
66
+ * Search Datadog logs
67
+ */
68
+ async function searchDatadogLogs(credentials, options = {}, logger = nullLogger$1) {
69
+ const effectiveQuery = buildDatadogQuery(options);
70
+ const effectiveFrom = options.from || "now-15m";
71
+ const effectiveTo = options.to || "now";
72
+ const effectiveLimit = Math.min(options.limit || 50, 1000);
73
+ const effectiveSort = options.sort || "-timestamp";
74
+ logger.info(`Effective query: ${effectiveQuery}`);
75
+ logger.info(`Search params: from=${effectiveFrom}, to=${effectiveTo}, limit=${effectiveLimit}, sort=${effectiveSort}`);
76
+ const requestBody = JSON.stringify({
77
+ filter: {
78
+ query: effectiveQuery,
79
+ from: effectiveFrom,
80
+ to: effectiveTo,
81
+ },
82
+ page: {
83
+ limit: effectiveLimit,
84
+ },
85
+ sort: effectiveSort,
86
+ });
87
+ return new Promise((resolve) => {
88
+ const requestOptions = {
89
+ hostname: "api.datadoghq.com",
90
+ port: 443,
91
+ path: "/api/v2/logs/events/search",
92
+ method: "POST",
93
+ headers: {
94
+ "Content-Type": "application/json",
95
+ "DD-API-KEY": credentials.apiKey,
96
+ "DD-APPLICATION-KEY": credentials.appKey,
97
+ "Content-Length": Buffer.byteLength(requestBody),
98
+ },
99
+ };
100
+ const req = https.request(requestOptions, (res) => {
101
+ let data = "";
102
+ res.on("data", (chunk) => {
103
+ data += chunk.toString();
104
+ });
105
+ res.on("end", () => {
106
+ logger.info(`Response status: ${res.statusCode}`);
107
+ if (res.statusCode !== 200) {
108
+ logger.error(`Datadog API error: ${res.statusCode}`);
109
+ let errorMessage = `Datadog API returned status ${res.statusCode}: ${data}`;
110
+ if (res.statusCode === 400) {
111
+ errorMessage = `Invalid query syntax. Check your query: "${effectiveQuery}". Datadog error: ${data}`;
112
+ }
113
+ else if (res.statusCode === 403) {
114
+ errorMessage =
115
+ "Access denied. Verify your API and Application keys have logs_read permission.";
116
+ }
117
+ else if (res.statusCode === 429) {
118
+ errorMessage =
119
+ "Rate limited by Datadog. Wait a moment and try again, or reduce your query scope.";
120
+ }
121
+ resolve({
122
+ success: false,
123
+ query: effectiveQuery,
124
+ timeRange: { from: effectiveFrom, to: effectiveTo },
125
+ logs: [],
126
+ error: errorMessage,
127
+ });
128
+ return;
129
+ }
130
+ try {
131
+ const response = JSON.parse(data);
132
+ const logs = (response.data || []).map((log) => {
133
+ const attrs = log.attributes || {};
134
+ return {
135
+ id: log.id,
136
+ timestamp: attrs.timestamp,
137
+ status: attrs.status,
138
+ service: attrs.service,
139
+ message: attrs.message,
140
+ attributes: attrs.attributes,
141
+ };
142
+ });
143
+ logger.info(`Retrieved ${logs.length} log entries`);
144
+ resolve({
145
+ success: true,
146
+ query: effectiveQuery,
147
+ timeRange: { from: effectiveFrom, to: effectiveTo },
148
+ logs,
149
+ });
150
+ }
151
+ catch (parseError) {
152
+ logger.error("Failed to parse Datadog response:", parseError);
153
+ resolve({
154
+ success: false,
155
+ query: effectiveQuery,
156
+ timeRange: { from: effectiveFrom, to: effectiveTo },
157
+ logs: [],
158
+ error: `Failed to parse response: ${parseError instanceof Error ? parseError.message : "Unknown error"}`,
159
+ });
160
+ }
161
+ });
162
+ });
163
+ req.on("error", (error) => {
164
+ logger.error("Request error:", error);
165
+ resolve({
166
+ success: false,
167
+ query: effectiveQuery,
168
+ timeRange: { from: effectiveFrom, to: effectiveTo },
169
+ logs: [],
170
+ error: `Connection error: ${error.message}`,
171
+ });
172
+ });
173
+ req.write(requestBody);
174
+ req.end();
175
+ });
176
+ }
177
+ /**
178
+ * Aggregate Datadog logs using the Analytics API
179
+ * Groups logs by specified fields and computes aggregations
180
+ */
181
+ async function aggregateDatadogLogs(credentials, options, logger = nullLogger$1) {
182
+ const effectiveQuery = buildDatadogQuery(options);
183
+ const effectiveFrom = options.from || "now-15m";
184
+ const effectiveTo = options.to || "now";
185
+ const groupBy = options.groupBy;
186
+ const compute = options.compute || [{ aggregation: "count" }];
187
+ logger.info(`Analytics query: ${effectiveQuery}`);
188
+ logger.info(`Group by: ${groupBy.join(", ")}`);
189
+ logger.info(`Time range: ${effectiveFrom} to ${effectiveTo}`);
190
+ // Build compute array - each item needs aggregation and type
191
+ const computeItems = compute.map((c) => {
192
+ const item = {
193
+ aggregation: c.aggregation,
194
+ type: "total",
195
+ };
196
+ if (c.metric) {
197
+ item.metric = c.metric;
198
+ }
199
+ return item;
200
+ });
201
+ // Build group_by with proper sort configuration
202
+ const groupByItems = groupBy.map((field) => {
203
+ const item = {
204
+ facet: field,
205
+ limit: 100,
206
+ sort: {
207
+ type: "measure",
208
+ order: "desc",
209
+ aggregation: compute[0]?.aggregation || "count",
210
+ },
211
+ };
212
+ return item;
213
+ });
214
+ const requestBody = JSON.stringify({
215
+ filter: {
216
+ query: effectiveQuery,
217
+ from: effectiveFrom,
218
+ to: effectiveTo,
219
+ },
220
+ group_by: groupByItems,
221
+ compute: computeItems,
222
+ page: {
223
+ limit: 100,
224
+ },
225
+ });
226
+ return new Promise((resolve) => {
227
+ const requestOptions = {
228
+ hostname: "api.datadoghq.com",
229
+ port: 443,
230
+ path: "/api/v2/logs/analytics/aggregate",
231
+ method: "POST",
232
+ headers: {
233
+ "Content-Type": "application/json",
234
+ "DD-API-KEY": credentials.apiKey,
235
+ "DD-APPLICATION-KEY": credentials.appKey,
236
+ "Content-Length": Buffer.byteLength(requestBody),
237
+ },
238
+ };
239
+ const req = https.request(requestOptions, (res) => {
240
+ let data = "";
241
+ res.on("data", (chunk) => {
242
+ data += chunk.toString();
243
+ });
244
+ res.on("end", () => {
245
+ logger.info(`Response status: ${res.statusCode}`);
246
+ if (res.statusCode !== 200) {
247
+ logger.error(`Datadog Analytics API error: ${res.statusCode}`);
248
+ let errorMessage = `Datadog API returned status ${res.statusCode}: ${data}`;
249
+ if (res.statusCode === 400) {
250
+ errorMessage = `Invalid query or groupBy fields. Verify facet names exist: ${groupBy.join(", ")}. Datadog error: ${data}`;
251
+ }
252
+ else if (res.statusCode === 403) {
253
+ errorMessage =
254
+ "Access denied. Verify your API and Application keys have logs_read permission.";
255
+ }
256
+ else if (res.statusCode === 429) {
257
+ errorMessage =
258
+ "Rate limited by Datadog. Wait a moment and try again, or reduce your query scope.";
259
+ }
260
+ resolve({
261
+ success: false,
262
+ query: effectiveQuery,
263
+ timeRange: { from: effectiveFrom, to: effectiveTo },
264
+ groupBy,
265
+ buckets: [],
266
+ error: errorMessage,
267
+ });
268
+ return;
269
+ }
270
+ try {
271
+ const response = JSON.parse(data);
272
+ const buckets = (response.data?.buckets || []).map((bucket) => ({
273
+ by: bucket.by || {},
274
+ computes: bucket.computes || {},
275
+ }));
276
+ logger.info(`Retrieved ${buckets.length} aggregation buckets`);
277
+ resolve({
278
+ success: true,
279
+ query: effectiveQuery,
280
+ timeRange: { from: effectiveFrom, to: effectiveTo },
281
+ groupBy,
282
+ buckets,
283
+ });
284
+ }
285
+ catch (parseError) {
286
+ logger.error("Failed to parse Datadog analytics response:", parseError);
287
+ resolve({
288
+ success: false,
289
+ query: effectiveQuery,
290
+ timeRange: { from: effectiveFrom, to: effectiveTo },
291
+ groupBy,
292
+ buckets: [],
293
+ error: `Failed to parse response: ${parseError instanceof Error ? parseError.message : "Unknown error"}`,
294
+ });
295
+ }
296
+ });
297
+ });
298
+ req.on("error", (error) => {
299
+ logger.error("Request error:", error);
300
+ resolve({
301
+ success: false,
302
+ query: effectiveQuery,
303
+ timeRange: { from: effectiveFrom, to: effectiveTo },
304
+ groupBy,
305
+ buckets: [],
306
+ error: `Connection error: ${error.message}`,
307
+ });
308
+ });
309
+ req.write(requestBody);
310
+ req.end();
311
+ });
312
+ }
313
+ /**
314
+ * List Datadog monitors with optional filtering
315
+ */
316
+ async function listDatadogMonitors(credentials, options = {}, logger = nullLogger$1) {
317
+ logger.info("Fetching Datadog monitors");
318
+ const queryParams = new URLSearchParams();
319
+ if (options.tags && options.tags.length > 0) {
320
+ queryParams.set("tags", options.tags.join(","));
321
+ }
322
+ if (options.monitorTags && options.monitorTags.length > 0) {
323
+ queryParams.set("monitor_tags", options.monitorTags.join(","));
324
+ }
325
+ if (options.name) {
326
+ queryParams.set("name", options.name);
327
+ }
328
+ const queryString = queryParams.toString();
329
+ const path = `/api/v1/monitor${queryString ? `?${queryString}` : ""}`;
330
+ logger.info(`Request path: ${path}`);
331
+ return new Promise((resolve) => {
332
+ const requestOptions = {
333
+ hostname: "api.datadoghq.com",
334
+ port: 443,
335
+ path,
336
+ method: "GET",
337
+ headers: {
338
+ "DD-API-KEY": credentials.apiKey,
339
+ "DD-APPLICATION-KEY": credentials.appKey,
340
+ },
341
+ };
342
+ const req = https.request(requestOptions, (res) => {
343
+ let data = "";
344
+ res.on("data", (chunk) => {
345
+ data += chunk.toString();
346
+ });
347
+ res.on("end", () => {
348
+ logger.info(`Response status: ${res.statusCode}`);
349
+ if (res.statusCode !== 200) {
350
+ logger.error(`Datadog Monitors API error: ${res.statusCode}`);
351
+ let errorMessage = `Datadog API returned status ${res.statusCode}: ${data}`;
352
+ if (res.statusCode === 403) {
353
+ errorMessage =
354
+ "Access denied. Verify your API and Application keys have monitors_read permission.";
355
+ }
356
+ else if (res.statusCode === 429) {
357
+ errorMessage =
358
+ "Rate limited by Datadog. Wait a moment and try again.";
359
+ }
360
+ resolve({
361
+ success: false,
362
+ monitors: [],
363
+ error: errorMessage,
364
+ });
365
+ return;
366
+ }
367
+ try {
368
+ const response = JSON.parse(data);
369
+ let monitors = response.map((monitor) => ({
370
+ id: monitor.id,
371
+ name: monitor.name,
372
+ type: monitor.type,
373
+ status: monitor.overall_state || "Unknown",
374
+ message: monitor.message,
375
+ tags: monitor.tags || [],
376
+ priority: monitor.priority,
377
+ query: monitor.query,
378
+ overallState: monitor.overall_state,
379
+ }));
380
+ // Filter by status if specified
381
+ if (options.status && options.status.length > 0) {
382
+ monitors = monitors.filter((m) => options.status.includes(m.status));
383
+ }
384
+ logger.info(`Retrieved ${monitors.length} monitors`);
385
+ resolve({
386
+ success: true,
387
+ monitors,
388
+ });
389
+ }
390
+ catch (parseError) {
391
+ logger.error("Failed to parse Datadog monitors response:", parseError);
392
+ resolve({
393
+ success: false,
394
+ monitors: [],
395
+ error: `Failed to parse response: ${parseError instanceof Error ? parseError.message : "Unknown error"}`,
396
+ });
397
+ }
398
+ });
399
+ });
400
+ req.on("error", (error) => {
401
+ logger.error("Request error:", error);
402
+ resolve({
403
+ success: false,
404
+ monitors: [],
405
+ error: `Connection error: ${error.message}`,
406
+ });
407
+ });
408
+ req.end();
409
+ });
410
+ }
411
+ /**
412
+ * List Datadog Synthetic tests
413
+ */
414
+ async function listDatadogSynthetics(credentials, options = {}, logger = nullLogger$1) {
415
+ logger.info("Fetching Datadog Synthetic tests");
416
+ return new Promise((resolve) => {
417
+ const requestOptions = {
418
+ hostname: "api.datadoghq.com",
419
+ port: 443,
420
+ path: "/api/v1/synthetics/tests",
421
+ method: "GET",
422
+ headers: {
423
+ "DD-API-KEY": credentials.apiKey,
424
+ "DD-APPLICATION-KEY": credentials.appKey,
425
+ },
426
+ };
427
+ const req = https.request(requestOptions, (res) => {
428
+ let data = "";
429
+ res.on("data", (chunk) => {
430
+ data += chunk.toString();
431
+ });
432
+ res.on("end", () => {
433
+ logger.info(`Response status: ${res.statusCode}`);
434
+ if (res.statusCode !== 200) {
435
+ logger.error(`Datadog Synthetics API error: ${res.statusCode}`);
436
+ let errorMessage = `Datadog API returned status ${res.statusCode}: ${data}`;
437
+ if (res.statusCode === 403) {
438
+ errorMessage =
439
+ "Access denied. Verify your API and Application keys have synthetics_read permission.";
440
+ }
441
+ else if (res.statusCode === 429) {
442
+ errorMessage =
443
+ "Rate limited by Datadog. Wait a moment and try again.";
444
+ }
445
+ resolve({
446
+ success: false,
447
+ tests: [],
448
+ error: errorMessage,
449
+ });
450
+ return;
451
+ }
452
+ try {
453
+ const response = JSON.parse(data);
454
+ let tests = (response.tests || []).map((test) => ({
455
+ publicId: test.public_id,
456
+ name: test.name,
457
+ type: test.type,
458
+ status: test.status,
459
+ tags: test.tags || [],
460
+ locations: test.locations || [],
461
+ message: test.message,
462
+ }));
463
+ // Filter by type if specified
464
+ if (options.type) {
465
+ tests = tests.filter((t) => t.type === options.type);
466
+ }
467
+ // Filter by tags if specified
468
+ if (options.tags && options.tags.length > 0) {
469
+ tests = tests.filter((t) => options.tags.some((tag) => t.tags.includes(tag)));
470
+ }
471
+ logger.info(`Retrieved ${tests.length} synthetic tests`);
472
+ resolve({
473
+ success: true,
474
+ tests,
475
+ });
476
+ }
477
+ catch (parseError) {
478
+ logger.error("Failed to parse Datadog synthetics response:", parseError);
479
+ resolve({
480
+ success: false,
481
+ tests: [],
482
+ error: `Failed to parse response: ${parseError instanceof Error ? parseError.message : "Unknown error"}`,
483
+ });
484
+ }
485
+ });
486
+ });
487
+ req.on("error", (error) => {
488
+ logger.error("Request error:", error);
489
+ resolve({
490
+ success: false,
491
+ tests: [],
492
+ error: `Connection error: ${error.message}`,
493
+ });
494
+ });
495
+ req.end();
496
+ });
497
+ }
498
+ /**
499
+ * Get recent results for a specific Synthetic test
500
+ */
501
+ async function getDatadogSyntheticResults(credentials, publicId, logger = nullLogger$1) {
502
+ logger.info(`Fetching results for Synthetic test: ${publicId}`);
503
+ return new Promise((resolve) => {
504
+ const requestOptions = {
505
+ hostname: "api.datadoghq.com",
506
+ port: 443,
507
+ path: `/api/v1/synthetics/tests/${publicId}/results`,
508
+ method: "GET",
509
+ headers: {
510
+ "DD-API-KEY": credentials.apiKey,
511
+ "DD-APPLICATION-KEY": credentials.appKey,
512
+ },
513
+ };
514
+ const req = https.request(requestOptions, (res) => {
515
+ let data = "";
516
+ res.on("data", (chunk) => {
517
+ data += chunk.toString();
518
+ });
519
+ res.on("end", () => {
520
+ logger.info(`Response status: ${res.statusCode}`);
521
+ if (res.statusCode !== 200) {
522
+ logger.error(`Datadog Synthetics Results API error: ${res.statusCode}`);
523
+ let errorMessage = `Datadog API returned status ${res.statusCode}: ${data}`;
524
+ if (res.statusCode === 403) {
525
+ errorMessage =
526
+ "Access denied. Verify your API and Application keys have synthetics_read permission.";
527
+ }
528
+ else if (res.statusCode === 404) {
529
+ errorMessage = `Synthetic test '${publicId}' not found. Use datadog_synthetics (without testId) to list available tests.`;
530
+ }
531
+ else if (res.statusCode === 429) {
532
+ errorMessage =
533
+ "Rate limited by Datadog. Wait a moment and try again.";
534
+ }
535
+ resolve({
536
+ success: false,
537
+ publicId,
538
+ results: [],
539
+ error: errorMessage,
540
+ });
541
+ return;
542
+ }
543
+ try {
544
+ const response = JSON.parse(data);
545
+ const results = (response.results || []).map((result) => ({
546
+ publicId,
547
+ resultId: result.result_id,
548
+ status: result.status,
549
+ checkTime: result.check_time,
550
+ passed: result.result?.passed ?? result.status === 0,
551
+ location: result.dc_id?.toString(),
552
+ }));
553
+ logger.info(`Retrieved ${results.length} synthetic results`);
554
+ resolve({
555
+ success: true,
556
+ publicId,
557
+ results,
558
+ });
559
+ }
560
+ catch (parseError) {
561
+ logger.error("Failed to parse Datadog synthetic results:", parseError);
562
+ resolve({
563
+ success: false,
564
+ publicId,
565
+ results: [],
566
+ error: `Failed to parse response: ${parseError instanceof Error ? parseError.message : "Unknown error"}`,
567
+ });
568
+ }
569
+ });
570
+ });
571
+ req.on("error", (error) => {
572
+ logger.error("Request error:", error);
573
+ resolve({
574
+ success: false,
575
+ publicId,
576
+ results: [],
577
+ error: `Connection error: ${error.message}`,
578
+ });
579
+ });
580
+ req.end();
581
+ });
582
+ }
583
+ /**
584
+ * Query Datadog metrics
585
+ */
586
+ async function queryDatadogMetrics(credentials, options, logger = nullLogger$1) {
587
+ logger.info(`Querying metrics: ${options.query}`);
588
+ logger.info(`Time range: ${options.from} to ${options.to}`);
589
+ const queryParams = new URLSearchParams({
590
+ query: options.query,
591
+ from: options.from.toString(),
592
+ to: options.to.toString(),
593
+ });
594
+ return new Promise((resolve) => {
595
+ const requestOptions = {
596
+ hostname: "api.datadoghq.com",
597
+ port: 443,
598
+ path: `/api/v1/query?${queryParams.toString()}`,
599
+ method: "GET",
600
+ headers: {
601
+ "DD-API-KEY": credentials.apiKey,
602
+ "DD-APPLICATION-KEY": credentials.appKey,
603
+ },
604
+ };
605
+ const req = https.request(requestOptions, (res) => {
606
+ let data = "";
607
+ res.on("data", (chunk) => {
608
+ data += chunk.toString();
609
+ });
610
+ res.on("end", () => {
611
+ logger.info(`Response status: ${res.statusCode}`);
612
+ if (res.statusCode !== 200) {
613
+ logger.error(`Datadog Metrics API error: ${res.statusCode}`);
614
+ let errorMessage = `Datadog API returned status ${res.statusCode}: ${data}`;
615
+ if (res.statusCode === 400) {
616
+ errorMessage = `Invalid metric query. Check format: 'aggregation:metric.name{tags}'. Query: "${options.query}". Datadog error: ${data}`;
617
+ }
618
+ else if (res.statusCode === 403) {
619
+ errorMessage =
620
+ "Access denied. Verify your API and Application keys have metrics_read permission.";
621
+ }
622
+ else if (res.statusCode === 429) {
623
+ errorMessage =
624
+ "Rate limited by Datadog. Wait a moment and try again, or reduce your time range.";
625
+ }
626
+ resolve({
627
+ success: false,
628
+ query: options.query,
629
+ timeRange: { from: options.from, to: options.to },
630
+ series: [],
631
+ error: errorMessage,
632
+ });
633
+ return;
634
+ }
635
+ try {
636
+ const response = JSON.parse(data);
637
+ const series = (response.series || []).map((s) => ({
638
+ metric: s.metric,
639
+ scope: s.scope,
640
+ pointlist: s.pointlist,
641
+ unit: s.unit?.[0]?.name,
642
+ }));
643
+ logger.info(`Retrieved ${series.length} metric series`);
644
+ resolve({
645
+ success: true,
646
+ query: options.query,
647
+ timeRange: { from: options.from, to: options.to },
648
+ series,
649
+ });
650
+ }
651
+ catch (parseError) {
652
+ logger.error("Failed to parse Datadog metrics response:", parseError);
653
+ resolve({
654
+ success: false,
655
+ query: options.query,
656
+ timeRange: { from: options.from, to: options.to },
657
+ series: [],
658
+ error: `Failed to parse response: ${parseError instanceof Error ? parseError.message : "Unknown error"}`,
659
+ });
660
+ }
661
+ });
662
+ });
663
+ req.on("error", (error) => {
664
+ logger.error("Request error:", error);
665
+ resolve({
666
+ success: false,
667
+ query: options.query,
668
+ timeRange: { from: options.from, to: options.to },
669
+ series: [],
670
+ error: `Connection error: ${error.message}`,
671
+ });
672
+ });
673
+ req.end();
674
+ });
675
+ }
676
+ /**
677
+ * Search Datadog RUM events
678
+ */
679
+ async function searchDatadogRum(credentials, options = {}, logger = nullLogger$1) {
680
+ const effectiveQuery = options.query || "*";
681
+ const effectiveFrom = options.from || "now-15m";
682
+ const effectiveTo = options.to || "now";
683
+ const effectiveLimit = Math.min(options.limit || 50, 1000);
684
+ const effectiveSort = options.sort || "-timestamp";
685
+ logger.info(`RUM query: ${effectiveQuery}`);
686
+ logger.info(`Time range: ${effectiveFrom} to ${effectiveTo}`);
687
+ const requestBody = JSON.stringify({
688
+ filter: {
689
+ query: effectiveQuery,
690
+ from: effectiveFrom,
691
+ to: effectiveTo,
692
+ },
693
+ page: {
694
+ limit: effectiveLimit,
695
+ },
696
+ sort: effectiveSort,
697
+ });
698
+ return new Promise((resolve) => {
699
+ const requestOptions = {
700
+ hostname: "api.datadoghq.com",
701
+ port: 443,
702
+ path: "/api/v2/rum/events/search",
703
+ method: "POST",
704
+ headers: {
705
+ "Content-Type": "application/json",
706
+ "DD-API-KEY": credentials.apiKey,
707
+ "DD-APPLICATION-KEY": credentials.appKey,
708
+ "Content-Length": Buffer.byteLength(requestBody),
709
+ },
710
+ };
711
+ const req = https.request(requestOptions, (res) => {
712
+ let data = "";
713
+ res.on("data", (chunk) => {
714
+ data += chunk.toString();
715
+ });
716
+ res.on("end", () => {
717
+ logger.info(`Response status: ${res.statusCode}`);
718
+ if (res.statusCode !== 200) {
719
+ logger.error(`Datadog RUM API error: ${res.statusCode}`);
720
+ let errorMessage = `Datadog API returned status ${res.statusCode}: ${data}`;
721
+ // Check for specific "No valid indexes" error which means no RUM app is configured
722
+ if (data.includes("No valid indexes")) {
723
+ errorMessage =
724
+ "No RUM application found. Ensure you have a RUM application configured in Datadog and it has collected data. " +
725
+ "You can create a RUM application at https://app.datadoghq.com/rum/list";
726
+ }
727
+ else if (res.statusCode === 400) {
728
+ errorMessage = `Invalid RUM query. Check syntax: "${effectiveQuery}". Datadog error: ${data}`;
729
+ }
730
+ else if (res.statusCode === 403) {
731
+ errorMessage =
732
+ "Access denied. Verify your API and Application keys have rum_read permission.";
733
+ }
734
+ else if (res.statusCode === 429) {
735
+ errorMessage =
736
+ "Rate limited by Datadog. Wait a moment and try again, or reduce your query scope.";
737
+ }
738
+ resolve({
739
+ success: false,
740
+ query: effectiveQuery,
741
+ timeRange: { from: effectiveFrom, to: effectiveTo },
742
+ events: [],
743
+ error: errorMessage,
744
+ });
745
+ return;
746
+ }
747
+ try {
748
+ const response = JSON.parse(data);
749
+ const events = (response.data || []).map((event) => {
750
+ const attrs = event.attributes?.attributes || {};
751
+ return {
752
+ id: event.id,
753
+ type: event.type,
754
+ timestamp: event.attributes?.timestamp,
755
+ sessionId: attrs.session?.id,
756
+ viewUrl: attrs.view?.url,
757
+ viewName: attrs.view?.name,
758
+ errorMessage: attrs.error?.message,
759
+ errorType: attrs.error?.type,
760
+ attributes: attrs,
761
+ };
762
+ });
763
+ logger.info(`Retrieved ${events.length} RUM events`);
764
+ resolve({
765
+ success: true,
766
+ query: effectiveQuery,
767
+ timeRange: { from: effectiveFrom, to: effectiveTo },
768
+ events,
769
+ });
770
+ }
771
+ catch (parseError) {
772
+ logger.error("Failed to parse Datadog RUM response:", parseError);
773
+ resolve({
774
+ success: false,
775
+ query: effectiveQuery,
776
+ timeRange: { from: effectiveFrom, to: effectiveTo },
777
+ events: [],
778
+ error: `Failed to parse response: ${parseError instanceof Error ? parseError.message : "Unknown error"}`,
779
+ });
780
+ }
781
+ });
782
+ });
783
+ req.on("error", (error) => {
784
+ logger.error("Request error:", error);
785
+ resolve({
786
+ success: false,
787
+ query: effectiveQuery,
788
+ timeRange: { from: effectiveFrom, to: effectiveTo },
789
+ events: [],
790
+ error: `Connection error: ${error.message}`,
791
+ });
792
+ });
793
+ req.write(requestBody);
794
+ req.end();
795
+ });
796
+ }
797
+
798
+ /**
799
+ * LLM debugging utilities for inspecting raw provider responses
800
+ */
801
+ // Default models for each provider
802
+ const DEFAULT_MODELS = {
803
+ anthropic: "claude-sonnet-4-20250514",
804
+ gemini: "gemini-2.0-flash",
805
+ openai: "gpt-4o-mini",
806
+ openrouter: "openai/gpt-4o-mini",
807
+ };
808
+ /**
809
+ * Make a debug LLM call and return the raw response data for inspection
810
+ */
811
+ async function debugLlmCall(params, log) {
812
+ const { provider, message } = params;
813
+ const model = params.model || DEFAULT_MODELS[provider];
814
+ try {
815
+ const llm = new Llm(provider, { model });
816
+ const result = await llm.operate(message, {
817
+ user: "[jaypie-mcp] Debug LLM Call",
818
+ });
819
+ if (result.error) {
820
+ return {
821
+ success: false,
822
+ provider,
823
+ model,
824
+ error: `${result.error.title}: ${result.error.detail || "Unknown error"}`,
825
+ };
826
+ }
827
+ // Calculate total reasoning tokens
828
+ const reasoningTokens = result.usage.reduce((sum, u) => sum + (u.reasoning || 0), 0);
829
+ return {
830
+ success: true,
831
+ provider,
832
+ model,
833
+ content: typeof result.content === "string"
834
+ ? result.content
835
+ : JSON.stringify(result.content),
836
+ reasoning: result.reasoning,
837
+ reasoningTokens,
838
+ history: result.history,
839
+ rawResponses: result.responses,
840
+ usage: result.usage,
841
+ };
842
+ }
843
+ catch (error) {
844
+ return {
845
+ success: false,
846
+ provider,
847
+ model,
848
+ error: error instanceof Error ? error.message : String(error),
849
+ };
850
+ }
851
+ }
852
+ /**
853
+ * List available providers and their default/reasoning models
854
+ */
855
+ function listLlmProviders() {
856
+ return {
857
+ providers: [
858
+ {
859
+ name: "openai",
860
+ defaultModel: DEFAULT_MODELS.openai,
861
+ reasoningModels: ["o3-mini", "o1-preview", "o1-mini"],
862
+ },
863
+ {
864
+ name: "anthropic",
865
+ defaultModel: DEFAULT_MODELS.anthropic,
866
+ reasoningModels: [], // Anthropic doesn't expose reasoning the same way
867
+ },
868
+ {
869
+ name: "gemini",
870
+ defaultModel: DEFAULT_MODELS.gemini,
871
+ reasoningModels: [], // Gemini has thoughtsTokenCount but unclear on content
872
+ },
873
+ {
874
+ name: "openrouter",
875
+ defaultModel: DEFAULT_MODELS.openrouter,
876
+ reasoningModels: ["openai/o3-mini", "openai/o1-preview"],
877
+ },
878
+ ],
879
+ };
880
+ }
881
+
882
+ /**
883
+ * AWS CLI integration module
884
+ * Provides a structured interface for common AWS operations via the AWS CLI
885
+ */
886
+ const nullLogger = {
887
+ info: () => { },
888
+ error: () => { },
889
+ };
890
+ /**
891
+ * Parse AWS CLI error messages into user-friendly descriptions
892
+ */
893
+ function parseAwsError(stderr, service, command) {
894
+ if (stderr.includes("ExpiredToken") || stderr.includes("Token has expired")) {
895
+ return "AWS credentials have expired. Run 'aws sso login' or refresh your credentials.";
896
+ }
897
+ if (stderr.includes("NoCredentialProviders") ||
898
+ stderr.includes("Unable to locate credentials")) {
899
+ return "No AWS credentials found. Configure credentials with 'aws configure' or 'aws sso login'.";
900
+ }
901
+ if (stderr.includes("AccessDenied") || stderr.includes("Access Denied")) {
902
+ return `Access denied for ${service}:${command}. Check your IAM permissions.`;
903
+ }
904
+ if (stderr.includes("ResourceNotFoundException")) {
905
+ return `Resource not found. Check that the specified resource exists in the correct region.`;
906
+ }
907
+ if (stderr.includes("ValidationException")) {
908
+ const match = stderr.match(/ValidationException[^:]*:\s*(.+)/);
909
+ return match
910
+ ? `Validation error: ${match[1].trim()}`
911
+ : "Validation error in request parameters.";
912
+ }
913
+ if (stderr.includes("ThrottlingException") ||
914
+ stderr.includes("Rate exceeded")) {
915
+ return "AWS API rate limit exceeded. Wait a moment and try again.";
916
+ }
917
+ if (stderr.includes("InvalidParameterValue")) {
918
+ const match = stderr.match(/InvalidParameterValue[^:]*:\s*(.+)/);
919
+ return match
920
+ ? `Invalid parameter: ${match[1].trim()}`
921
+ : "Invalid parameter value provided.";
922
+ }
923
+ return stderr.trim();
924
+ }
925
+ /**
926
+ * Parse relative time strings like 'now-1h' to Unix timestamps
927
+ */
928
+ function parseRelativeTime(timeStr) {
929
+ const now = Date.now();
930
+ if (timeStr === "now") {
931
+ return now;
932
+ }
933
+ // Handle relative time like 'now-15m', 'now-1h', 'now-1d'
934
+ const relativeMatch = timeStr.match(/^now-(\d+)([smhd])$/);
935
+ if (relativeMatch) {
936
+ const value = parseInt(relativeMatch[1], 10);
937
+ const unit = relativeMatch[2];
938
+ const multipliers = {
939
+ s: 1000,
940
+ m: 60 * 1000,
941
+ h: 60 * 60 * 1000,
942
+ d: 24 * 60 * 60 * 1000,
943
+ };
944
+ return now - value * multipliers[unit];
945
+ }
946
+ // Handle ISO 8601 format
947
+ const parsed = Date.parse(timeStr);
948
+ if (!isNaN(parsed)) {
949
+ return parsed;
950
+ }
951
+ // Default to the current time if parsing fails
952
+ return now;
953
+ }
954
+ /**
955
+ * Execute an AWS CLI command and return parsed JSON output
956
+ */
957
+ async function executeAwsCommand(service, command, args, options = {}, logger = nullLogger) {
958
+ const fullArgs = [service, command, ...args, "--output", "json"];
959
+ if (options.profile) {
960
+ fullArgs.push("--profile", options.profile);
961
+ }
962
+ if (options.region) {
963
+ fullArgs.push("--region", options.region);
964
+ }
965
+ logger.info(`Executing: aws ${fullArgs.join(" ")}`);
966
+ return new Promise((resolve) => {
967
+ const proc = spawn("aws", fullArgs);
968
+ let stdout = "";
969
+ let stderr = "";
970
+ proc.stdout.on("data", (data) => {
971
+ stdout += data.toString();
972
+ });
973
+ proc.stderr.on("data", (data) => {
974
+ stderr += data.toString();
975
+ });
976
+ proc.on("close", (code) => {
977
+ if (code !== 0) {
978
+ logger.error(`AWS CLI error: ${stderr}`);
979
+ resolve({
980
+ success: false,
981
+ error: parseAwsError(stderr, service, command),
982
+ });
983
+ return;
984
+ }
985
+ // Handle empty output (some commands return nothing on success)
986
+ if (!stdout.trim()) {
987
+ resolve({ success: true });
988
+ return;
989
+ }
990
+ try {
991
+ const data = JSON.parse(stdout);
992
+ resolve({ success: true, data });
993
+ }
994
+ catch {
995
+ // Some commands return plain text
996
+ resolve({ success: true, data: stdout.trim() });
997
+ }
998
+ });
999
+ proc.on("error", (error) => {
1000
+ if (error.message.includes("ENOENT")) {
1001
+ resolve({
1002
+ success: false,
1003
+ error: "AWS CLI not found. Install it from https://aws.amazon.com/cli/",
1004
+ });
1005
+ }
1006
+ else {
1007
+ resolve({ success: false, error: error.message });
1008
+ }
1009
+ });
1010
+ });
1011
+ }
1012
+ /**
1013
+ * List available AWS profiles from ~/.aws/config and ~/.aws/credentials
1014
+ */
1015
+ async function listAwsProfiles(logger = nullLogger) {
1016
+ const profiles = [];
1017
+ const homeDir = os.homedir();
1018
+ try {
1019
+ // Parse ~/.aws/config
1020
+ const configPath = path.join(homeDir, ".aws", "config");
1021
+ try {
1022
+ const configContent = await fs.readFile(configPath, "utf-8");
1023
+ const profileRegex = /\[profile\s+([^\]]+)\]|\[default\]/g;
1024
+ let match;
1025
+ while ((match = profileRegex.exec(configContent)) !== null) {
1026
+ const name = match[1] || "default";
1027
+ profiles.push({
1028
+ name,
1029
+ source: "config",
1030
+ });
1031
+ }
1032
+ logger.info(`Found ${profiles.length} profiles in config`);
1033
+ }
1034
+ catch {
1035
+ logger.info("No ~/.aws/config file found");
1036
+ }
1037
+ // Parse ~/.aws/credentials
1038
+ const credentialsPath = path.join(homeDir, ".aws", "credentials");
1039
+ try {
1040
+ const credentialsContent = await fs.readFile(credentialsPath, "utf-8");
1041
+ const profileRegex = /\[([^\]]+)\]/g;
1042
+ let match;
1043
+ while ((match = profileRegex.exec(credentialsContent)) !== null) {
1044
+ const name = match[1];
1045
+ // Only add if not already in the list
1046
+ if (!profiles.find((p) => p.name === name)) {
1047
+ profiles.push({
1048
+ name,
1049
+ source: "credentials",
1050
+ });
1051
+ }
1052
+ }
1053
+ logger.info(`Total profiles after credentials: ${profiles.length}`);
1054
+ }
1055
+ catch {
1056
+ logger.info("No ~/.aws/credentials file found");
1057
+ }
1058
+ return { success: true, data: profiles };
1059
+ }
1060
+ catch (error) {
1061
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1062
+ logger.error(`Error listing profiles: ${errorMessage}`);
1063
+ return { success: false, error: errorMessage };
1064
+ }
1065
+ }
1066
+ // Step Functions operations
1067
+ async function listStepFunctionExecutions(options, logger = nullLogger) {
1068
+ const args = ["--state-machine-arn", options.stateMachineArn];
1069
+ if (options.statusFilter) {
1070
+ args.push("--status-filter", options.statusFilter);
1071
+ }
1072
+ if (options.maxResults) {
1073
+ args.push("--max-results", String(options.maxResults));
1074
+ }
1075
+ return executeAwsCommand("stepfunctions", "list-executions", args, { profile: options.profile, region: options.region }, logger);
1076
+ }
1077
+ async function stopStepFunctionExecution(options, logger = nullLogger) {
1078
+ const args = ["--execution-arn", options.executionArn];
1079
+ if (options.cause) {
1080
+ args.push("--cause", options.cause);
1081
+ }
1082
+ return executeAwsCommand("stepfunctions", "stop-execution", args, { profile: options.profile, region: options.region }, logger);
1083
+ }
1084
+ // Lambda operations
1085
+ async function listLambdaFunctions(options = {}, logger = nullLogger) {
1086
+ const args = [];
1087
+ if (options.maxResults) {
1088
+ args.push("--max-items", String(options.maxResults));
1089
+ }
1090
+ const result = await executeAwsCommand("lambda", "list-functions", args, { profile: options.profile, region: options.region }, logger);
1091
+ // Filter by prefix if specified
1092
+ if (result.success && result.data && options.functionNamePrefix) {
1093
+ result.data.Functions = result.data.Functions.filter((f) => f.FunctionName.startsWith(options.functionNamePrefix));
1094
+ }
1095
+ return result;
1096
+ }
1097
+ async function getLambdaFunction(options, logger = nullLogger) {
1098
+ return executeAwsCommand("lambda", "get-function", ["--function-name", options.functionName], { profile: options.profile, region: options.region }, logger);
1099
+ }
1100
+ // CloudWatch Logs operations
1101
+ async function filterLogEvents(options, logger = nullLogger) {
1102
+ const args = ["--log-group-name", options.logGroupName];
1103
+ if (options.filterPattern) {
1104
+ args.push("--filter-pattern", options.filterPattern);
1105
+ }
1106
+ if (options.startTime) {
1107
+ const startMs = parseRelativeTime(options.startTime);
1108
+ args.push("--start-time", String(startMs));
1109
+ }
1110
+ if (options.endTime) {
1111
+ const endMs = parseRelativeTime(options.endTime);
1112
+ args.push("--end-time", String(endMs));
1113
+ }
1114
+ {
1115
+ args.push("--limit", String(options.limit));
1116
+ }
1117
+ return executeAwsCommand("logs", "filter-log-events", args, { profile: options.profile, region: options.region }, logger);
1118
+ }
1119
+ // S3 operations
1120
+ async function listS3Objects(options, logger = nullLogger) {
1121
+ const args = ["--bucket", options.bucket];
1122
+ if (options.prefix) {
1123
+ args.push("--prefix", options.prefix);
1124
+ }
1125
+ if (options.maxResults) {
1126
+ args.push("--max-items", String(options.maxResults));
1127
+ }
1128
+ return executeAwsCommand("s3api", "list-objects-v2", args, { profile: options.profile, region: options.region }, logger);
1129
+ }
1130
+ // CloudFormation operations
1131
+ async function describeStack(options, logger = nullLogger) {
1132
+ return executeAwsCommand("cloudformation", "describe-stacks", ["--stack-name", options.stackName], { profile: options.profile, region: options.region }, logger);
1133
+ }
1134
+ // DynamoDB operations
1135
+ async function describeDynamoDBTable(options, logger = nullLogger) {
1136
+ return executeAwsCommand("dynamodb", "describe-table", ["--table-name", options.tableName], { profile: options.profile, region: options.region }, logger);
1137
+ }
1138
+ async function scanDynamoDB(options, logger = nullLogger) {
1139
+ const args = ["--table-name", options.tableName];
1140
+ if (options.filterExpression) {
1141
+ args.push("--filter-expression", options.filterExpression);
1142
+ }
1143
+ if (options.expressionAttributeValues) {
1144
+ args.push("--expression-attribute-values", options.expressionAttributeValues);
1145
+ }
1146
+ {
1147
+ args.push("--limit", String(options.limit));
1148
+ }
1149
+ return executeAwsCommand("dynamodb", "scan", args, { profile: options.profile, region: options.region }, logger);
1150
+ }
1151
+ async function queryDynamoDB(options, logger = nullLogger) {
1152
+ const args = [
1153
+ "--table-name",
1154
+ options.tableName,
1155
+ "--key-condition-expression",
1156
+ options.keyConditionExpression,
1157
+ "--expression-attribute-values",
1158
+ options.expressionAttributeValues,
1159
+ ];
1160
+ if (options.indexName) {
1161
+ args.push("--index-name", options.indexName);
1162
+ }
1163
+ if (options.filterExpression) {
1164
+ args.push("--filter-expression", options.filterExpression);
1165
+ }
1166
+ if (options.limit) {
1167
+ args.push("--limit", String(options.limit));
1168
+ }
1169
+ if (options.scanIndexForward === false) {
1170
+ args.push("--no-scan-index-forward");
1171
+ }
1172
+ return executeAwsCommand("dynamodb", "query", args, { profile: options.profile, region: options.region }, logger);
1173
+ }
1174
+ async function getDynamoDBItem(options, logger = nullLogger) {
1175
+ return executeAwsCommand("dynamodb", "get-item", ["--table-name", options.tableName, "--key", options.key], { profile: options.profile, region: options.region }, logger);
1176
+ }
1177
+ // SQS operations
1178
+ async function listSQSQueues(options = {}, logger = nullLogger) {
1179
+ const args = [];
1180
+ if (options.queueNamePrefix) {
1181
+ args.push("--queue-name-prefix", options.queueNamePrefix);
1182
+ }
1183
+ return executeAwsCommand("sqs", "list-queues", args, { profile: options.profile, region: options.region }, logger);
1184
+ }
1185
+ async function getSQSQueueAttributes(options, logger = nullLogger) {
1186
+ return executeAwsCommand("sqs", "get-queue-attributes", ["--queue-url", options.queueUrl, "--attribute-names", "All"], { profile: options.profile, region: options.region }, logger);
1187
+ }
1188
+ async function receiveSQSMessage(options, logger = nullLogger) {
1189
+ const args = ["--queue-url", options.queueUrl];
1190
+ {
1191
+ args.push("--max-number-of-messages", String(options.maxNumberOfMessages));
1192
+ }
1193
+ {
1194
+ args.push("--visibility-timeout", String(options.visibilityTimeout));
1195
+ }
1196
+ args.push("--attribute-names", "All");
1197
+ return executeAwsCommand("sqs", "receive-message", args, { profile: options.profile, region: options.region }, logger);
1198
+ }
1199
+ async function purgeSQSQueue(options, logger = nullLogger) {
1200
+ return executeAwsCommand("sqs", "purge-queue", ["--queue-url", options.queueUrl], { profile: options.profile, region: options.region }, logger);
1201
+ }
12
1202
 
13
1203
  // ServiceSuite for @jaypie/mcp
14
1204
  // Provides metadata and direct execution for Jaypie MCP services
15
- const BUILD_VERSION_STRING = "@jaypie/mcp@0.3.4#a6510094"
1205
+ const BUILD_VERSION_STRING = "@jaypie/mcp@0.4.0#988a2bd8"
16
1206
  ;
17
1207
  const __filename$1 = fileURLToPath(import.meta.url);
18
1208
  const __dirname$1 = path.dirname(__filename$1);
@@ -631,7 +1821,7 @@ const llmDebugCall = fabricService({
631
1821
  provider: input.provider,
632
1822
  model: input.model,
633
1823
  message: input.message,
634
- }, log);
1824
+ });
635
1825
  if (!result.success) {
636
1826
  throw new Error(result.error);
637
1827
  }