@jaypie/mcp 0.8.139 → 0.8.141

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/suite.js CHANGED
@@ -1,5 +1,5 @@
1
+ import { datadogService } from '@jaypie/datadog';
1
2
  import { createServiceSuite } from '@jaypie/fabric';
2
- import { datadogService } from './suites/datadog/index.js';
3
3
  import { skillService, versionService, releaseNotesService } from './suites/docs/index.js';
4
4
 
5
5
  /**
package/dist/suite.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"suite.js","sources":["../src/suite.ts"],"sourcesContent":["/**\n * ServiceSuite for @jaypie/mcp\n * Provides metadata and direct execution for Jaypie MCP services\n *\n * Unified router-style tools:\n * - datadog: 6 Datadog observability commands\n * - skill: Jaypie development documentation\n * - version: Package version info\n * - release_notes: Package release notes\n */\n\nimport { createServiceSuite } from \"@jaypie/fabric\";\n\nimport { datadogService } from \"./suites/datadog/index.js\";\nimport {\n releaseNotesService,\n skillService,\n versionService,\n} from \"./suites/docs/index.js\";\n\n// =============================================================================\n// SUITE CREATION\n// =============================================================================\n\nconst VERSION = \"0.5.0\";\n\nexport const suite = createServiceSuite({\n name: \"jaypie\",\n version: VERSION,\n});\n\n// Register docs services\nsuite.register(skillService, { category: \"docs\" });\nsuite.register(versionService, { category: \"docs\" });\nsuite.register(releaseNotesService, { category: \"docs\" });\n\n// Register Datadog services\nsuite.register(datadogService, { category: \"datadog\" });\n"],"names":[],"mappings":";;;;AAAA;;;;;;;;;AASG;AAWH;AACA;AACA;AAEA,MAAM,OAAO,GAAG,OAAO;AAEhB,MAAM,KAAK,GAAG,kBAAkB,CAAC;AACtC,IAAA,IAAI,EAAE,QAAQ;AACd,IAAA,OAAO,EAAE,OAAO;AACjB,CAAA;AAED;AACA,KAAK,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAClD,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACpD,KAAK,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAEzD;AACA,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;;;;"}
1
+ {"version":3,"file":"suite.js","sources":["../src/suite.ts"],"sourcesContent":["/**\n * ServiceSuite for @jaypie/mcp\n * Provides metadata and direct execution for Jaypie MCP services\n *\n * Unified router-style tools:\n * - datadog: 6 Datadog observability commands\n * - skill: Jaypie development documentation\n * - version: Package version info\n * - release_notes: Package release notes\n */\n\nimport { datadogService } from \"@jaypie/datadog\";\nimport { createServiceSuite } from \"@jaypie/fabric\";\n\nimport {\n releaseNotesService,\n skillService,\n versionService,\n} from \"./suites/docs/index.js\";\n\n// =============================================================================\n// SUITE CREATION\n// =============================================================================\n\nconst VERSION = \"0.5.0\";\n\nexport const suite = createServiceSuite({\n name: \"jaypie\",\n version: VERSION,\n});\n\n// Register docs services\nsuite.register(skillService, { category: \"docs\" });\nsuite.register(versionService, { category: \"docs\" });\nsuite.register(releaseNotesService, { category: \"docs\" });\n\n// Register Datadog services\nsuite.register(datadogService, { category: \"datadog\" });\n"],"names":[],"mappings":";;;;AAAA;;;;;;;;;AASG;AAWH;AACA;AACA;AAEA,MAAM,OAAO,GAAG,OAAO;AAEhB,MAAM,KAAK,GAAG,kBAAkB,CAAC;AACtC,IAAA,IAAI,EAAE,QAAQ;AACd,IAAA,OAAO,EAAE,OAAO;AACjB,CAAA;AAED;AACA,KAAK,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAClD,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACpD,KAAK,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAEzD;AACA,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;;;;"}
@@ -1,3 +1,4 @@
1
+ import { BadRequestError } from '@jaypie/errors';
1
2
  import { fabricService } from '@jaypie/fabric';
2
3
  import { parseFrontmatter } from '@jaypie/kit';
3
4
  import { createMarkdownStore, createLayeredStore, createSkillService } from '@jaypie/tildeskill';
@@ -9,7 +10,7 @@ import { gt } from 'semver';
9
10
  /**
10
11
  * Docs Suite - Documentation services (skill, version, release_notes)
11
12
  */
12
- const BUILD_VERSION_STRING = "@jaypie/mcp@0.8.139#b5c90690"
13
+ const BUILD_VERSION_STRING = "@jaypie/mcp@0.8.141#1dc93d0e"
13
14
  ;
14
15
  const __filename$1 = fileURLToPath(import.meta.url);
15
16
  const __dirname$1 = path.dirname(__filename$1);
@@ -176,14 +177,14 @@ const releaseNotesService = fabricService({
176
177
  }
177
178
  case "read": {
178
179
  if (!p.package)
179
- throw new Error("package is required");
180
+ throw new BadRequestError("package is required");
180
181
  if (!p.version)
181
- throw new Error("version is required");
182
+ throw new BadRequestError("version is required");
182
183
  const filePath = path.join(RELEASE_NOTES_PATH, p.package, `${p.version}.md`);
183
184
  return fs.readFile(filePath, "utf-8");
184
185
  }
185
186
  default:
186
- throw new Error(`Unknown command: ${command}. Use release_notes() for help.`);
187
+ throw new BadRequestError(`Unknown command: ${command}. Use release_notes() for help.`);
187
188
  }
188
189
  },
189
190
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/suites/docs/index.ts"],"sourcesContent":["/**\n * Docs Suite - Documentation services (skill, version, release_notes)\n */\nimport { fabricService } from \"@jaypie/fabric\";\nimport { parseFrontmatter } from \"@jaypie/kit\";\nimport {\n createLayeredStore,\n createMarkdownStore,\n createSkillService,\n type LayeredStoreLayer,\n} from \"@jaypie/tildeskill\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { gt } from \"semver\";\n\n// Build-time constants\ndeclare const __BUILD_VERSION_STRING__: string;\nconst BUILD_VERSION_STRING =\n typeof __BUILD_VERSION_STRING__ !== \"undefined\"\n ? __BUILD_VERSION_STRING__\n : \"@jaypie/mcp@0.0.0\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n// From dist/suites/docs/, go up 3 levels to package root where skills/ and release-notes/ live\n// Environment variables allow overriding paths when bundled (e.g., esbuild Lambda)\nconst RELEASE_NOTES_PATH =\n process.env.MCP_RELEASE_NOTES_PATH ||\n path.join(__dirname, \"..\", \"..\", \"..\", \"release-notes\");\n\n// Bundled Jaypie skills ship inside the @jaypie/mcp package. MCP_BUILTIN_SKILLS_PATH\n// lets bundlers (esbuild, Lambda) relocate them without disabling the built-in layer.\nconst BUILTIN_SKILLS_PATH =\n process.env.MCP_BUILTIN_SKILLS_PATH ||\n path.join(__dirname, \"..\", \"..\", \"..\", \"skills\");\n\nconst LOCAL_SKILLS_NAMESPACE = \"local\";\nconst JAYPIE_SKILLS_NAMESPACE = \"jaypie\";\nconst LAYER_SEPARATOR = \":\";\n\n// Skill layers resolved in order: a client's MCP_SKILLS_PATH layers on top of\n// the built-in Jaypie skill pack so `skill(\"aws\")` prefers the client's copy\n// while still exposing bundled Jaypie docs under the `jaypie:` namespace.\nconst skillLayers: LayeredStoreLayer[] = [];\n\nif (process.env.MCP_SKILLS_PATH) {\n skillLayers.push({\n namespace: LOCAL_SKILLS_NAMESPACE,\n store: createMarkdownStore({ path: process.env.MCP_SKILLS_PATH }),\n });\n}\n\nskillLayers.push({\n namespace: JAYPIE_SKILLS_NAMESPACE,\n store: createMarkdownStore({ path: BUILTIN_SKILLS_PATH }),\n});\n\nconst skillStore = createLayeredStore({\n layers: skillLayers,\n separator: LAYER_SEPARATOR,\n});\n\n// =============================================================================\n// HELPER FUNCTIONS\n// =============================================================================\n\ninterface ReleaseNoteFrontMatter {\n date?: string;\n summary?: string;\n version?: string;\n}\n\nasync function parseReleaseNoteFile(filePath: string): Promise<{\n date?: string;\n filename: string;\n summary?: string;\n version?: string;\n}> {\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n const filename = path.basename(filePath, \".md\");\n\n if (content.startsWith(\"---\")) {\n const frontMatter =\n parseFrontmatter<ReleaseNoteFrontMatter>(content).data;\n return {\n date: frontMatter.date,\n filename,\n summary: frontMatter.summary,\n version: frontMatter.version || filename,\n };\n }\n\n return { filename, version: filename };\n } catch {\n return { filename: path.basename(filePath, \".md\") };\n }\n}\n\nfunction formatReleaseNoteListItem(note: {\n date?: string;\n filename: string;\n packageName: string;\n summary?: string;\n version?: string;\n}): string {\n const { date, packageName, summary, version } = note;\n const parts = [`* ${packageName}@${version}`];\n\n if (date) {\n parts.push(`(${date})`);\n }\n\n if (summary) {\n parts.push(`- ${summary}`);\n }\n\n return parts.join(\" \");\n}\n\nasync function getPackageReleaseNotes(packageName: string): Promise<\n Array<{\n date?: string;\n filename: string;\n packageName: string;\n summary?: string;\n version?: string;\n }>\n> {\n const packageDir = path.join(RELEASE_NOTES_PATH, packageName);\n try {\n const files = await fs.readdir(packageDir);\n const mdFiles = files.filter((file) => file.endsWith(\".md\"));\n\n const notes = await Promise.all(\n mdFiles.map(async (file) => {\n const parsed = await parseReleaseNoteFile(path.join(packageDir, file));\n return { ...parsed, packageName };\n }),\n );\n\n return notes.sort((a, b) => {\n if (!a.version || !b.version) return 0;\n try {\n return gt(a.version, b.version) ? -1 : 1;\n } catch {\n return b.version.localeCompare(a.version);\n }\n });\n } catch {\n return [];\n }\n}\n\nfunction filterReleaseNotesSince(\n notes: Array<{\n date?: string;\n filename: string;\n packageName: string;\n summary?: string;\n version?: string;\n }>,\n sinceVersion: string,\n): Array<{\n date?: string;\n filename: string;\n packageName: string;\n summary?: string;\n version?: string;\n}> {\n return notes.filter((note) => {\n if (!note.version) return false;\n try {\n return gt(note.version, sinceVersion);\n } catch {\n return false;\n }\n });\n}\n\n// =============================================================================\n// SKILL SERVICE\n// =============================================================================\n\nexport const skillService = createSkillService(skillStore);\n\n// =============================================================================\n// VERSION SERVICE\n// =============================================================================\n\nexport const versionService = fabricService({\n alias: \"version\",\n description: `Prints the current version and hash, \\`${BUILD_VERSION_STRING}\\``,\n input: {},\n service: async () => BUILD_VERSION_STRING,\n});\n\n// =============================================================================\n// RELEASE NOTES SERVICE\n// =============================================================================\n\nasync function getReleaseNotesHelp(): Promise<string> {\n return fs.readFile(path.join(__dirname, \"release-notes\", \"help.md\"), \"utf-8\");\n}\n\ninterface ReleaseNotesInput {\n package?: string;\n since_version?: string;\n version?: string;\n}\n\nexport const releaseNotesService = fabricService({\n alias: \"release_notes\",\n description:\n \"Browse Jaypie package release notes. Commands: list, read. Call with no args for help.\",\n input: {\n command: {\n description: \"Command to execute (omit for help)\",\n required: false,\n type: String,\n },\n input: {\n description: \"Command parameters\",\n required: false,\n type: Object,\n },\n },\n service: async ({\n command,\n input: params,\n }: {\n command?: string;\n input?: ReleaseNotesInput;\n }) => {\n if (!command || command === \"help\") {\n return getReleaseNotesHelp();\n }\n\n const p = params || {};\n\n switch (command) {\n case \"list\": {\n const entries = await fs.readdir(RELEASE_NOTES_PATH, {\n withFileTypes: true,\n });\n const packageDirs = entries\n .filter((entry) => entry.isDirectory())\n .map((entry) => entry.name);\n const packagesToList = p.package\n ? packageDirs.filter((pkg) => pkg === p.package)\n : packageDirs;\n\n if (packagesToList.length === 0 && p.package) {\n return `No release notes found for package \"${p.package}\".`;\n }\n\n const allNotes = await Promise.all(\n packagesToList.map((pkg) => getPackageReleaseNotes(pkg)),\n );\n let flatNotes = allNotes.flat();\n\n if (p.since_version) {\n flatNotes = filterReleaseNotesSince(flatNotes, p.since_version);\n }\n\n if (flatNotes.length === 0) {\n const filterDesc = p.since_version\n ? ` newer than ${p.since_version}`\n : \"\";\n return `No release notes found${filterDesc}.`;\n }\n\n return flatNotes.map(formatReleaseNoteListItem).join(\"\\n\");\n }\n\n case \"read\": {\n if (!p.package) throw new Error(\"package is required\");\n if (!p.version) throw new Error(\"version is required\");\n const filePath = path.join(\n RELEASE_NOTES_PATH,\n p.package,\n `${p.version}.md`,\n );\n return fs.readFile(filePath, \"utf-8\");\n }\n\n default:\n throw new Error(\n `Unknown command: ${command}. Use release_notes() for help.`,\n );\n }\n },\n});\n"],"names":["__filename","__dirname"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/suites/docs/index.ts"],"sourcesContent":["/**\n * Docs Suite - Documentation services (skill, version, release_notes)\n */\nimport { BadRequestError } from \"@jaypie/errors\";\nimport { fabricService } from \"@jaypie/fabric\";\nimport { parseFrontmatter } from \"@jaypie/kit\";\nimport {\n createLayeredStore,\n createMarkdownStore,\n createSkillService,\n type LayeredStoreLayer,\n} from \"@jaypie/tildeskill\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { gt } from \"semver\";\n\n// Build-time constants\ndeclare const __BUILD_VERSION_STRING__: string;\nconst BUILD_VERSION_STRING =\n typeof __BUILD_VERSION_STRING__ !== \"undefined\"\n ? __BUILD_VERSION_STRING__\n : \"@jaypie/mcp@0.0.0\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n// From dist/suites/docs/, go up 3 levels to package root where skills/ and release-notes/ live\n// Environment variables allow overriding paths when bundled (e.g., esbuild Lambda)\nconst RELEASE_NOTES_PATH =\n process.env.MCP_RELEASE_NOTES_PATH ||\n path.join(__dirname, \"..\", \"..\", \"..\", \"release-notes\");\n\n// Bundled Jaypie skills ship inside the @jaypie/mcp package. MCP_BUILTIN_SKILLS_PATH\n// lets bundlers (esbuild, Lambda) relocate them without disabling the built-in layer.\nconst BUILTIN_SKILLS_PATH =\n process.env.MCP_BUILTIN_SKILLS_PATH ||\n path.join(__dirname, \"..\", \"..\", \"..\", \"skills\");\n\nconst LOCAL_SKILLS_NAMESPACE = \"local\";\nconst JAYPIE_SKILLS_NAMESPACE = \"jaypie\";\nconst LAYER_SEPARATOR = \":\";\n\n// Skill layers resolved in order: a client's MCP_SKILLS_PATH layers on top of\n// the built-in Jaypie skill pack so `skill(\"aws\")` prefers the client's copy\n// while still exposing bundled Jaypie docs under the `jaypie:` namespace.\nconst skillLayers: LayeredStoreLayer[] = [];\n\nif (process.env.MCP_SKILLS_PATH) {\n skillLayers.push({\n namespace: LOCAL_SKILLS_NAMESPACE,\n store: createMarkdownStore({ path: process.env.MCP_SKILLS_PATH }),\n });\n}\n\nskillLayers.push({\n namespace: JAYPIE_SKILLS_NAMESPACE,\n store: createMarkdownStore({ path: BUILTIN_SKILLS_PATH }),\n});\n\nconst skillStore = createLayeredStore({\n layers: skillLayers,\n separator: LAYER_SEPARATOR,\n});\n\n// =============================================================================\n// HELPER FUNCTIONS\n// =============================================================================\n\ninterface ReleaseNoteFrontMatter {\n date?: string;\n summary?: string;\n version?: string;\n}\n\nasync function parseReleaseNoteFile(filePath: string): Promise<{\n date?: string;\n filename: string;\n summary?: string;\n version?: string;\n}> {\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n const filename = path.basename(filePath, \".md\");\n\n if (content.startsWith(\"---\")) {\n const frontMatter =\n parseFrontmatter<ReleaseNoteFrontMatter>(content).data;\n return {\n date: frontMatter.date,\n filename,\n summary: frontMatter.summary,\n version: frontMatter.version || filename,\n };\n }\n\n return { filename, version: filename };\n } catch {\n return { filename: path.basename(filePath, \".md\") };\n }\n}\n\nfunction formatReleaseNoteListItem(note: {\n date?: string;\n filename: string;\n packageName: string;\n summary?: string;\n version?: string;\n}): string {\n const { date, packageName, summary, version } = note;\n const parts = [`* ${packageName}@${version}`];\n\n if (date) {\n parts.push(`(${date})`);\n }\n\n if (summary) {\n parts.push(`- ${summary}`);\n }\n\n return parts.join(\" \");\n}\n\nasync function getPackageReleaseNotes(packageName: string): Promise<\n Array<{\n date?: string;\n filename: string;\n packageName: string;\n summary?: string;\n version?: string;\n }>\n> {\n const packageDir = path.join(RELEASE_NOTES_PATH, packageName);\n try {\n const files = await fs.readdir(packageDir);\n const mdFiles = files.filter((file) => file.endsWith(\".md\"));\n\n const notes = await Promise.all(\n mdFiles.map(async (file) => {\n const parsed = await parseReleaseNoteFile(path.join(packageDir, file));\n return { ...parsed, packageName };\n }),\n );\n\n return notes.sort((a, b) => {\n if (!a.version || !b.version) return 0;\n try {\n return gt(a.version, b.version) ? -1 : 1;\n } catch {\n return b.version.localeCompare(a.version);\n }\n });\n } catch {\n return [];\n }\n}\n\nfunction filterReleaseNotesSince(\n notes: Array<{\n date?: string;\n filename: string;\n packageName: string;\n summary?: string;\n version?: string;\n }>,\n sinceVersion: string,\n): Array<{\n date?: string;\n filename: string;\n packageName: string;\n summary?: string;\n version?: string;\n}> {\n return notes.filter((note) => {\n if (!note.version) return false;\n try {\n return gt(note.version, sinceVersion);\n } catch {\n return false;\n }\n });\n}\n\n// =============================================================================\n// SKILL SERVICE\n// =============================================================================\n\nexport const skillService = createSkillService(skillStore);\n\n// =============================================================================\n// VERSION SERVICE\n// =============================================================================\n\nexport const versionService = fabricService({\n alias: \"version\",\n description: `Prints the current version and hash, \\`${BUILD_VERSION_STRING}\\``,\n input: {},\n service: async () => BUILD_VERSION_STRING,\n});\n\n// =============================================================================\n// RELEASE NOTES SERVICE\n// =============================================================================\n\nasync function getReleaseNotesHelp(): Promise<string> {\n return fs.readFile(path.join(__dirname, \"release-notes\", \"help.md\"), \"utf-8\");\n}\n\ninterface ReleaseNotesInput {\n package?: string;\n since_version?: string;\n version?: string;\n}\n\nexport const releaseNotesService = fabricService({\n alias: \"release_notes\",\n description:\n \"Browse Jaypie package release notes. Commands: list, read. Call with no args for help.\",\n input: {\n command: {\n description: \"Command to execute (omit for help)\",\n required: false,\n type: String,\n },\n input: {\n description: \"Command parameters\",\n required: false,\n type: Object,\n },\n },\n service: async ({\n command,\n input: params,\n }: {\n command?: string;\n input?: ReleaseNotesInput;\n }) => {\n if (!command || command === \"help\") {\n return getReleaseNotesHelp();\n }\n\n const p = params || {};\n\n switch (command) {\n case \"list\": {\n const entries = await fs.readdir(RELEASE_NOTES_PATH, {\n withFileTypes: true,\n });\n const packageDirs = entries\n .filter((entry) => entry.isDirectory())\n .map((entry) => entry.name);\n const packagesToList = p.package\n ? packageDirs.filter((pkg) => pkg === p.package)\n : packageDirs;\n\n if (packagesToList.length === 0 && p.package) {\n return `No release notes found for package \"${p.package}\".`;\n }\n\n const allNotes = await Promise.all(\n packagesToList.map((pkg) => getPackageReleaseNotes(pkg)),\n );\n let flatNotes = allNotes.flat();\n\n if (p.since_version) {\n flatNotes = filterReleaseNotesSince(flatNotes, p.since_version);\n }\n\n if (flatNotes.length === 0) {\n const filterDesc = p.since_version\n ? ` newer than ${p.since_version}`\n : \"\";\n return `No release notes found${filterDesc}.`;\n }\n\n return flatNotes.map(formatReleaseNoteListItem).join(\"\\n\");\n }\n\n case \"read\": {\n if (!p.package) throw new BadRequestError(\"package is required\");\n if (!p.version) throw new BadRequestError(\"version is required\");\n const filePath = path.join(\n RELEASE_NOTES_PATH,\n p.package,\n `${p.version}.md`,\n );\n return fs.readFile(filePath, \"utf-8\");\n }\n\n default:\n throw new BadRequestError(\n `Unknown command: ${command}. Use release_notes() for help.`,\n );\n }\n },\n});\n"],"names":["__filename","__dirname"],"mappings":";;;;;;;;;AAAA;;AAEG;AAiBH,MAAM,oBAAoB,GAEpB;IACmB;AAEzB,MAAMA,YAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;AACjD,MAAMC,WAAS,GAAG,IAAI,CAAC,OAAO,CAACD,YAAU,CAAC;AAC1C;AACA;AACA,MAAM,kBAAkB,GACtB,OAAO,CAAC,GAAG,CAAC,sBAAsB;AAClC,IAAA,IAAI,CAAC,IAAI,CAACC,WAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,CAAC;AAEzD;AACA;AACA,MAAM,mBAAmB,GACvB,OAAO,CAAC,GAAG,CAAC,uBAAuB;AACnC,IAAA,IAAI,CAAC,IAAI,CAACA,WAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC;AAElD,MAAM,sBAAsB,GAAG,OAAO;AACtC,MAAM,uBAAuB,GAAG,QAAQ;AACxC,MAAM,eAAe,GAAG,GAAG;AAE3B;AACA;AACA;AACA,MAAM,WAAW,GAAwB,EAAE;AAE3C,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE;IAC/B,WAAW,CAAC,IAAI,CAAC;AACf,QAAA,SAAS,EAAE,sBAAsB;AACjC,QAAA,KAAK,EAAE,mBAAmB,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;AAClE,KAAA,CAAC;AACJ;AAEA,WAAW,CAAC,IAAI,CAAC;AACf,IAAA,SAAS,EAAE,uBAAuB;IAClC,KAAK,EAAE,mBAAmB,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;AAC1D,CAAA,CAAC;AAEF,MAAM,UAAU,GAAG,kBAAkB,CAAC;AACpC,IAAA,MAAM,EAAE,WAAW;AACnB,IAAA,SAAS,EAAE,eAAe;AAC3B,CAAA,CAAC;AAYF,eAAe,oBAAoB,CAAC,QAAgB,EAAA;AAMlD,IAAA,IAAI;QACF,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;AAE/C,QAAA,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE;YAC7B,MAAM,WAAW,GACf,gBAAgB,CAAyB,OAAO,CAAC,CAAC,IAAI;YACxD,OAAO;gBACL,IAAI,EAAE,WAAW,CAAC,IAAI;gBACtB,QAAQ;gBACR,OAAO,EAAE,WAAW,CAAC,OAAO;AAC5B,gBAAA,OAAO,EAAE,WAAW,CAAC,OAAO,IAAI,QAAQ;aACzC;QACH;AAEA,QAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE;IACxC;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE;IACrD;AACF;AAEA,SAAS,yBAAyB,CAAC,IAMlC,EAAA;IACC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI;IACpD,MAAM,KAAK,GAAG,CAAC,CAAA,EAAA,EAAK,WAAW,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE,CAAC;IAE7C,IAAI,IAAI,EAAE;AACR,QAAA,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAA,CAAA,CAAG,CAAC;IACzB;IAEA,IAAI,OAAO,EAAE;AACX,QAAA,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAA,CAAE,CAAC;IAC5B;AAEA,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AACxB;AAEA,eAAe,sBAAsB,CAAC,WAAmB,EAAA;IASvD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC;AAC7D,IAAA,IAAI;QACF,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;AAC1C,QAAA,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAE5D,QAAA,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAC7B,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,KAAI;AACzB,YAAA,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AACtE,YAAA,OAAO,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE;QACnC,CAAC,CAAC,CACH;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAI;YACzB,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO;AAAE,gBAAA,OAAO,CAAC;AACtC,YAAA,IAAI;AACF,gBAAA,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;YAC1C;AAAE,YAAA,MAAM;gBACN,OAAO,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC;YAC3C;AACF,QAAA,CAAC,CAAC;IACJ;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,EAAE;IACX;AACF;AAEA,SAAS,uBAAuB,CAC9B,KAME,EACF,YAAoB,EAAA;AAQpB,IAAA,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAI;QAC3B,IAAI,CAAC,IAAI,CAAC,OAAO;AAAE,YAAA,OAAO,KAAK;AAC/B,QAAA,IAAI;YACF,OAAO,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC;QACvC;AAAE,QAAA,MAAM;AACN,YAAA,OAAO,KAAK;QACd;AACF,IAAA,CAAC,CAAC;AACJ;AAEA;AACA;AACA;MAEa,YAAY,GAAG,kBAAkB,CAAC,UAAU;AAEzD;AACA;AACA;AAEO,MAAM,cAAc,GAAG,aAAa,CAAC;AAC1C,IAAA,KAAK,EAAE,SAAS;IAChB,WAAW,EAAE,CAAA,uCAAA,EAA0C,oBAAoB,CAAA,EAAA,CAAI;AAC/E,IAAA,KAAK,EAAE,EAAE;AACT,IAAA,OAAO,EAAE,YAAY,oBAAoB;AAC1C,CAAA;AAED;AACA;AACA;AAEA,eAAe,mBAAmB,GAAA;AAChC,IAAA,OAAO,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAACA,WAAS,EAAE,eAAe,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC;AAC/E;AAQO,MAAM,mBAAmB,GAAG,aAAa,CAAC;AAC/C,IAAA,KAAK,EAAE,eAAe;AACtB,IAAA,WAAW,EACT,wFAAwF;AAC1F,IAAA,KAAK,EAAE;AACL,QAAA,OAAO,EAAE;AACP,YAAA,WAAW,EAAE,oCAAoC;AACjD,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,IAAI,EAAE,MAAM;AACb,SAAA;AACD,QAAA,KAAK,EAAE;AACL,YAAA,WAAW,EAAE,oBAAoB;AACjC,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,IAAI,EAAE,MAAM;AACb,SAAA;AACF,KAAA;IACD,OAAO,EAAE,OAAO,EACd,OAAO,EACP,KAAK,EAAE,MAAM,GAId,KAAI;AACH,QAAA,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,MAAM,EAAE;YAClC,OAAO,mBAAmB,EAAE;QAC9B;AAEA,QAAA,MAAM,CAAC,GAAG,MAAM,IAAI,EAAE;QAEtB,QAAQ,OAAO;YACb,KAAK,MAAM,EAAE;gBACX,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,kBAAkB,EAAE;AACnD,oBAAA,aAAa,EAAE,IAAI;AACpB,iBAAA,CAAC;gBACF,MAAM,WAAW,GAAG;qBACjB,MAAM,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,WAAW,EAAE;qBACrC,GAAG,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,CAAC;AAC7B,gBAAA,MAAM,cAAc,GAAG,CAAC,CAAC;AACvB,sBAAE,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO;sBAC7C,WAAW;gBAEf,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE;AAC5C,oBAAA,OAAO,CAAA,oCAAA,EAAuC,CAAC,CAAC,OAAO,IAAI;gBAC7D;gBAEA,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAChC,cAAc,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,sBAAsB,CAAC,GAAG,CAAC,CAAC,CACzD;AACD,gBAAA,IAAI,SAAS,GAAG,QAAQ,CAAC,IAAI,EAAE;AAE/B,gBAAA,IAAI,CAAC,CAAC,aAAa,EAAE;oBACnB,SAAS,GAAG,uBAAuB,CAAC,SAAS,EAAE,CAAC,CAAC,aAAa,CAAC;gBACjE;AAEA,gBAAA,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;AAC1B,oBAAA,MAAM,UAAU,GAAG,CAAC,CAAC;AACnB,0BAAE,CAAA,YAAA,EAAe,CAAC,CAAC,aAAa,CAAA;0BAC9B,EAAE;oBACN,OAAO,CAAA,sBAAA,EAAyB,UAAU,CAAA,CAAA,CAAG;gBAC/C;gBAEA,OAAO,SAAS,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YAC5D;YAEA,KAAK,MAAM,EAAE;gBACX,IAAI,CAAC,CAAC,CAAC,OAAO;AAAE,oBAAA,MAAM,IAAI,eAAe,CAAC,qBAAqB,CAAC;gBAChE,IAAI,CAAC,CAAC,CAAC,OAAO;AAAE,oBAAA,MAAM,IAAI,eAAe,CAAC,qBAAqB,CAAC;AAChE,gBAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CACxB,kBAAkB,EAClB,CAAC,CAAC,OAAO,EACT,CAAA,EAAG,CAAC,CAAC,OAAO,CAAA,GAAA,CAAK,CAClB;gBACD,OAAO,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;YACvC;AAEA,YAAA;AACE,gBAAA,MAAM,IAAI,eAAe,CACvB,oBAAoB,OAAO,CAAA,+BAAA,CAAiC,CAC7D;;IAEP,CAAC;AACF,CAAA;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaypie/mcp",
3
- "version": "0.8.139",
3
+ "version": "0.8.141",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,6 +43,8 @@
43
43
  "typecheck": "tsc --noEmit"
44
44
  },
45
45
  "dependencies": {
46
+ "@jaypie/datadog": "^1.2.7",
47
+ "@jaypie/errors": "^1.2.6",
46
48
  "@jaypie/fabric": "^0.3.3",
47
49
  "@jaypie/kit": "^1.2.12",
48
50
  "@jaypie/tildeskill": "^0.3.3",
@@ -0,0 +1,34 @@
1
+ ---
2
+ version: 1.2.7
3
+ date: 2026-08-30
4
+ summary: Export the Datadog query service as a fabric service and resolve keys through getEnvSecret
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - **`datadogService` is now exported from `@jaypie/datadog`** (#512). The unified
10
+ Datadog query surface (`logs`, `log_analytics`, `monitors`, `synthetics`,
11
+ `metrics`, `rum`, `validate`) moved out of `@jaypie/mcp/suite`. Register it with
12
+ an LLM toolkit through `fabricTool({ service: datadogService })` or with an MCP
13
+ server through `suite.register(datadogService)` without taking the MCP suite and
14
+ its skill files as a dependency.
15
+ - **Keys resolve through `getEnvSecret`** (#513). `resolveDatadogApiKey` and
16
+ `resolveDatadogAppKey` read a `SECRET_<NAME>` or `<NAME>_SECRET` reference from
17
+ Secrets Manager at call time and fall back to the plain environment variable.
18
+ Nothing has to be written into `process.env` by the caller first. The existing
19
+ `DATADOG_API_KEY_ARN`, `DD_API_KEY_SECRET_ARN`, and `SECRET_DATADOG_API_KEY`
20
+ variables keep resolving through `getSecret` so a non-Lambda consumer is
21
+ unaffected.
22
+ - **Jaypie errors from the service** (#516). Missing credentials throw
23
+ `ConfigurationError`; an unknown command or a missing required parameter throws
24
+ `BadRequestError`. An unsuccessful Datadog response is no longer a throw: the
25
+ result carries `success: false` and a status-specific `error`, so a model
26
+ reading the tool output can explain a 403 rather than losing the call to an
27
+ exception.
28
+ - `validateDatadogSetup` now counts a `SECRET_*` reference as a present key.
29
+ - `DATADOG.ENV` gained the application key names; `DATADOG_HELP` and the service
30
+ result types are exported.
31
+
32
+ ## Migration
33
+
34
+ `getDatadogCredentials()` is now async. Await it.
@@ -0,0 +1,26 @@
1
+ ---
2
+ version: 1.2.36
3
+ date: 2026-08-30
4
+ summary: expressHandler accepts sensitiveHeaders and logBody for webhook routes
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - **`sensitiveHeaders`** (#515) adds header names to the request log's redaction
10
+ list. Matching is case-insensitive and the option is additive, so the defaults
11
+ still apply:
12
+
13
+ ```typescript
14
+ expressHandler(controller, {
15
+ sensitiveHeaders: ["x-hub-signature-256", "x-slack-signature"],
16
+ });
17
+ ```
18
+
19
+ - **`logBody: false`** omits the request body from the log, for a route that
20
+ receives a third-party payload the log should not carry.
21
+ - The default list is published as `EXPRESS.HEADER.SENSITIVE`
22
+ (`authorization`, `cookie`, `set-cookie`).
23
+ - Both options apply to `expressStreamHandler` as well.
24
+
25
+ Defaults are unchanged: without either option the handler logs exactly what it
26
+ logged before.
@@ -0,0 +1,11 @@
1
+ ---
2
+ version: 1.2.91
3
+ date: 2026-08-27
4
+ summary: Pulls @jaypie/lambda 1.2.15 (migrationHandler pending poll fix)
5
+ ---
6
+
7
+ # jaypie 1.2.91
8
+
9
+ ## Changed
10
+
11
+ - Depends on `@jaypie/lambda` 1.2.15.
@@ -0,0 +1,12 @@
1
+ ---
2
+ version: 1.2.92
3
+ date: 2026-08-30
4
+ summary: Pick up the Datadog fabric service and the expressHandler logging options
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - `@jaypie/datadog` 1.2.7 — `datadogService` fabric service, `getEnvSecret` key
10
+ resolution, Jaypie errors from the service.
11
+ - `@jaypie/express` 1.2.36 — `sensitiveHeaders` and `logBody` options on
12
+ `expressHandler` and `expressStreamHandler`.
@@ -0,0 +1,15 @@
1
+ ---
2
+ version: 1.2.18
3
+ date: 2026-08-30
4
+ summary: Remove the dead log re-export from core.ts that made the declaration build warn
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - `src/core.ts` no longer imports and re-exports `log` from `@jaypie/logger`. The
10
+ re-export was never reachable from `src/index.ts`, so `rollup-plugin-dts`
11
+ tree-shook it and warned that the import was unused on every build.
12
+ - `jaypieHandler` imports `log` directly from `@jaypie/logger`. It is the same
13
+ singleton, so behavior is unchanged.
14
+ - No public export changed. `log` was not on the package entry point before or
15
+ after.
@@ -0,0 +1,31 @@
1
+ ---
2
+ version: 1.2.15
3
+ date: 2026-08-27
4
+ summary: migrationHandler omits Data on pending polls and skips migrations on Delete
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - `migrationHandler` returns `{ IsComplete: false }` with no `Data` while a migration is pending.
10
+ - Completed polls return `{ Data: result, IsComplete: true }`, and omit `Data` when the handler result is not a plain object.
11
+ - `RequestType: "Delete"` short-circuits without invoking the migration: `onEvent` returns `PhysicalResourceId`, `isComplete` returns `{ IsComplete: true }`.
12
+
13
+ ## Motivation
14
+
15
+ The `cr.Provider` framework throws `"Data" is not allowed if "IsComplete" is "False"`
16
+ when a pending `isComplete` response carries any `Data` keys. Any migration set needing
17
+ more than one invocation therefore failed the custom resource on the first pending poll,
18
+ marking the resource `CREATE_FAILED`. The rollback then invoked the same handler for the
19
+ `Delete` request, ran the next pending migration, failed the same way, and left the stack
20
+ `ROLLBACK_FAILED`.
21
+
22
+ Scalar and array results were also submitted as `Data`, which CloudFormation rejects
23
+ because `Data` must be a map.
24
+
25
+ ## Migration
26
+
27
+ No changes required. Handlers returning `{ pending: true }` now poll correctly. Handlers
28
+ returning a scalar or array no longer expose that value through `Fn::GetAtt`; return a
29
+ plain object to keep resource attributes.
30
+
31
+ Fixes #510.
@@ -0,0 +1,13 @@
1
+ ---
2
+ version: 1.3.34
3
+ date: 2026-08-30
4
+ summary: Externalize @aws-sdk/client-bedrock-runtime so the build stops warning it is unresolved
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - `rollup.config.js` adds `@aws-sdk/client-bedrock-runtime` to `external`. The
10
+ SDK is an optional peer loaded through a dynamic import, so rollup was warning
11
+ it could not resolve it on every build.
12
+ - Emitted output is unchanged: rollup already treated the specifier as external,
13
+ it simply warned while doing so.
@@ -0,0 +1,12 @@
1
+ ---
2
+ version: 0.8.140
3
+ date: 2026-08-27
4
+ summary: Migrations skill documents the isComplete Data protocol and Delete short-circuit
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - `skill("migrations")` records that pending polls carry no `Data`, that completion
10
+ returns `Data` only for plain-object results, and that `Delete` requests skip the
11
+ migration.
12
+ - Release notes for `@jaypie/lambda` 1.2.15 and `jaypie` 1.2.91.
@@ -0,0 +1,13 @@
1
+ ---
2
+ version: 0.8.141
3
+ date: 2026-08-30
4
+ summary: Datadog service moved to @jaypie/datadog; suites throw Jaypie errors
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - The Datadog suite moved to `@jaypie/datadog` (#512). `@jaypie/mcp` now imports
10
+ `datadogService` from that package and registers it unchanged. The MCP tool
11
+ surface is identical.
12
+ - The docs suite throws `BadRequestError` rather than a vanilla `Error` for a
13
+ missing parameter or an unknown command (#516).
@@ -0,0 +1,12 @@
1
+ ---
2
+ version: 1.2.67
3
+ date: 2026-08-30
4
+ summary: Mock the new @jaypie/datadog exports
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - `@jaypie/testkit/mock` passes through `datadogService` and `DATADOG_HELP` from
10
+ `@jaypie/datadog`. The fabric service is passed through rather than stubbed:
11
+ its command router is the behavior under test whenever a consumer registers it
12
+ as a tool.
@@ -0,0 +1,15 @@
1
+ ---
2
+ version: 0.3.4
3
+ date: 2026-08-30
4
+ summary: Derive rollup externals from package.json so a new dependency cannot drift out of the list
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - `rollup.config.js` builds `external` from `dependencies` and
10
+ `peerDependencies` plus `/^node:/`, replacing a hand-maintained array.
11
+ `@jaypie/fabric` and `@jaypie/kit` had been added as dependencies without
12
+ reaching that array, so both warned as unresolved on every build.
13
+ - Drops the stale `gray-matter` entry, which the package neither depends on nor
14
+ imports.
15
+ - Emitted output is unchanged.
package/skills/datadog.md CHANGED
@@ -83,24 +83,68 @@ if (isDatadogForwardingEnabled()) {
83
83
 
84
84
  ## @jaypie/datadog Package
85
85
 
86
- The `@jaypie/datadog` package provides utilities:
86
+ The `@jaypie/datadog` package submits metrics and queries observability data.
87
87
 
88
88
  ```typescript
89
- import { datadogMetric, datadogEvent } from "@jaypie/datadog";
89
+ import { submitMetric, submitMetricSet } from "@jaypie/datadog";
90
90
 
91
- // Send custom metric
92
- await datadogMetric("checkout.completed", 1, {
93
- tags: ["env:production", "service:checkout"],
91
+ // Send one metric
92
+ await submitMetric({
93
+ name: "checkout.completed",
94
+ value: 1,
95
+ tags: { service: "checkout" },
94
96
  });
95
97
 
96
- // Send event
97
- await datadogEvent({
98
- title: "Deployment completed",
99
- text: "Version 1.2.3 deployed to production",
100
- tags: ["env:production"],
98
+ // Send several in one call
99
+ await submitMetricSet({
100
+ metrics: [
101
+ { name: "checkout.completed", value: 1 },
102
+ { name: "checkout.duration", value: 428 },
103
+ ],
101
104
  });
102
105
  ```
103
106
 
107
+ `PROJECT_ENV`, `PROJECT_KEY`, `PROJECT_SERVICE`, `PROJECT_SPONSOR`, and
108
+ `PROJECT_VERSION` are applied as tags automatically. On Lambda with the Datadog
109
+ extension the submission goes over StatsD instead of the HTTP API.
110
+
111
+ ### Query service
112
+
113
+ `datadogService` is a fabric service exporting the same commands as the MCP
114
+ `datadog` tool. Register it wherever a tool registry is wanted, without taking
115
+ `@jaypie/mcp` as a dependency:
116
+
117
+ ```typescript
118
+ import { datadogService } from "@jaypie/datadog";
119
+ import { fabricTool } from "@jaypie/fabric/llm";
120
+
121
+ const tools = [fabricTool({ service: datadogService })];
122
+
123
+ // Or call it directly
124
+ await datadogService({ command: "logs", query: "status:error", from: "now-1h" });
125
+ ```
126
+
127
+ Commands: `logs`, `log_analytics`, `monitors`, `synthetics`, `metrics`, `rum`,
128
+ `validate`. Called with no command it returns its own help.
129
+
130
+ A missing key throws `ConfigurationError`; a bad command or a missing required
131
+ parameter throws `BadRequestError`. An unsuccessful Datadog response is **not** a
132
+ throw: the result carries `success: false` and a status-specific `error` string,
133
+ so an agent can read a 403 and explain it rather than losing the call to an
134
+ exception.
135
+
136
+ ### Key resolution
137
+
138
+ Both keys resolve at call time through `getEnvSecret`, so a Secrets Manager
139
+ reference never has to be written into `process.env` first.
140
+
141
+ | Variable | Purpose |
142
+ |----------|---------|
143
+ | `DATADOG_API_KEY` / `DD_API_KEY` | Plain API key |
144
+ | `SECRET_DATADOG_API_KEY` / `DATADOG_API_KEY_ARN` / `DD_API_KEY_SECRET_ARN` | Secrets Manager ARN, resolved with `getSecret` |
145
+ | `DATADOG_API_KEY_SECRET` | Secrets Manager reference, resolved with `getEnvSecret` |
146
+ | `DATADOG_APP_KEY` / `DATADOG_APPLICATION_KEY` / `DD_APP_KEY` / `DD_APPLICATION_KEY` | Application key, required by the query service |
147
+
104
148
  ### LLM Observability primitives
105
149
 
106
150
  Bundler-safe access to the runtime `dd-trace` LLM Obs singleton. `dd-trace` is resolved at runtime via a computed module specifier (never bundled), so on Lambda these reach the layer-initialized singleton — a bundled copy would be a different instance whose buffer never ships.
package/skills/express.md CHANGED
@@ -48,8 +48,11 @@ app.get("/api/users", expressHandler(async (req, res) => {
48
48
  expressHandler(handler, {
49
49
  fabric: false, // Wrap return with fabricApiResponse before res.json (default false)
50
50
  locals: {}, // Values passed to res.locals
51
+ logBody: true, // Include the request body in the request log
51
52
  name: "handler", // Handler name for logging
53
+ scrub: true, // Withhold error detail from the client, the log, or both
52
54
  secrets: [], // AWS Secrets names to load into process.env
55
+ sensitiveHeaders: [], // Header names redacted in addition to the defaults
53
56
  setup: async (req, res) => {}, // Pre-handler setup
54
57
  teardown: async (req, res) => {}, // Post-handler cleanup
55
58
  unavailable: false, // Return 503 immediately if true
@@ -57,6 +60,30 @@ expressHandler(handler, {
57
60
  });
58
61
  ```
59
62
 
63
+ ### Request Logging
64
+
65
+ `expressHandler` logs a summary of every request. Two options control what that
66
+ summary carries; both also apply to `expressStreamHandler`.
67
+
68
+ ```typescript
69
+ app.post(
70
+ "/webhook/github",
71
+ expressHandler(handleGitHubWebhook, {
72
+ logBody: false,
73
+ sensitiveHeaders: ["x-hub-signature-256"],
74
+ }),
75
+ );
76
+ ```
77
+
78
+ - `sensitiveHeaders` is **additive**. `EXPRESS.HEADER.SENSITIVE`
79
+ (`authorization`, `cookie`, `set-cookie`) is always redacted; these names are
80
+ redacted as well. Matching is case-insensitive.
81
+ - `logBody: false` omits the body entirely, for a route whose payload is
82
+ third-party data the log should not carry.
83
+
84
+ Reach for these on inbound webhook routes, where the provider sends a signature
85
+ header and a body neither of which belongs in the log.
86
+
60
87
  ### fabricApiResponse and `{ fabric: true }`
61
88
 
62
89
  Return plain domain objects and opt into the canonical Jaypie API envelope:
@@ -165,14 +192,18 @@ app.use(cors({ origin: ["https://a.com", "https://b.com"] }));
165
192
  ## EXPRESS Constants
166
193
 
167
194
  ```typescript
168
- import { EXPRESS } from "jaypie";
195
+ import { EXPRESS } from "@jaypie/express";
169
196
 
170
- EXPRESS.HEADER.POWERED_BY // "x-powered-by" (removed by decorateResponse)
171
- EXPRESS.HEADER.PROJECT_KEY // "x-project-key"
172
- EXPRESS.HEADER.REQUEST_ID // "x-request-id"
173
- EXPRESS.PROJECT.EXPRESS // "@jaypie/express"
197
+ EXPRESS.HEADER.SENSITIVE // ["authorization", "cookie", "set-cookie"]
198
+ EXPRESS.PATH.ANY // RegExp matching every path in Express 4 and 5
199
+ EXPRESS.PATH.ID // "/:id"
200
+ EXPRESS.PATH.ROOT // RegExp matching the root path
174
201
  ```
175
202
 
203
+ Header *names* live on `HTTP.HEADER` in `@jaypie/kit`
204
+ (`HTTP.HEADER.POWERED_BY`, `HTTP.HEADER.PROJECT_KEY`,
205
+ `HTTP.HEADER.REQUEST_ID`), not on `EXPRESS`.
206
+
176
207
  ## Request Properties
177
208
 
178
209
  The Lambda adapter provides Express-compatible request properties:
package/skills/logs.md CHANGED
@@ -247,6 +247,22 @@ log.config({
247
247
 
248
248
  The `redact` hook runs ahead of built-in rules on every node; return a replacement value or `undefined` to defer.
249
249
 
250
+ ### Request headers
251
+
252
+ `expressHandler` redacts request headers from its own list, not from
253
+ `redactKeys`. `EXPRESS.HEADER.SENSITIVE` (`authorization`, `cookie`,
254
+ `set-cookie`) always applies; a route adds to it per handler:
255
+
256
+ ```typescript
257
+ expressHandler(handleWebhook, {
258
+ logBody: false,
259
+ sensitiveHeaders: ["x-hub-signature-256"],
260
+ });
261
+ ```
262
+
263
+ Reach for this on inbound webhook routes, where the provider signature header
264
+ and the payload both belong out of the log. See ~express.
265
+
250
266
  ## Lambda Logging
251
267
 
252
268
  Lambda handlers automatically add context:
@@ -7,6 +7,10 @@ related: datadog, mcp, debugging, logs
7
7
 
8
8
  Datadog observability provided by the Jaypie MCP server.
9
9
 
10
+ The service itself lives in `@jaypie/datadog` as `datadogService`. Anything
11
+ described here is available outside the MCP server by importing that package;
12
+ see ~datadog.
13
+
10
14
  ## Usage
11
15
 
12
16
  All parameters are passed at the top level (flat structure):
@@ -55,10 +59,21 @@ datadog({ command: "validate" })
55
59
  ```
56
60
 
57
61
  Returns:
58
- - `apiKey` - { present: boolean, source: "DATADOG_API_KEY" | "DD_API_KEY" | null }
59
- - `appKey` - { present: boolean, source: "DATADOG_APP_KEY" | "DATADOG_APPLICATION_KEY" | "DD_APP_KEY" | "DD_APPLICATION_KEY" | null }
62
+ - `apiKey` - { present: boolean, source: string | null }
63
+ - `appKey` - { present: boolean, source: string | null }
60
64
  - `success` - true if both keys are present
61
65
 
66
+ `source` names the variable that supplies the key. A `SECRET_<NAME>` or
67
+ `<NAME>_SECRET` reference counts as present and is reported under that name,
68
+ because it resolves at call time.
69
+
70
+ ## Errors
71
+
72
+ A missing key throws `ConfigurationError`. An unknown command or a missing
73
+ required parameter throws `BadRequestError`. An unsuccessful Datadog response is
74
+ not a throw: the result carries `success: false` and an `error` string naming the
75
+ cause, so a 403 or a rate limit is readable rather than fatal.
76
+
62
77
  ## Environment Variables
63
78
 
64
79
  Configure defaults via environment:
@@ -69,6 +84,11 @@ Configure defaults via environment:
69
84
  | `DATADOG_APP_KEY` or `DD_APP_KEY` | Application key (required) |
70
85
  | `DD_ENV` | Default environment filter |
71
86
 
87
+ Either key may be held in Secrets Manager instead. `SECRET_DATADOG_API_KEY`,
88
+ `DATADOG_API_KEY_ARN`, and `DD_API_KEY_SECRET_ARN` take an ARN; any key name
89
+ also accepts a `SECRET_<NAME>` or `<NAME>_SECRET` reference. Resolution happens
90
+ on the call, so nothing has to be loaded into the environment first.
91
+
72
92
  ## Log Search
73
93
 
74
94
  Search individual log entries:
@@ -45,7 +45,7 @@ new JaypieMigration(this, "SeedData", {
45
45
 
46
46
  - **Timeout**: 15 minutes per invocation (Lambda max); `totalTimeout` controls the end-to-end ceiling across all polling invocations (default 2 hours)
47
47
  - **Role**: Tagged as `CDK.ROLE.PROCESSING`
48
- - **Execution**: Uses `cr.Provider` with both `onEventHandler` and `isCompleteHandler` pointing to the same Lambda. The `onEventHandler` returns `PhysicalResourceId` immediately; the migration code runs in `isCompleteHandler` invocations, which are polled by Step Functions until `IsComplete: true`.
48
+ - **Execution**: Uses `cr.Provider` with both `onEventHandler` and `isCompleteHandler` pointing to the same Lambda. The `onEventHandler` returns `PhysicalResourceId` immediately; the migration code runs in `isCompleteHandler` invocations, which are polled by Step Functions until `IsComplete: true`. `Delete` requests skip the migration entirely.
49
49
  - **Dependencies**: Use `dependencies` to ensure tables and other resources exist before the migration executes
50
50
  - **Permissions**: Tables passed via `tables` get data-plane (`grantReadWriteData`) plus control-plane access (`DescribeTable`, `UpdateTable`, `UpdateTimeToLive`, `UpdateContinuousBackups`) scoped to the table ARN and its indexes — migrations that add GSIs, toggle TTL, or change backups work without extra IAM
51
51
 
@@ -85,7 +85,20 @@ export const handler = migrationHandler(async (event) => {
85
85
 
86
86
  `migrationHandler` maps the `pending` flag onto CFN's `IsComplete` protocol:
87
87
  - `pending: true` → `{ IsComplete: false }` — waiter re-invokes after `queryInterval`
88
- - `pending: false` or omitted → `{ IsComplete: true }` — deploy proceeds
88
+ - `pending: false` or omitted → `{ IsComplete: true, Data: result }` — deploy proceeds
89
+
90
+ Pending responses carry no `Data`. The `cr.Provider` framework rejects
91
+ `Data` alongside `IsComplete: false` with `"Data" is not allowed if "IsComplete" is "False"`,
92
+ which fails the custom resource on the first pending poll. On completion the handler
93
+ result is returned as `Data` only when it is a plain object; scalar and array results
94
+ are reported complete without `Data` because CloudFormation accepts a map only.
95
+
96
+ ### Delete requests
97
+
98
+ `migrationHandler` short-circuits `RequestType: "Delete"` without invoking the migration
99
+ code. The resource being migrated is usually torn down in the same operation, so running
100
+ migrations against it is wasted work, and a failure there strands the stack in
101
+ `ROLLBACK_FAILED`.
89
102
 
90
103
  ## Building Migration Code
91
104