@jaypie/mcp 0.3.1 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aws-B3dW_-bD.js +1202 -0
- package/dist/aws-B3dW_-bD.js.map +1 -0
- package/dist/index.js +357 -1200
- package/dist/index.js.map +1 -1
- package/dist/suite.d.ts +1 -0
- package/dist/suite.js +1252 -0
- package/dist/suite.js.map +1 -0
- package/package.json +11 -2
- package/prompts/Jaypie_Fabric_MCP.md +22 -2
- package/prompts/Jaypie_Fabric_Package.md +86 -0
- package/prompts/Jaypie_MCP_Package.md +34 -2
- package/release-notes/constructs/1.2.17.md +11 -0
- package/release-notes/fabric/0.1.1.md +17 -0
- package/release-notes/fabric/0.1.2.md +11 -0
- package/release-notes/mcp/0.3.2.md +14 -0
- package/release-notes/mcp/0.3.3.md +12 -0
- package/release-notes/mcp/0.3.4.md +36 -0
- package/skills/agents.md +25 -0
- package/skills/aws.md +107 -0
- package/skills/cdk.md +141 -0
- package/skills/cicd.md +152 -0
- package/skills/datadog.md +129 -0
- package/skills/debugging.md +148 -0
- package/skills/dns.md +134 -0
- package/skills/dynamodb.md +140 -0
- package/skills/errors.md +142 -0
- package/skills/fabric.md +164 -0
- package/skills/index.md +7 -0
- package/skills/jaypie.md +100 -0
- package/skills/legacy.md +97 -0
- package/skills/logs.md +160 -0
- package/skills/mocks.md +174 -0
- package/skills/models.md +195 -0
- package/skills/releasenotes.md +94 -0
- package/skills/secrets.md +155 -0
- package/skills/services.md +175 -0
- package/skills/style.md +190 -0
- package/skills/tests.md +209 -0
- package/skills/tools.md +127 -0
- package/skills/topics.md +116 -0
- package/skills/variables.md +146 -0
- package/skills/writing.md +153 -0
package/dist/suite.js
ADDED
|
@@ -0,0 +1,1252 @@
|
|
|
1
|
+
import { fabricService, createServiceSuite } from '@jaypie/fabric';
|
|
2
|
+
import * as fs from 'node:fs/promises';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import matter from 'gray-matter';
|
|
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';
|
|
12
|
+
|
|
13
|
+
// ServiceSuite for @jaypie/mcp
|
|
14
|
+
// Provides metadata and direct execution for Jaypie MCP services
|
|
15
|
+
const BUILD_VERSION_STRING = "@jaypie/mcp@0.3.4#a6510094"
|
|
16
|
+
;
|
|
17
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
18
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
19
|
+
const PROMPTS_PATH = path.join(__dirname$1, "..", "prompts");
|
|
20
|
+
const RELEASE_NOTES_PATH = path.join(__dirname$1, "..", "release-notes");
|
|
21
|
+
const SKILLS_PATH = path.join(__dirname$1, "..", "skills");
|
|
22
|
+
// Silent logger for direct execution
|
|
23
|
+
const log = {
|
|
24
|
+
info: () => { },
|
|
25
|
+
error: () => { },
|
|
26
|
+
};
|
|
27
|
+
async function parseMarkdownFile(filePath) {
|
|
28
|
+
try {
|
|
29
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
30
|
+
const filename = path.basename(filePath);
|
|
31
|
+
if (content.startsWith("---")) {
|
|
32
|
+
const parsed = matter(content);
|
|
33
|
+
const frontMatter = parsed.data;
|
|
34
|
+
return {
|
|
35
|
+
filename,
|
|
36
|
+
description: frontMatter.description,
|
|
37
|
+
include: frontMatter.include || frontMatter.globs,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return { filename };
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return { filename: path.basename(filePath) };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function formatPromptListItem(prompt) {
|
|
47
|
+
const { filename, description, include } = prompt;
|
|
48
|
+
if (description && include) {
|
|
49
|
+
return `* ${filename}: ${description} - Required for ${include}`;
|
|
50
|
+
}
|
|
51
|
+
else if (description) {
|
|
52
|
+
return `* ${filename}: ${description}`;
|
|
53
|
+
}
|
|
54
|
+
else if (include) {
|
|
55
|
+
return `* ${filename} - Required for ${include}`;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return `* ${filename}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function parseReleaseNoteFile(filePath) {
|
|
62
|
+
try {
|
|
63
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
64
|
+
const filename = path.basename(filePath, ".md");
|
|
65
|
+
if (content.startsWith("---")) {
|
|
66
|
+
const parsed = matter(content);
|
|
67
|
+
const frontMatter = parsed.data;
|
|
68
|
+
return {
|
|
69
|
+
date: frontMatter.date,
|
|
70
|
+
filename,
|
|
71
|
+
summary: frontMatter.summary,
|
|
72
|
+
version: frontMatter.version || filename,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return { filename, version: filename };
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return { filename: path.basename(filePath, ".md") };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function formatReleaseNoteListItem(note) {
|
|
82
|
+
const { date, packageName, summary, version } = note;
|
|
83
|
+
const parts = [`* ${packageName}@${version}`];
|
|
84
|
+
if (date) {
|
|
85
|
+
parts.push(`(${date})`);
|
|
86
|
+
}
|
|
87
|
+
if (summary) {
|
|
88
|
+
parts.push(`- ${summary}`);
|
|
89
|
+
}
|
|
90
|
+
return parts.join(" ");
|
|
91
|
+
}
|
|
92
|
+
function isValidSkillAlias(alias) {
|
|
93
|
+
const normalized = alias.toLowerCase().trim();
|
|
94
|
+
// Reject if contains path separators or traversal
|
|
95
|
+
if (normalized.includes("/") ||
|
|
96
|
+
normalized.includes("\\") ||
|
|
97
|
+
normalized.includes("..")) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
// Only allow alphanumeric, hyphens, underscores
|
|
101
|
+
return /^[a-z0-9_-]+$/.test(normalized);
|
|
102
|
+
}
|
|
103
|
+
async function parseSkillFile(filePath) {
|
|
104
|
+
try {
|
|
105
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
106
|
+
const alias = path.basename(filePath, ".md");
|
|
107
|
+
if (content.startsWith("---")) {
|
|
108
|
+
const parsed = matter(content);
|
|
109
|
+
const frontMatter = parsed.data;
|
|
110
|
+
return {
|
|
111
|
+
alias,
|
|
112
|
+
description: frontMatter.description,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return { alias };
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return { alias: path.basename(filePath, ".md") };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function formatSkillListItem(skill) {
|
|
122
|
+
const { alias, description } = skill;
|
|
123
|
+
if (description) {
|
|
124
|
+
return `* ${alias} - ${description}`;
|
|
125
|
+
}
|
|
126
|
+
return `* ${alias}`;
|
|
127
|
+
}
|
|
128
|
+
async function getPackageReleaseNotes(packageName) {
|
|
129
|
+
const packageDir = path.join(RELEASE_NOTES_PATH, packageName);
|
|
130
|
+
try {
|
|
131
|
+
const files = await fs.readdir(packageDir);
|
|
132
|
+
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
133
|
+
const notes = await Promise.all(mdFiles.map(async (file) => {
|
|
134
|
+
const parsed = await parseReleaseNoteFile(path.join(packageDir, file));
|
|
135
|
+
return { ...parsed, packageName };
|
|
136
|
+
}));
|
|
137
|
+
return notes.sort((a, b) => {
|
|
138
|
+
if (!a.version || !b.version)
|
|
139
|
+
return 0;
|
|
140
|
+
try {
|
|
141
|
+
return gt(a.version, b.version) ? -1 : 1;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return b.version.localeCompare(a.version);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function filterReleaseNotesSince(notes, sinceVersion) {
|
|
153
|
+
return notes.filter((note) => {
|
|
154
|
+
if (!note.version)
|
|
155
|
+
return false;
|
|
156
|
+
try {
|
|
157
|
+
return gt(note.version, sinceVersion);
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// =============================================================================
|
|
165
|
+
// DOCS SERVICES
|
|
166
|
+
// =============================================================================
|
|
167
|
+
const version = fabricService({
|
|
168
|
+
alias: "version",
|
|
169
|
+
description: `Prints the current version and hash, \`${BUILD_VERSION_STRING}\``,
|
|
170
|
+
input: {},
|
|
171
|
+
service: async () => BUILD_VERSION_STRING,
|
|
172
|
+
});
|
|
173
|
+
const skill = fabricService({
|
|
174
|
+
alias: "skill",
|
|
175
|
+
description: "Access Jaypie development documentation. Pass a skill alias (e.g., 'aws', 'tests', 'errors') to get that documentation. Pass 'index' or no argument to list all available skills.",
|
|
176
|
+
input: {
|
|
177
|
+
alias: {
|
|
178
|
+
type: String,
|
|
179
|
+
required: false,
|
|
180
|
+
description: "Skill alias (e.g., 'aws', 'tests'). Omit or use 'index' to list all skills.",
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
service: async ({ alias: inputAlias }) => {
|
|
184
|
+
const alias = (inputAlias || "index").toLowerCase().trim();
|
|
185
|
+
// Security: validate alias to prevent path traversal
|
|
186
|
+
if (!isValidSkillAlias(alias)) {
|
|
187
|
+
throw new Error(`Invalid skill alias "${alias}". Use alphanumeric characters, hyphens, and underscores only.`);
|
|
188
|
+
}
|
|
189
|
+
// If requesting index, return list of all skills with descriptions
|
|
190
|
+
if (alias === "index") {
|
|
191
|
+
const indexPath = path.join(SKILLS_PATH, "index.md");
|
|
192
|
+
let indexContent = "";
|
|
193
|
+
try {
|
|
194
|
+
indexContent = await fs.readFile(indexPath, "utf-8");
|
|
195
|
+
// Strip frontmatter for display
|
|
196
|
+
if (indexContent.startsWith("---")) {
|
|
197
|
+
const parsed = matter(indexContent);
|
|
198
|
+
indexContent = parsed.content.trim();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// Index file doesn't exist, will just show skill list
|
|
203
|
+
}
|
|
204
|
+
// Get all skill files
|
|
205
|
+
const files = await fs.readdir(SKILLS_PATH);
|
|
206
|
+
const mdFiles = files.filter((file) => file.endsWith(".md") && file !== "index.md");
|
|
207
|
+
const skills = await Promise.all(mdFiles.map((file) => parseSkillFile(path.join(SKILLS_PATH, file))));
|
|
208
|
+
// Sort alphabetically
|
|
209
|
+
skills.sort((a, b) => a.alias.localeCompare(b.alias));
|
|
210
|
+
const skillList = skills.map(formatSkillListItem).join("\n");
|
|
211
|
+
if (indexContent) {
|
|
212
|
+
return `${indexContent}\n\n## Available Skills\n\n${skillList}`;
|
|
213
|
+
}
|
|
214
|
+
return `# Jaypie Skills\n\n## Available Skills\n\n${skillList}`;
|
|
215
|
+
}
|
|
216
|
+
// Read specific skill file
|
|
217
|
+
const skillPath = path.join(SKILLS_PATH, `${alias}.md`);
|
|
218
|
+
try {
|
|
219
|
+
return await fs.readFile(skillPath, "utf-8");
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
throw new Error(`Skill "${alias}" not found. Use skill("index") to list available skills.`);
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
const listPrompts = fabricService({
|
|
227
|
+
alias: "list_prompts",
|
|
228
|
+
description: "[DEPRECATED: Use skill('index') instead] List available Jaypie development prompts and guides. Use this FIRST when starting work on a Jaypie project to discover relevant documentation. Returns filenames, descriptions, and which file patterns each prompt applies to (e.g., 'Required for packages/express/**').",
|
|
229
|
+
input: {},
|
|
230
|
+
service: async () => {
|
|
231
|
+
const files = await fs.readdir(PROMPTS_PATH);
|
|
232
|
+
const mdFiles = files.filter((file) => file.endsWith(".md"));
|
|
233
|
+
const prompts = await Promise.all(mdFiles.map((file) => parseMarkdownFile(path.join(PROMPTS_PATH, file))));
|
|
234
|
+
return (prompts.map(formatPromptListItem).join("\n") ||
|
|
235
|
+
"No .md files found in the prompts directory.");
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
const readPrompt = fabricService({
|
|
239
|
+
alias: "read_prompt",
|
|
240
|
+
description: "[DEPRECATED: Use skill(alias) instead] Read a Jaypie prompt/guide by filename. Call list_prompts first to see available prompts. These contain best practices, templates, code patterns, and step-by-step guides for Jaypie development tasks.",
|
|
241
|
+
input: {
|
|
242
|
+
filename: {
|
|
243
|
+
type: String,
|
|
244
|
+
required: true,
|
|
245
|
+
description: "The prompt filename from list_prompts (e.g., 'Jaypie_Express_Package.md', 'Development_Process.md')",
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
service: async ({ filename }) => {
|
|
249
|
+
const filePath = path.join(PROMPTS_PATH, filename);
|
|
250
|
+
return fs.readFile(filePath, "utf-8");
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
const listReleaseNotes = fabricService({
|
|
254
|
+
alias: "list_release_notes",
|
|
255
|
+
description: "List available release notes for Jaypie packages. Filter by package name and/or get only versions newer than a specified version.",
|
|
256
|
+
input: {
|
|
257
|
+
package: {
|
|
258
|
+
type: String,
|
|
259
|
+
required: false,
|
|
260
|
+
description: "Filter by package name (e.g., 'jaypie', 'mcp'). If not provided, lists release notes for all packages.",
|
|
261
|
+
},
|
|
262
|
+
since_version: {
|
|
263
|
+
type: String,
|
|
264
|
+
required: false,
|
|
265
|
+
description: "Only show versions newer than this (e.g., '1.0.0'). Uses semver comparison.",
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
service: async ({ package: packageFilter, since_version: sinceVersion, }) => {
|
|
269
|
+
const entries = await fs.readdir(RELEASE_NOTES_PATH, {
|
|
270
|
+
withFileTypes: true,
|
|
271
|
+
});
|
|
272
|
+
const packageDirs = entries
|
|
273
|
+
.filter((entry) => entry.isDirectory())
|
|
274
|
+
.map((entry) => entry.name);
|
|
275
|
+
const packagesToList = packageFilter
|
|
276
|
+
? packageDirs.filter((pkg) => pkg === packageFilter)
|
|
277
|
+
: packageDirs;
|
|
278
|
+
if (packagesToList.length === 0 && packageFilter) {
|
|
279
|
+
return `No release notes found for package "${packageFilter}".`;
|
|
280
|
+
}
|
|
281
|
+
const allNotes = await Promise.all(packagesToList.map((pkg) => getPackageReleaseNotes(pkg)));
|
|
282
|
+
let flatNotes = allNotes.flat();
|
|
283
|
+
if (sinceVersion) {
|
|
284
|
+
flatNotes = filterReleaseNotesSince(flatNotes, sinceVersion);
|
|
285
|
+
}
|
|
286
|
+
if (flatNotes.length === 0) {
|
|
287
|
+
const filterDesc = sinceVersion ? ` newer than ${sinceVersion}` : "";
|
|
288
|
+
return `No release notes found${filterDesc}.`;
|
|
289
|
+
}
|
|
290
|
+
return flatNotes.map(formatReleaseNoteListItem).join("\n");
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
const readReleaseNote = fabricService({
|
|
294
|
+
alias: "read_release_note",
|
|
295
|
+
description: "Read the full content of a specific release note. Call list_release_notes first to see available versions.",
|
|
296
|
+
input: {
|
|
297
|
+
package: {
|
|
298
|
+
type: String,
|
|
299
|
+
required: true,
|
|
300
|
+
description: "Package name (e.g., 'jaypie', 'mcp')",
|
|
301
|
+
},
|
|
302
|
+
version: {
|
|
303
|
+
type: String,
|
|
304
|
+
required: true,
|
|
305
|
+
description: "Version number (e.g., '1.2.3')",
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
service: async ({ package: packageName, version: ver, }) => {
|
|
309
|
+
const filePath = path.join(RELEASE_NOTES_PATH, packageName, `${ver}.md`);
|
|
310
|
+
return fs.readFile(filePath, "utf-8");
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
// =============================================================================
|
|
314
|
+
// DATADOG SERVICES
|
|
315
|
+
// =============================================================================
|
|
316
|
+
const datadogLogs = fabricService({
|
|
317
|
+
alias: "datadog_logs",
|
|
318
|
+
description: "Search and retrieve individual Datadog log entries. Use this to view actual log messages and details. For aggregated counts/statistics (e.g., 'how many errors by service?'), use datadog_log_analytics instead. Requires DATADOG_API_KEY and DATADOG_APP_KEY environment variables.",
|
|
319
|
+
input: {
|
|
320
|
+
query: {
|
|
321
|
+
type: String,
|
|
322
|
+
required: false,
|
|
323
|
+
description: "Search query to filter logs. Examples: 'status:error', '@http.status_code:500', '*timeout*', '@requestId:abc123'. Combined with DD_ENV, DD_SERVICE, DD_SOURCE env vars if set.",
|
|
324
|
+
},
|
|
325
|
+
source: {
|
|
326
|
+
type: String,
|
|
327
|
+
required: false,
|
|
328
|
+
description: "Override the log source (e.g., 'lambda', 'auth0', 'nginx'). If not provided, uses DD_SOURCE env var or defaults to 'lambda'.",
|
|
329
|
+
},
|
|
330
|
+
env: {
|
|
331
|
+
type: String,
|
|
332
|
+
required: false,
|
|
333
|
+
description: "Override the environment (e.g., 'sandbox', 'kitchen', 'lab', 'studio', 'production'). If not provided, uses DD_ENV env var.",
|
|
334
|
+
},
|
|
335
|
+
service: {
|
|
336
|
+
type: String,
|
|
337
|
+
required: false,
|
|
338
|
+
description: "Override the service name. If not provided, uses DD_SERVICE env var.",
|
|
339
|
+
},
|
|
340
|
+
from: {
|
|
341
|
+
type: String,
|
|
342
|
+
required: false,
|
|
343
|
+
description: "Start time. Formats: relative ('now-15m', 'now-1h', 'now-1d'), ISO 8601 ('2024-01-15T10:00:00Z'). Defaults to 'now-15m'.",
|
|
344
|
+
},
|
|
345
|
+
to: {
|
|
346
|
+
type: String,
|
|
347
|
+
required: false,
|
|
348
|
+
description: "End time. Formats: 'now', relative ('now-5m'), or ISO 8601. Defaults to 'now'.",
|
|
349
|
+
},
|
|
350
|
+
limit: {
|
|
351
|
+
type: Number,
|
|
352
|
+
required: false,
|
|
353
|
+
description: "Max logs to return (1-1000). Defaults to 50.",
|
|
354
|
+
},
|
|
355
|
+
sort: {
|
|
356
|
+
type: ["timestamp", "-timestamp"],
|
|
357
|
+
required: false,
|
|
358
|
+
description: "Sort order: 'timestamp' (oldest first) or '-timestamp' (newest first, default).",
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
service: async (input) => {
|
|
362
|
+
const credentials = getDatadogCredentials();
|
|
363
|
+
if (!credentials) {
|
|
364
|
+
throw new Error("Datadog credentials not found. Set DATADOG_API_KEY and DATADOG_APP_KEY.");
|
|
365
|
+
}
|
|
366
|
+
const result = await searchDatadogLogs(credentials, input, log);
|
|
367
|
+
if (!result.success) {
|
|
368
|
+
throw new Error(result.error);
|
|
369
|
+
}
|
|
370
|
+
return result;
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
const datadogLogAnalytics = fabricService({
|
|
374
|
+
alias: "datadog_log_analytics",
|
|
375
|
+
description: "Aggregate and analyze Datadog logs by grouping them by fields. Use this for statistics and counts (e.g., 'errors by service', 'requests by status code'). For viewing individual log entries, use datadog_logs instead.",
|
|
376
|
+
input: {
|
|
377
|
+
groupBy: {
|
|
378
|
+
type: [String],
|
|
379
|
+
required: true,
|
|
380
|
+
description: "Fields to group by. Examples: ['source'], ['service', 'status'], ['@http.status_code']. Common facets: source, service, status, host, @http.status_code, @env.",
|
|
381
|
+
},
|
|
382
|
+
query: {
|
|
383
|
+
type: String,
|
|
384
|
+
required: false,
|
|
385
|
+
description: "Filter query. Examples: 'status:error', '*timeout*', '@http.method:POST'. Use '*' for all logs.",
|
|
386
|
+
},
|
|
387
|
+
source: {
|
|
388
|
+
type: String,
|
|
389
|
+
required: false,
|
|
390
|
+
description: "Override the log source filter. Use '*' to include all sources. If not provided, uses DD_SOURCE env var or defaults to 'lambda'.",
|
|
391
|
+
},
|
|
392
|
+
env: {
|
|
393
|
+
type: String,
|
|
394
|
+
required: false,
|
|
395
|
+
description: "Override the environment filter. If not provided, uses DD_ENV env var.",
|
|
396
|
+
},
|
|
397
|
+
service: {
|
|
398
|
+
type: String,
|
|
399
|
+
required: false,
|
|
400
|
+
description: "Override the service name filter. If not provided, uses DD_SERVICE env var.",
|
|
401
|
+
},
|
|
402
|
+
from: {
|
|
403
|
+
type: String,
|
|
404
|
+
required: false,
|
|
405
|
+
description: "Start time. Formats: relative ('now-15m', 'now-1h', 'now-1d'), ISO 8601 ('2024-01-15T10:00:00Z'). Defaults to 'now-15m'.",
|
|
406
|
+
},
|
|
407
|
+
to: {
|
|
408
|
+
type: String,
|
|
409
|
+
required: false,
|
|
410
|
+
description: "End time. Formats: 'now', relative ('now-5m'), or ISO 8601. Defaults to 'now'.",
|
|
411
|
+
},
|
|
412
|
+
aggregation: {
|
|
413
|
+
type: ["count", "avg", "sum", "min", "max", "cardinality"],
|
|
414
|
+
required: false,
|
|
415
|
+
description: "Aggregation type. 'count' counts logs, others require a metric field. Defaults to 'count'.",
|
|
416
|
+
},
|
|
417
|
+
metric: {
|
|
418
|
+
type: String,
|
|
419
|
+
required: false,
|
|
420
|
+
description: "Metric field to aggregate when using avg, sum, min, max, or cardinality. E.g., '@duration', '@http.response_time'.",
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
service: async (input) => {
|
|
424
|
+
const credentials = getDatadogCredentials();
|
|
425
|
+
if (!credentials) {
|
|
426
|
+
throw new Error("Datadog credentials not found. Set DATADOG_API_KEY and DATADOG_APP_KEY.");
|
|
427
|
+
}
|
|
428
|
+
const compute = input.aggregation
|
|
429
|
+
? [{ aggregation: input.aggregation, metric: input.metric }]
|
|
430
|
+
: [{ aggregation: "count" }];
|
|
431
|
+
const result = await aggregateDatadogLogs(credentials, { ...input, compute }, log);
|
|
432
|
+
if (!result.success) {
|
|
433
|
+
throw new Error(result.error);
|
|
434
|
+
}
|
|
435
|
+
return result;
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
const datadogMonitors = fabricService({
|
|
439
|
+
alias: "datadog_monitors",
|
|
440
|
+
description: "List and check Datadog monitors. Shows monitor status (Alert, Warn, No Data, OK), name, type, and tags. Useful for quickly checking if any monitors are alerting.",
|
|
441
|
+
input: {
|
|
442
|
+
status: {
|
|
443
|
+
type: Array,
|
|
444
|
+
required: false,
|
|
445
|
+
description: "Filter monitors by status. E.g., ['Alert', 'Warn'] to see only alerting monitors.",
|
|
446
|
+
},
|
|
447
|
+
tags: {
|
|
448
|
+
type: Array,
|
|
449
|
+
required: false,
|
|
450
|
+
description: "Filter monitors by resource tags (tags on the monitored resources).",
|
|
451
|
+
},
|
|
452
|
+
monitorTags: {
|
|
453
|
+
type: Array,
|
|
454
|
+
required: false,
|
|
455
|
+
description: "Filter monitors by monitor tags (tags on the monitor itself).",
|
|
456
|
+
},
|
|
457
|
+
name: {
|
|
458
|
+
type: String,
|
|
459
|
+
required: false,
|
|
460
|
+
description: "Filter monitors by name (partial match supported).",
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
service: async (input) => {
|
|
464
|
+
const credentials = getDatadogCredentials();
|
|
465
|
+
if (!credentials) {
|
|
466
|
+
throw new Error("Datadog credentials not found. Set DATADOG_API_KEY and DATADOG_APP_KEY.");
|
|
467
|
+
}
|
|
468
|
+
const result = await listDatadogMonitors(credentials, input, log);
|
|
469
|
+
if (!result.success) {
|
|
470
|
+
throw new Error(result.error);
|
|
471
|
+
}
|
|
472
|
+
return result;
|
|
473
|
+
},
|
|
474
|
+
});
|
|
475
|
+
const datadogSynthetics = fabricService({
|
|
476
|
+
alias: "datadog_synthetics",
|
|
477
|
+
description: "List Datadog Synthetic tests and optionally get recent results for a specific test. Shows test status, type (api/browser), and locations.",
|
|
478
|
+
input: {
|
|
479
|
+
type: {
|
|
480
|
+
type: ["api", "browser"],
|
|
481
|
+
required: false,
|
|
482
|
+
description: "Filter tests by type: 'api' or 'browser'.",
|
|
483
|
+
},
|
|
484
|
+
tags: {
|
|
485
|
+
type: Array,
|
|
486
|
+
required: false,
|
|
487
|
+
description: "Filter tests by tags.",
|
|
488
|
+
},
|
|
489
|
+
testId: {
|
|
490
|
+
type: String,
|
|
491
|
+
required: false,
|
|
492
|
+
description: "If provided, fetches recent results for this specific test (public_id). Otherwise lists all tests.",
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
service: async (input) => {
|
|
496
|
+
const credentials = getDatadogCredentials();
|
|
497
|
+
if (!credentials) {
|
|
498
|
+
throw new Error("Datadog credentials not found. Set DATADOG_API_KEY and DATADOG_APP_KEY.");
|
|
499
|
+
}
|
|
500
|
+
if (input.testId) {
|
|
501
|
+
const result = await getDatadogSyntheticResults(credentials, input.testId, log);
|
|
502
|
+
if (!result.success) {
|
|
503
|
+
throw new Error(result.error);
|
|
504
|
+
}
|
|
505
|
+
return result;
|
|
506
|
+
}
|
|
507
|
+
const result = await listDatadogSynthetics(credentials, input, log);
|
|
508
|
+
if (!result.success) {
|
|
509
|
+
throw new Error(result.error);
|
|
510
|
+
}
|
|
511
|
+
return result;
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
const datadogMetrics = fabricService({
|
|
515
|
+
alias: "datadog_metrics",
|
|
516
|
+
description: "Query Datadog metrics. Returns timeseries data for the specified metric query. Useful for checking specific metric values.",
|
|
517
|
+
input: {
|
|
518
|
+
query: {
|
|
519
|
+
type: String,
|
|
520
|
+
required: true,
|
|
521
|
+
description: "Metric query. Format: 'aggregation:metric.name{tags}'. Examples: 'avg:system.cpu.user{*}', 'sum:aws.lambda.invocations{function:my-func}.as_count()', 'max:aws.lambda.duration{env:production}'.",
|
|
522
|
+
},
|
|
523
|
+
from: {
|
|
524
|
+
type: String,
|
|
525
|
+
required: false,
|
|
526
|
+
description: "Start time. Formats: relative ('1h', '30m', '1d'), or Unix timestamp. Defaults to '1h'.",
|
|
527
|
+
},
|
|
528
|
+
to: {
|
|
529
|
+
type: String,
|
|
530
|
+
required: false,
|
|
531
|
+
description: "End time. Formats: 'now' or Unix timestamp. Defaults to 'now'.",
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
service: async (input) => {
|
|
535
|
+
const credentials = getDatadogCredentials();
|
|
536
|
+
if (!credentials) {
|
|
537
|
+
throw new Error("Datadog credentials not found. Set DATADOG_API_KEY and DATADOG_APP_KEY.");
|
|
538
|
+
}
|
|
539
|
+
const now = Math.floor(Date.now() / 1000);
|
|
540
|
+
const fromStr = input.from || "1h";
|
|
541
|
+
let fromTs;
|
|
542
|
+
if (fromStr.match(/^\d+$/)) {
|
|
543
|
+
fromTs = parseInt(fromStr, 10);
|
|
544
|
+
}
|
|
545
|
+
else if (fromStr.match(/^(\d+)h$/)) {
|
|
546
|
+
const hours = parseInt(fromStr.match(/^(\d+)h$/)[1], 10);
|
|
547
|
+
fromTs = now - hours * 3600;
|
|
548
|
+
}
|
|
549
|
+
else if (fromStr.match(/^(\d+)m$/)) {
|
|
550
|
+
const minutes = parseInt(fromStr.match(/^(\d+)m$/)[1], 10);
|
|
551
|
+
fromTs = now - minutes * 60;
|
|
552
|
+
}
|
|
553
|
+
else if (fromStr.match(/^(\d+)d$/)) {
|
|
554
|
+
const days = parseInt(fromStr.match(/^(\d+)d$/)[1], 10);
|
|
555
|
+
fromTs = now - days * 86400;
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
fromTs = now - 3600;
|
|
559
|
+
}
|
|
560
|
+
const toStr = input.to || "now";
|
|
561
|
+
const toTs = toStr === "now" ? now : parseInt(toStr, 10);
|
|
562
|
+
const result = await queryDatadogMetrics(credentials, { query: input.query, from: fromTs, to: toTs }, log);
|
|
563
|
+
if (!result.success) {
|
|
564
|
+
throw new Error(result.error);
|
|
565
|
+
}
|
|
566
|
+
return result;
|
|
567
|
+
},
|
|
568
|
+
});
|
|
569
|
+
const datadogRum = fabricService({
|
|
570
|
+
alias: "datadog_rum",
|
|
571
|
+
description: "Search Datadog RUM (Real User Monitoring) events. Find user sessions, page views, errors, and actions. Useful for debugging frontend issues and understanding user behavior.",
|
|
572
|
+
input: {
|
|
573
|
+
query: {
|
|
574
|
+
type: String,
|
|
575
|
+
required: false,
|
|
576
|
+
description: "RUM search query. E.g., '@type:error', '@session.id:abc123', '@view.url:*checkout*'. Defaults to '*' (all events).",
|
|
577
|
+
},
|
|
578
|
+
from: {
|
|
579
|
+
type: String,
|
|
580
|
+
required: false,
|
|
581
|
+
description: "Start time. Formats: relative ('now-15m', 'now-1h', 'now-1d'), ISO 8601 ('2024-01-15T10:00:00Z'). Defaults to 'now-15m'.",
|
|
582
|
+
},
|
|
583
|
+
to: {
|
|
584
|
+
type: String,
|
|
585
|
+
required: false,
|
|
586
|
+
description: "End time. Formats: 'now', relative ('now-5m'), or ISO 8601. Defaults to 'now'.",
|
|
587
|
+
},
|
|
588
|
+
limit: {
|
|
589
|
+
type: Number,
|
|
590
|
+
required: false,
|
|
591
|
+
description: "Max events to return (1-1000). Defaults to 50.",
|
|
592
|
+
},
|
|
593
|
+
},
|
|
594
|
+
service: async (input) => {
|
|
595
|
+
const credentials = getDatadogCredentials();
|
|
596
|
+
if (!credentials) {
|
|
597
|
+
throw new Error("Datadog credentials not found. Set DATADOG_API_KEY and DATADOG_APP_KEY.");
|
|
598
|
+
}
|
|
599
|
+
const result = await searchDatadogRum(credentials, input, log);
|
|
600
|
+
if (!result.success) {
|
|
601
|
+
throw new Error(result.error);
|
|
602
|
+
}
|
|
603
|
+
return result;
|
|
604
|
+
},
|
|
605
|
+
});
|
|
606
|
+
// =============================================================================
|
|
607
|
+
// LLM SERVICES
|
|
608
|
+
// =============================================================================
|
|
609
|
+
const llmDebugCall = fabricService({
|
|
610
|
+
alias: "llm_debug_call",
|
|
611
|
+
description: "Make a debug LLM API call and inspect the raw response. Useful for understanding how each provider formats responses, especially for reasoning/thinking content. Returns full history, raw responses, and extracted reasoning.",
|
|
612
|
+
input: {
|
|
613
|
+
provider: {
|
|
614
|
+
type: ["anthropic", "gemini", "openai", "openrouter"],
|
|
615
|
+
required: true,
|
|
616
|
+
description: "LLM provider to call",
|
|
617
|
+
},
|
|
618
|
+
model: {
|
|
619
|
+
type: String,
|
|
620
|
+
required: false,
|
|
621
|
+
description: "Model to use. If not provided, uses a sensible default. For reasoning tests, try 'o3-mini' with openai.",
|
|
622
|
+
},
|
|
623
|
+
message: {
|
|
624
|
+
type: String,
|
|
625
|
+
required: true,
|
|
626
|
+
description: "Message to send to the LLM. For reasoning tests, try something that requires thinking like 'What is 15 * 17? Think step by step.'",
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
service: async (input) => {
|
|
630
|
+
const result = await debugLlmCall({
|
|
631
|
+
provider: input.provider,
|
|
632
|
+
model: input.model,
|
|
633
|
+
message: input.message,
|
|
634
|
+
}, log);
|
|
635
|
+
if (!result.success) {
|
|
636
|
+
throw new Error(result.error);
|
|
637
|
+
}
|
|
638
|
+
return result;
|
|
639
|
+
},
|
|
640
|
+
});
|
|
641
|
+
const llmListProviders = fabricService({
|
|
642
|
+
alias: "llm_list_providers",
|
|
643
|
+
description: "List available LLM providers with their default and reasoning-capable models.",
|
|
644
|
+
input: {},
|
|
645
|
+
service: async () => listLlmProviders(),
|
|
646
|
+
});
|
|
647
|
+
// =============================================================================
|
|
648
|
+
// AWS SERVICES
|
|
649
|
+
// =============================================================================
|
|
650
|
+
const awsListProfiles = fabricService({
|
|
651
|
+
alias: "aws_list_profiles",
|
|
652
|
+
description: "List available AWS profiles from ~/.aws/config and credentials.",
|
|
653
|
+
input: {},
|
|
654
|
+
service: async () => {
|
|
655
|
+
const result = await listAwsProfiles(log);
|
|
656
|
+
if (!result.success) {
|
|
657
|
+
throw new Error(result.error);
|
|
658
|
+
}
|
|
659
|
+
return result.data;
|
|
660
|
+
},
|
|
661
|
+
});
|
|
662
|
+
const awsStepfunctionsListExecutions = fabricService({
|
|
663
|
+
alias: "aws_stepfunctions_list_executions",
|
|
664
|
+
description: "List Step Function executions for a state machine. Useful for finding stuck or running executions.",
|
|
665
|
+
input: {
|
|
666
|
+
stateMachineArn: {
|
|
667
|
+
type: String,
|
|
668
|
+
required: true,
|
|
669
|
+
description: "ARN of the state machine",
|
|
670
|
+
},
|
|
671
|
+
statusFilter: {
|
|
672
|
+
type: [
|
|
673
|
+
"RUNNING",
|
|
674
|
+
"SUCCEEDED",
|
|
675
|
+
"FAILED",
|
|
676
|
+
"TIMED_OUT",
|
|
677
|
+
"ABORTED",
|
|
678
|
+
"PENDING_REDRIVE",
|
|
679
|
+
],
|
|
680
|
+
required: false,
|
|
681
|
+
description: "Filter by execution status",
|
|
682
|
+
},
|
|
683
|
+
profile: {
|
|
684
|
+
type: String,
|
|
685
|
+
required: false,
|
|
686
|
+
description: "AWS profile to use",
|
|
687
|
+
},
|
|
688
|
+
region: {
|
|
689
|
+
type: String,
|
|
690
|
+
required: false,
|
|
691
|
+
description: "AWS region",
|
|
692
|
+
},
|
|
693
|
+
maxResults: {
|
|
694
|
+
type: Number,
|
|
695
|
+
required: false,
|
|
696
|
+
description: "Max results (1-1000, default 100)",
|
|
697
|
+
},
|
|
698
|
+
},
|
|
699
|
+
service: async (input) => {
|
|
700
|
+
const result = await listStepFunctionExecutions(input, log);
|
|
701
|
+
if (!result.success) {
|
|
702
|
+
throw new Error(result.error);
|
|
703
|
+
}
|
|
704
|
+
return result.data;
|
|
705
|
+
},
|
|
706
|
+
});
|
|
707
|
+
const awsStepfunctionsStopExecution = fabricService({
|
|
708
|
+
alias: "aws_stepfunctions_stop_execution",
|
|
709
|
+
description: "Stop a running Step Function execution. Use with caution - this will abort the workflow.",
|
|
710
|
+
input: {
|
|
711
|
+
executionArn: {
|
|
712
|
+
type: String,
|
|
713
|
+
required: true,
|
|
714
|
+
description: "ARN of the execution to stop",
|
|
715
|
+
},
|
|
716
|
+
cause: {
|
|
717
|
+
type: String,
|
|
718
|
+
required: false,
|
|
719
|
+
description: "Description of why the execution was stopped",
|
|
720
|
+
},
|
|
721
|
+
profile: {
|
|
722
|
+
type: String,
|
|
723
|
+
required: false,
|
|
724
|
+
description: "AWS profile to use",
|
|
725
|
+
},
|
|
726
|
+
region: {
|
|
727
|
+
type: String,
|
|
728
|
+
required: false,
|
|
729
|
+
description: "AWS region",
|
|
730
|
+
},
|
|
731
|
+
},
|
|
732
|
+
service: async (input) => {
|
|
733
|
+
const result = await stopStepFunctionExecution(input, log);
|
|
734
|
+
if (!result.success) {
|
|
735
|
+
throw new Error(result.error);
|
|
736
|
+
}
|
|
737
|
+
return result.data;
|
|
738
|
+
},
|
|
739
|
+
});
|
|
740
|
+
const awsLambdaListFunctions = fabricService({
|
|
741
|
+
alias: "aws_lambda_list_functions",
|
|
742
|
+
description: "List Lambda functions in the account. Filter by function name prefix.",
|
|
743
|
+
input: {
|
|
744
|
+
functionNamePrefix: {
|
|
745
|
+
type: String,
|
|
746
|
+
required: false,
|
|
747
|
+
description: "Filter by function name prefix",
|
|
748
|
+
},
|
|
749
|
+
profile: {
|
|
750
|
+
type: String,
|
|
751
|
+
required: false,
|
|
752
|
+
description: "AWS profile to use",
|
|
753
|
+
},
|
|
754
|
+
region: {
|
|
755
|
+
type: String,
|
|
756
|
+
required: false,
|
|
757
|
+
description: "AWS region",
|
|
758
|
+
},
|
|
759
|
+
maxResults: {
|
|
760
|
+
type: Number,
|
|
761
|
+
required: false,
|
|
762
|
+
description: "Max results to return",
|
|
763
|
+
},
|
|
764
|
+
},
|
|
765
|
+
service: async (input) => {
|
|
766
|
+
const result = await listLambdaFunctions(input, log);
|
|
767
|
+
if (!result.success) {
|
|
768
|
+
throw new Error(result.error);
|
|
769
|
+
}
|
|
770
|
+
return result.data;
|
|
771
|
+
},
|
|
772
|
+
});
|
|
773
|
+
const awsLambdaGetFunction = fabricService({
|
|
774
|
+
alias: "aws_lambda_get_function",
|
|
775
|
+
description: "Get configuration and details for a specific Lambda function.",
|
|
776
|
+
input: {
|
|
777
|
+
functionName: {
|
|
778
|
+
type: String,
|
|
779
|
+
required: true,
|
|
780
|
+
description: "Function name or ARN",
|
|
781
|
+
},
|
|
782
|
+
profile: {
|
|
783
|
+
type: String,
|
|
784
|
+
required: false,
|
|
785
|
+
description: "AWS profile to use",
|
|
786
|
+
},
|
|
787
|
+
region: {
|
|
788
|
+
type: String,
|
|
789
|
+
required: false,
|
|
790
|
+
description: "AWS region",
|
|
791
|
+
},
|
|
792
|
+
},
|
|
793
|
+
service: async (input) => {
|
|
794
|
+
const result = await getLambdaFunction(input, log);
|
|
795
|
+
if (!result.success) {
|
|
796
|
+
throw new Error(result.error);
|
|
797
|
+
}
|
|
798
|
+
return result.data;
|
|
799
|
+
},
|
|
800
|
+
});
|
|
801
|
+
const awsLogsFilterLogEvents = fabricService({
|
|
802
|
+
alias: "aws_logs_filter_log_events",
|
|
803
|
+
description: "Search CloudWatch Logs for a log group. Filter by pattern and time range.",
|
|
804
|
+
input: {
|
|
805
|
+
logGroupName: {
|
|
806
|
+
type: String,
|
|
807
|
+
required: true,
|
|
808
|
+
description: "Log group name (e.g., /aws/lambda/my-function)",
|
|
809
|
+
},
|
|
810
|
+
filterPattern: {
|
|
811
|
+
type: String,
|
|
812
|
+
required: false,
|
|
813
|
+
description: "CloudWatch filter pattern (e.g., 'ERROR', '{ $.level = \"error\" }')",
|
|
814
|
+
},
|
|
815
|
+
startTime: {
|
|
816
|
+
type: String,
|
|
817
|
+
required: false,
|
|
818
|
+
description: "Start time (ISO 8601 or relative like 'now-1h'). Defaults to 'now-15m'.",
|
|
819
|
+
},
|
|
820
|
+
endTime: {
|
|
821
|
+
type: String,
|
|
822
|
+
required: false,
|
|
823
|
+
description: "End time (ISO 8601 or 'now'). Defaults to 'now'.",
|
|
824
|
+
},
|
|
825
|
+
profile: {
|
|
826
|
+
type: String,
|
|
827
|
+
required: false,
|
|
828
|
+
description: "AWS profile to use",
|
|
829
|
+
},
|
|
830
|
+
region: {
|
|
831
|
+
type: String,
|
|
832
|
+
required: false,
|
|
833
|
+
description: "AWS region",
|
|
834
|
+
},
|
|
835
|
+
limit: {
|
|
836
|
+
type: Number,
|
|
837
|
+
required: false,
|
|
838
|
+
description: "Max events to return (default 100)",
|
|
839
|
+
},
|
|
840
|
+
},
|
|
841
|
+
service: async (input) => {
|
|
842
|
+
const result = await filterLogEvents({
|
|
843
|
+
...input,
|
|
844
|
+
startTime: input.startTime || "now-15m",
|
|
845
|
+
endTime: input.endTime || "now",
|
|
846
|
+
limit: input.limit || 100,
|
|
847
|
+
}, log);
|
|
848
|
+
if (!result.success) {
|
|
849
|
+
throw new Error(result.error);
|
|
850
|
+
}
|
|
851
|
+
return result.data;
|
|
852
|
+
},
|
|
853
|
+
});
|
|
854
|
+
const awsS3ListObjects = fabricService({
|
|
855
|
+
alias: "aws_s3_list_objects",
|
|
856
|
+
description: "List objects in an S3 bucket with optional prefix filtering.",
|
|
857
|
+
input: {
|
|
858
|
+
bucket: {
|
|
859
|
+
type: String,
|
|
860
|
+
required: true,
|
|
861
|
+
description: "S3 bucket name",
|
|
862
|
+
},
|
|
863
|
+
prefix: {
|
|
864
|
+
type: String,
|
|
865
|
+
required: false,
|
|
866
|
+
description: "Object key prefix filter",
|
|
867
|
+
},
|
|
868
|
+
profile: {
|
|
869
|
+
type: String,
|
|
870
|
+
required: false,
|
|
871
|
+
description: "AWS profile to use",
|
|
872
|
+
},
|
|
873
|
+
region: {
|
|
874
|
+
type: String,
|
|
875
|
+
required: false,
|
|
876
|
+
description: "AWS region",
|
|
877
|
+
},
|
|
878
|
+
maxResults: {
|
|
879
|
+
type: Number,
|
|
880
|
+
required: false,
|
|
881
|
+
description: "Max results to return",
|
|
882
|
+
},
|
|
883
|
+
},
|
|
884
|
+
service: async (input) => {
|
|
885
|
+
const result = await listS3Objects(input, log);
|
|
886
|
+
if (!result.success) {
|
|
887
|
+
throw new Error(result.error);
|
|
888
|
+
}
|
|
889
|
+
return result.data;
|
|
890
|
+
},
|
|
891
|
+
});
|
|
892
|
+
const awsCloudformationDescribeStack = fabricService({
|
|
893
|
+
alias: "aws_cloudformation_describe_stack",
|
|
894
|
+
description: "Get details and status of a CloudFormation stack.",
|
|
895
|
+
input: {
|
|
896
|
+
stackName: {
|
|
897
|
+
type: String,
|
|
898
|
+
required: true,
|
|
899
|
+
description: "Stack name or ARN",
|
|
900
|
+
},
|
|
901
|
+
profile: {
|
|
902
|
+
type: String,
|
|
903
|
+
required: false,
|
|
904
|
+
description: "AWS profile to use",
|
|
905
|
+
},
|
|
906
|
+
region: {
|
|
907
|
+
type: String,
|
|
908
|
+
required: false,
|
|
909
|
+
description: "AWS region",
|
|
910
|
+
},
|
|
911
|
+
},
|
|
912
|
+
service: async (input) => {
|
|
913
|
+
const result = await describeStack(input, log);
|
|
914
|
+
if (!result.success) {
|
|
915
|
+
throw new Error(result.error);
|
|
916
|
+
}
|
|
917
|
+
return result.data;
|
|
918
|
+
},
|
|
919
|
+
});
|
|
920
|
+
const awsDynamodbDescribeTable = fabricService({
|
|
921
|
+
alias: "aws_dynamodb_describe_table",
|
|
922
|
+
description: "Get metadata about a DynamoDB table including key schema, indexes, and provisioned capacity.",
|
|
923
|
+
input: {
|
|
924
|
+
tableName: {
|
|
925
|
+
type: String,
|
|
926
|
+
required: true,
|
|
927
|
+
description: "DynamoDB table name",
|
|
928
|
+
},
|
|
929
|
+
profile: {
|
|
930
|
+
type: String,
|
|
931
|
+
required: false,
|
|
932
|
+
description: "AWS profile to use",
|
|
933
|
+
},
|
|
934
|
+
region: {
|
|
935
|
+
type: String,
|
|
936
|
+
required: false,
|
|
937
|
+
description: "AWS region",
|
|
938
|
+
},
|
|
939
|
+
},
|
|
940
|
+
service: async (input) => {
|
|
941
|
+
const result = await describeDynamoDBTable(input, log);
|
|
942
|
+
if (!result.success) {
|
|
943
|
+
throw new Error(result.error);
|
|
944
|
+
}
|
|
945
|
+
return result.data;
|
|
946
|
+
},
|
|
947
|
+
});
|
|
948
|
+
const awsDynamodbScan = fabricService({
|
|
949
|
+
alias: "aws_dynamodb_scan",
|
|
950
|
+
description: "Scan a DynamoDB table. Use sparingly on large tables - prefer query when possible.",
|
|
951
|
+
input: {
|
|
952
|
+
tableName: {
|
|
953
|
+
type: String,
|
|
954
|
+
required: true,
|
|
955
|
+
description: "DynamoDB table name",
|
|
956
|
+
},
|
|
957
|
+
filterExpression: {
|
|
958
|
+
type: String,
|
|
959
|
+
required: false,
|
|
960
|
+
description: "Filter expression (e.g., 'status = :s')",
|
|
961
|
+
},
|
|
962
|
+
expressionAttributeValues: {
|
|
963
|
+
type: String,
|
|
964
|
+
required: false,
|
|
965
|
+
description: 'JSON object of attribute values (e.g., \'{\\":s\\":{\\"S\\":\\"active\\"}}\')',
|
|
966
|
+
},
|
|
967
|
+
limit: {
|
|
968
|
+
type: Number,
|
|
969
|
+
required: false,
|
|
970
|
+
description: "Max items to return (default 25)",
|
|
971
|
+
},
|
|
972
|
+
profile: {
|
|
973
|
+
type: String,
|
|
974
|
+
required: false,
|
|
975
|
+
description: "AWS profile to use",
|
|
976
|
+
},
|
|
977
|
+
region: {
|
|
978
|
+
type: String,
|
|
979
|
+
required: false,
|
|
980
|
+
description: "AWS region",
|
|
981
|
+
},
|
|
982
|
+
},
|
|
983
|
+
service: async (input) => {
|
|
984
|
+
const result = await scanDynamoDB({ ...input, limit: input.limit || 25 }, log);
|
|
985
|
+
if (!result.success) {
|
|
986
|
+
throw new Error(result.error);
|
|
987
|
+
}
|
|
988
|
+
return result.data;
|
|
989
|
+
},
|
|
990
|
+
});
|
|
991
|
+
const awsDynamodbQuery = fabricService({
|
|
992
|
+
alias: "aws_dynamodb_query",
|
|
993
|
+
description: "Query a DynamoDB table by partition key. More efficient than scan for targeted lookups.",
|
|
994
|
+
input: {
|
|
995
|
+
tableName: {
|
|
996
|
+
type: String,
|
|
997
|
+
required: true,
|
|
998
|
+
description: "DynamoDB table name",
|
|
999
|
+
},
|
|
1000
|
+
keyConditionExpression: {
|
|
1001
|
+
type: String,
|
|
1002
|
+
required: true,
|
|
1003
|
+
description: "Key condition (e.g., 'pk = :pk')",
|
|
1004
|
+
},
|
|
1005
|
+
expressionAttributeValues: {
|
|
1006
|
+
type: String,
|
|
1007
|
+
required: true,
|
|
1008
|
+
description: "JSON object of attribute values",
|
|
1009
|
+
},
|
|
1010
|
+
indexName: {
|
|
1011
|
+
type: String,
|
|
1012
|
+
required: false,
|
|
1013
|
+
description: "GSI or LSI name to query",
|
|
1014
|
+
},
|
|
1015
|
+
filterExpression: {
|
|
1016
|
+
type: String,
|
|
1017
|
+
required: false,
|
|
1018
|
+
description: "Additional filter expression",
|
|
1019
|
+
},
|
|
1020
|
+
limit: {
|
|
1021
|
+
type: Number,
|
|
1022
|
+
required: false,
|
|
1023
|
+
description: "Max items to return",
|
|
1024
|
+
},
|
|
1025
|
+
scanIndexForward: {
|
|
1026
|
+
type: Boolean,
|
|
1027
|
+
required: false,
|
|
1028
|
+
description: "Sort ascending (true) or descending (false)",
|
|
1029
|
+
},
|
|
1030
|
+
profile: {
|
|
1031
|
+
type: String,
|
|
1032
|
+
required: false,
|
|
1033
|
+
description: "AWS profile to use",
|
|
1034
|
+
},
|
|
1035
|
+
region: {
|
|
1036
|
+
type: String,
|
|
1037
|
+
required: false,
|
|
1038
|
+
description: "AWS region",
|
|
1039
|
+
},
|
|
1040
|
+
},
|
|
1041
|
+
service: async (input) => {
|
|
1042
|
+
const result = await queryDynamoDB(input, log);
|
|
1043
|
+
if (!result.success) {
|
|
1044
|
+
throw new Error(result.error);
|
|
1045
|
+
}
|
|
1046
|
+
return result.data;
|
|
1047
|
+
},
|
|
1048
|
+
});
|
|
1049
|
+
const awsDynamodbGetItem = fabricService({
|
|
1050
|
+
alias: "aws_dynamodb_get_item",
|
|
1051
|
+
description: "Get a single item from a DynamoDB table by its primary key.",
|
|
1052
|
+
input: {
|
|
1053
|
+
tableName: {
|
|
1054
|
+
type: String,
|
|
1055
|
+
required: true,
|
|
1056
|
+
description: "DynamoDB table name",
|
|
1057
|
+
},
|
|
1058
|
+
key: {
|
|
1059
|
+
type: String,
|
|
1060
|
+
required: true,
|
|
1061
|
+
description: 'JSON object of the primary key (e.g., \'{\\"pk\\":{\\"S\\":\\"user#123\\"},\\"sk\\":{\\"S\\":\\"profile\\"}}\')',
|
|
1062
|
+
},
|
|
1063
|
+
profile: {
|
|
1064
|
+
type: String,
|
|
1065
|
+
required: false,
|
|
1066
|
+
description: "AWS profile to use",
|
|
1067
|
+
},
|
|
1068
|
+
region: {
|
|
1069
|
+
type: String,
|
|
1070
|
+
required: false,
|
|
1071
|
+
description: "AWS region",
|
|
1072
|
+
},
|
|
1073
|
+
},
|
|
1074
|
+
service: async (input) => {
|
|
1075
|
+
const result = await getDynamoDBItem(input, log);
|
|
1076
|
+
if (!result.success) {
|
|
1077
|
+
throw new Error(result.error);
|
|
1078
|
+
}
|
|
1079
|
+
return result.data;
|
|
1080
|
+
},
|
|
1081
|
+
});
|
|
1082
|
+
const awsSqsListQueues = fabricService({
|
|
1083
|
+
alias: "aws_sqs_list_queues",
|
|
1084
|
+
description: "List SQS queues in the account. Filter by queue name prefix.",
|
|
1085
|
+
input: {
|
|
1086
|
+
queueNamePrefix: {
|
|
1087
|
+
type: String,
|
|
1088
|
+
required: false,
|
|
1089
|
+
description: "Filter by queue name prefix",
|
|
1090
|
+
},
|
|
1091
|
+
profile: {
|
|
1092
|
+
type: String,
|
|
1093
|
+
required: false,
|
|
1094
|
+
description: "AWS profile to use",
|
|
1095
|
+
},
|
|
1096
|
+
region: {
|
|
1097
|
+
type: String,
|
|
1098
|
+
required: false,
|
|
1099
|
+
description: "AWS region",
|
|
1100
|
+
},
|
|
1101
|
+
},
|
|
1102
|
+
service: async (input) => {
|
|
1103
|
+
const result = await listSQSQueues(input, log);
|
|
1104
|
+
if (!result.success) {
|
|
1105
|
+
throw new Error(result.error);
|
|
1106
|
+
}
|
|
1107
|
+
return result.data;
|
|
1108
|
+
},
|
|
1109
|
+
});
|
|
1110
|
+
const awsSqsGetQueueAttributes = fabricService({
|
|
1111
|
+
alias: "aws_sqs_get_queue_attributes",
|
|
1112
|
+
description: "Get attributes for an SQS queue including approximate message count, visibility timeout, and dead-letter config.",
|
|
1113
|
+
input: {
|
|
1114
|
+
queueUrl: {
|
|
1115
|
+
type: String,
|
|
1116
|
+
required: true,
|
|
1117
|
+
description: "SQS queue URL",
|
|
1118
|
+
},
|
|
1119
|
+
profile: {
|
|
1120
|
+
type: String,
|
|
1121
|
+
required: false,
|
|
1122
|
+
description: "AWS profile to use",
|
|
1123
|
+
},
|
|
1124
|
+
region: {
|
|
1125
|
+
type: String,
|
|
1126
|
+
required: false,
|
|
1127
|
+
description: "AWS region",
|
|
1128
|
+
},
|
|
1129
|
+
},
|
|
1130
|
+
service: async (input) => {
|
|
1131
|
+
const result = await getSQSQueueAttributes(input, log);
|
|
1132
|
+
if (!result.success) {
|
|
1133
|
+
throw new Error(result.error);
|
|
1134
|
+
}
|
|
1135
|
+
return result.data;
|
|
1136
|
+
},
|
|
1137
|
+
});
|
|
1138
|
+
const awsSqsReceiveMessage = fabricService({
|
|
1139
|
+
alias: "aws_sqs_receive_message",
|
|
1140
|
+
description: "Receive messages from an SQS queue for inspection. Messages are returned to the queue after visibility timeout.",
|
|
1141
|
+
input: {
|
|
1142
|
+
queueUrl: {
|
|
1143
|
+
type: String,
|
|
1144
|
+
required: true,
|
|
1145
|
+
description: "SQS queue URL",
|
|
1146
|
+
},
|
|
1147
|
+
maxNumberOfMessages: {
|
|
1148
|
+
type: Number,
|
|
1149
|
+
required: false,
|
|
1150
|
+
description: "Max messages to receive (1-10, default 1)",
|
|
1151
|
+
},
|
|
1152
|
+
visibilityTimeout: {
|
|
1153
|
+
type: Number,
|
|
1154
|
+
required: false,
|
|
1155
|
+
description: "Seconds to hide message (default 30)",
|
|
1156
|
+
},
|
|
1157
|
+
profile: {
|
|
1158
|
+
type: String,
|
|
1159
|
+
required: false,
|
|
1160
|
+
description: "AWS profile to use",
|
|
1161
|
+
},
|
|
1162
|
+
region: {
|
|
1163
|
+
type: String,
|
|
1164
|
+
required: false,
|
|
1165
|
+
description: "AWS region",
|
|
1166
|
+
},
|
|
1167
|
+
},
|
|
1168
|
+
service: async (input) => {
|
|
1169
|
+
const result = await receiveSQSMessage({
|
|
1170
|
+
...input,
|
|
1171
|
+
maxNumberOfMessages: input.maxNumberOfMessages || 1,
|
|
1172
|
+
visibilityTimeout: input.visibilityTimeout || 30,
|
|
1173
|
+
}, log);
|
|
1174
|
+
if (!result.success) {
|
|
1175
|
+
throw new Error(result.error);
|
|
1176
|
+
}
|
|
1177
|
+
return result.data;
|
|
1178
|
+
},
|
|
1179
|
+
});
|
|
1180
|
+
const awsSqsPurgeQueue = fabricService({
|
|
1181
|
+
alias: "aws_sqs_purge_queue",
|
|
1182
|
+
description: "Delete all messages from an SQS queue. Use with caution - this is irreversible.",
|
|
1183
|
+
input: {
|
|
1184
|
+
queueUrl: {
|
|
1185
|
+
type: String,
|
|
1186
|
+
required: true,
|
|
1187
|
+
description: "SQS queue URL",
|
|
1188
|
+
},
|
|
1189
|
+
profile: {
|
|
1190
|
+
type: String,
|
|
1191
|
+
required: false,
|
|
1192
|
+
description: "AWS profile to use",
|
|
1193
|
+
},
|
|
1194
|
+
region: {
|
|
1195
|
+
type: String,
|
|
1196
|
+
required: false,
|
|
1197
|
+
description: "AWS region",
|
|
1198
|
+
},
|
|
1199
|
+
},
|
|
1200
|
+
service: async (input) => {
|
|
1201
|
+
const result = await purgeSQSQueue(input, log);
|
|
1202
|
+
if (!result.success) {
|
|
1203
|
+
throw new Error(result.error);
|
|
1204
|
+
}
|
|
1205
|
+
return { success: true };
|
|
1206
|
+
},
|
|
1207
|
+
});
|
|
1208
|
+
// =============================================================================
|
|
1209
|
+
// SUITE CREATION
|
|
1210
|
+
// =============================================================================
|
|
1211
|
+
const VERSION = "0.3.4";
|
|
1212
|
+
const suite = createServiceSuite({
|
|
1213
|
+
name: "jaypie",
|
|
1214
|
+
version: VERSION,
|
|
1215
|
+
});
|
|
1216
|
+
// Register docs services
|
|
1217
|
+
suite.register(skill, "docs");
|
|
1218
|
+
suite.register(version, "docs");
|
|
1219
|
+
suite.register(listPrompts, "docs");
|
|
1220
|
+
suite.register(readPrompt, "docs");
|
|
1221
|
+
suite.register(listReleaseNotes, "docs");
|
|
1222
|
+
suite.register(readReleaseNote, "docs");
|
|
1223
|
+
// Register Datadog services
|
|
1224
|
+
suite.register(datadogLogs, "datadog");
|
|
1225
|
+
suite.register(datadogLogAnalytics, "datadog");
|
|
1226
|
+
suite.register(datadogMonitors, "datadog");
|
|
1227
|
+
suite.register(datadogSynthetics, "datadog");
|
|
1228
|
+
suite.register(datadogMetrics, "datadog");
|
|
1229
|
+
suite.register(datadogRum, "datadog");
|
|
1230
|
+
// Register LLM services
|
|
1231
|
+
suite.register(llmDebugCall, "llm");
|
|
1232
|
+
suite.register(llmListProviders, "llm");
|
|
1233
|
+
// Register AWS services
|
|
1234
|
+
suite.register(awsListProfiles, "aws");
|
|
1235
|
+
suite.register(awsStepfunctionsListExecutions, "aws");
|
|
1236
|
+
suite.register(awsStepfunctionsStopExecution, "aws");
|
|
1237
|
+
suite.register(awsLambdaListFunctions, "aws");
|
|
1238
|
+
suite.register(awsLambdaGetFunction, "aws");
|
|
1239
|
+
suite.register(awsLogsFilterLogEvents, "aws");
|
|
1240
|
+
suite.register(awsS3ListObjects, "aws");
|
|
1241
|
+
suite.register(awsCloudformationDescribeStack, "aws");
|
|
1242
|
+
suite.register(awsDynamodbDescribeTable, "aws");
|
|
1243
|
+
suite.register(awsDynamodbScan, "aws");
|
|
1244
|
+
suite.register(awsDynamodbQuery, "aws");
|
|
1245
|
+
suite.register(awsDynamodbGetItem, "aws");
|
|
1246
|
+
suite.register(awsSqsListQueues, "aws");
|
|
1247
|
+
suite.register(awsSqsGetQueueAttributes, "aws");
|
|
1248
|
+
suite.register(awsSqsReceiveMessage, "aws");
|
|
1249
|
+
suite.register(awsSqsPurgeQueue, "aws");
|
|
1250
|
+
|
|
1251
|
+
export { suite };
|
|
1252
|
+
//# sourceMappingURL=suite.js.map
|