@jaypie/mcp 0.8.28 → 0.8.29

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.
@@ -1,5 +1,5 @@
1
1
  import { fabricService } from '@jaypie/fabric';
2
- import { createMarkdownStore, createLayeredStore, normalizeAlias, isValidAlias } from '@jaypie/tildeskill';
2
+ import { createMarkdownStore, createLayeredStore, createSkillService } from '@jaypie/tildeskill';
3
3
  import * as fs from 'node:fs/promises';
4
4
  import * as path from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
@@ -9,7 +9,7 @@ import { gt } from 'semver';
9
9
  /**
10
10
  * Docs Suite - Documentation services (skill, version, release_notes)
11
11
  */
12
- const BUILD_VERSION_STRING = "@jaypie/mcp@0.8.28#dbd0faa2"
12
+ const BUILD_VERSION_STRING = "@jaypie/mcp@0.8.29#e602beb5"
13
13
  ;
14
14
  const __filename$1 = fileURLToPath(import.meta.url);
15
15
  const __dirname$1 = path.dirname(__filename$1);
@@ -28,19 +28,16 @@ const LAYER_SEPARATOR = ":";
28
28
  // the built-in Jaypie skill pack so `skill("aws")` prefers the client's copy
29
29
  // while still exposing bundled Jaypie docs under the `jaypie:` namespace.
30
30
  const skillLayers = [];
31
- const skillLayerPaths = new Map();
32
31
  if (process.env.MCP_SKILLS_PATH) {
33
32
  skillLayers.push({
34
33
  namespace: LOCAL_SKILLS_NAMESPACE,
35
34
  store: createMarkdownStore({ path: process.env.MCP_SKILLS_PATH }),
36
35
  });
37
- skillLayerPaths.set(LOCAL_SKILLS_NAMESPACE, process.env.MCP_SKILLS_PATH);
38
36
  }
39
37
  skillLayers.push({
40
38
  namespace: JAYPIE_SKILLS_NAMESPACE,
41
39
  store: createMarkdownStore({ path: BUILTIN_SKILLS_PATH }),
42
40
  });
43
- skillLayerPaths.set(JAYPIE_SKILLS_NAMESPACE, BUILTIN_SKILLS_PATH);
44
41
  const skillStore = createLayeredStore({
45
42
  layers: skillLayers,
46
43
  separator: LAYER_SEPARATOR,
@@ -76,13 +73,6 @@ function formatReleaseNoteListItem(note) {
76
73
  }
77
74
  return parts.join(" ");
78
75
  }
79
- function formatSkillListItem(skill) {
80
- const { alias, description } = skill;
81
- if (description) {
82
- return `* ${alias} - ${description}`;
83
- }
84
- return `* ${alias}`;
85
- }
86
76
  async function getPackageReleaseNotes(packageName) {
87
77
  const packageDir = path.join(RELEASE_NOTES_PATH, packageName);
88
78
  try {
@@ -122,70 +112,7 @@ function filterReleaseNotesSince(notes, sinceVersion) {
122
112
  // =============================================================================
123
113
  // SKILL SERVICE
124
114
  // =============================================================================
125
- /**
126
- * Add alias to frontmatter indicating the canonical skill name
127
- */
128
- function addAliasToFrontmatter(content, matchedAlias) {
129
- if (content.startsWith("---")) {
130
- // Find the end of frontmatter
131
- const endIndex = content.indexOf("---", 3);
132
- if (endIndex !== -1) {
133
- // Insert alias before the closing ---
134
- const beforeClose = content.slice(0, endIndex);
135
- const afterClose = content.slice(endIndex);
136
- return `${beforeClose}alias: ${matchedAlias}\n${afterClose}`;
137
- }
138
- }
139
- // No frontmatter exists, create one
140
- return `---\nalias: ${matchedAlias}\n---\n\n${content}`;
141
- }
142
- const skillService = fabricService({
143
- alias: "skill",
144
- 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.",
145
- input: {
146
- alias: {
147
- description: "Skill alias (e.g., 'aws', 'tests'). Omit or use 'index' to list all skills.",
148
- required: false,
149
- type: String,
150
- },
151
- },
152
- service: async ({ alias: inputAlias }) => {
153
- const alias = normalizeAlias(inputAlias || "index");
154
- if (!isValidAlias(alias)) {
155
- throw new Error(`Invalid skill alias "${alias}". Use alphanumeric characters, hyphens, and underscores only.`);
156
- }
157
- if (alias === "index") {
158
- const allSkills = await skillStore.list();
159
- // Index entries from every layer hide per-layer "index" records.
160
- const skills = allSkills.filter((s) => s.alias !== "index" && !s.alias.endsWith(`${LAYER_SEPARATOR}index`));
161
- const skillList = skills.map(formatSkillListItem).join("\n");
162
- return `# Index of Skills\n\n${skillList}`;
163
- }
164
- const skill = await skillStore.find(alias);
165
- if (!skill) {
166
- throw new Error(`Skill "${alias}" not found. Use skill("index") to list available skills.`);
167
- }
168
- // Split the namespaced alias the layered store returned (e.g., "local:aws")
169
- // so we can read the raw markdown file from the correct layer directory.
170
- const separatorIdx = skill.alias.indexOf(LAYER_SEPARATOR);
171
- const layerNamespace = separatorIdx === -1 ? "" : skill.alias.slice(0, separatorIdx);
172
- const innerAlias = separatorIdx === -1 ? skill.alias : skill.alias.slice(separatorIdx + 1);
173
- const layerPath = skillLayerPaths.get(layerNamespace);
174
- if (!layerPath) {
175
- // Defensive: layered store returned a layer we don't know the path for.
176
- return skill.content;
177
- }
178
- const skillPath = path.join(layerPath, `${innerAlias}.md`);
179
- let content = await fs.readFile(skillPath, "utf-8");
180
- // Detect plural/singular fallback so we can annotate the canonical alias.
181
- const inputSeparatorIdx = alias.indexOf(LAYER_SEPARATOR);
182
- const inputInnerAlias = inputSeparatorIdx === -1 ? alias : alias.slice(inputSeparatorIdx + 1);
183
- if (innerAlias !== inputInnerAlias) {
184
- content = addAliasToFrontmatter(content, skill.alias);
185
- }
186
- return content;
187
- },
188
- });
115
+ const skillService = createSkillService(skillStore);
189
116
  // =============================================================================
190
117
  // VERSION SERVICE
191
118
  // =============================================================================
@@ -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 {\n createLayeredStore,\n createMarkdownStore,\n isValidAlias,\n type LayeredStoreLayer,\n normalizeAlias,\n type SkillRecord,\n} from \"@jaypie/tildeskill\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport matter from \"gray-matter\";\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[] = [];\nconst skillLayerPaths = new Map<string, string>();\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 skillLayerPaths.set(LOCAL_SKILLS_NAMESPACE, process.env.MCP_SKILLS_PATH);\n}\n\nskillLayers.push({\n namespace: JAYPIE_SKILLS_NAMESPACE,\n store: createMarkdownStore({ path: BUILTIN_SKILLS_PATH }),\n});\nskillLayerPaths.set(JAYPIE_SKILLS_NAMESPACE, BUILTIN_SKILLS_PATH);\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 parsed = matter(content);\n const frontMatter = parsed.data as ReleaseNoteFrontMatter;\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\nfunction formatSkillListItem(skill: SkillRecord): string {\n const { alias, description } = skill;\n if (description) {\n return `* ${alias} - ${description}`;\n }\n return `* ${alias}`;\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\n/**\n * Add alias to frontmatter indicating the canonical skill name\n */\nfunction addAliasToFrontmatter(content: string, matchedAlias: string): string {\n if (content.startsWith(\"---\")) {\n // Find the end of frontmatter\n const endIndex = content.indexOf(\"---\", 3);\n if (endIndex !== -1) {\n // Insert alias before the closing ---\n const beforeClose = content.slice(0, endIndex);\n const afterClose = content.slice(endIndex);\n return `${beforeClose}alias: ${matchedAlias}\\n${afterClose}`;\n }\n }\n // No frontmatter exists, create one\n return `---\\nalias: ${matchedAlias}\\n---\\n\\n${content}`;\n}\n\nexport const skillService = fabricService({\n alias: \"skill\",\n description:\n \"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.\",\n input: {\n alias: {\n description:\n \"Skill alias (e.g., 'aws', 'tests'). Omit or use 'index' to list all skills.\",\n required: false,\n type: String,\n },\n },\n service: async ({ alias: inputAlias }: { alias?: string }) => {\n const alias = normalizeAlias(inputAlias || \"index\");\n\n if (!isValidAlias(alias)) {\n throw new Error(\n `Invalid skill alias \"${alias}\". Use alphanumeric characters, hyphens, and underscores only.`,\n );\n }\n\n if (alias === \"index\") {\n const allSkills = await skillStore.list();\n // Index entries from every layer hide per-layer \"index\" records.\n const skills = allSkills.filter(\n (s: { alias: string }) =>\n s.alias !== \"index\" && !s.alias.endsWith(`${LAYER_SEPARATOR}index`),\n );\n const skillList = skills.map(formatSkillListItem).join(\"\\n\");\n\n return `# Index of Skills\\n\\n${skillList}`;\n }\n\n const skill = await skillStore.find(alias);\n\n if (!skill) {\n throw new Error(\n `Skill \"${alias}\" not found. Use skill(\"index\") to list available skills.`,\n );\n }\n\n // Split the namespaced alias the layered store returned (e.g., \"local:aws\")\n // so we can read the raw markdown file from the correct layer directory.\n const separatorIdx = skill.alias.indexOf(LAYER_SEPARATOR);\n const layerNamespace =\n separatorIdx === -1 ? \"\" : skill.alias.slice(0, separatorIdx);\n const innerAlias =\n separatorIdx === -1 ? skill.alias : skill.alias.slice(separatorIdx + 1);\n const layerPath = skillLayerPaths.get(layerNamespace);\n if (!layerPath) {\n // Defensive: layered store returned a layer we don't know the path for.\n return skill.content;\n }\n\n const skillPath = path.join(layerPath, `${innerAlias}.md`);\n let content = await fs.readFile(skillPath, \"utf-8\");\n\n // Detect plural/singular fallback so we can annotate the canonical alias.\n const inputSeparatorIdx = alias.indexOf(LAYER_SEPARATOR);\n const inputInnerAlias =\n inputSeparatorIdx === -1 ? alias : alias.slice(inputSeparatorIdx + 1);\n if (innerAlias !== inputInnerAlias) {\n content = addAliasToFrontmatter(content, skill.alias);\n }\n\n return content;\n },\n});\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 { fabricService } from \"@jaypie/fabric\";\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 matter from \"gray-matter\";\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 parsed = matter(content);\n const frontMatter = parsed.data as ReleaseNoteFrontMatter;\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaypie/mcp",
3
- "version": "0.8.28",
3
+ "version": "0.8.29",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@jaypie/fabric": "^0.2.4",
43
- "@jaypie/tildeskill": "^0.3.0",
43
+ "@jaypie/tildeskill": "^0.3.1",
44
44
  "@modelcontextprotocol/sdk": "^1.17.0",
45
45
  "commander": "^14.0.0",
46
46
  "gray-matter": "^4.0.3",
@@ -0,0 +1,13 @@
1
+ ---
2
+ version: 0.8.29
3
+ date: 2026-04-12
4
+ summary: Delegate skill service to @jaypie/tildeskill createSkillService
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - Replace inline `skillService` with `createSkillService(skillStore)` from `@jaypie/tildeskill`
10
+ - Skill lookups now automatically expand includes
11
+ - Plural/singular fallback annotates with `<!-- resolved: -->` HTML comment instead of injecting frontmatter
12
+ - Remove raw file reading, `addAliasToFrontmatter`, `formatSkillListItem`, and `skillLayerPaths` from MCP
13
+ - Bump `@jaypie/tildeskill` dependency to `^0.3.1`
@@ -0,0 +1,9 @@
1
+ ---
2
+ version: 1.2.32
3
+ date: 2026-04-12
4
+ summary: Add createSkillService mock for tildeskill parity
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - Add `createSkillService` mock to tildeskill mock module
@@ -0,0 +1,12 @@
1
+ ---
2
+ version: 0.3.1
3
+ date: 2026-04-12
4
+ summary: Add createSkillService factory for reusable skill lookup as a fabricService
5
+ ---
6
+
7
+ ## Changes
8
+
9
+ - Add `createSkillService(store)` factory that returns a `fabricService` wrapping any `SkillStore`
10
+ - The service handles index listing, alias validation, `find()` with plural/singular fallback, and automatic `expandIncludes`
11
+ - Compatible with `fabricTool()` for `Llm.operate` toolkits and `suite.register()` for MCP servers
12
+ - Add `@jaypie/fabric` as a dependency (lightweight; only requires `@jaypie/errors`)
@@ -87,6 +87,27 @@ const store = createMemoryStore([
87
87
  const skill = await store.get("test");
88
88
  ```
89
89
 
90
+ ## Skill Service Factory
91
+
92
+ ```typescript
93
+ import { createSkillService, createMemoryStore } from "@jaypie/tildeskill";
94
+
95
+ const store = createMemoryStore([
96
+ { alias: "aws", content: "# AWS docs", description: "AWS guide" },
97
+ ]);
98
+
99
+ // Returns a fabricService — works with MCP, Llm.operate, or direct calls
100
+ const skillService = createSkillService(store);
101
+
102
+ await skillService({ alias: "aws" }); // → skill content (with expandIncludes)
103
+ await skillService({ alias: "index" }); // → formatted listing
104
+ await skillService(); // → same as "index"
105
+
106
+ // Use with fabricTool for Llm.operate toolkits
107
+ import { fabricTool } from "@jaypie/fabric/llm";
108
+ const { tool } = fabricTool({ service: skillService });
109
+ ```
110
+
90
111
  ## Include Expansion
91
112
 
92
113
  ```typescript