@kubb/mcp 5.14.6 → 5.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +13 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -2
- package/dist/index.d.ts +0 -2
- package/dist/index.js +12 -24
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
2
|
+
// \0rolldown/runtime.js
|
|
3
3
|
var __create = Object.create;
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -20,7 +20,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
20
20
|
value: mod,
|
|
21
21
|
enumerable: true
|
|
22
22
|
}) : target, mod));
|
|
23
|
-
//#endregion
|
|
24
23
|
let _tmcp_adapter_valibot = require("@tmcp/adapter-valibot");
|
|
25
24
|
let _tmcp_transport_stdio = require("@tmcp/transport-stdio");
|
|
26
25
|
let tmcp = require("tmcp");
|
|
@@ -39,10 +38,9 @@ let valibot = require("valibot");
|
|
|
39
38
|
valibot = __toESM(valibot, 1);
|
|
40
39
|
let node_util = require("node:util");
|
|
41
40
|
let _kubb_adapter_oas = require("@kubb/adapter-oas");
|
|
42
|
-
|
|
43
|
-
var version = "5.
|
|
44
|
-
|
|
45
|
-
//#region ../../internals/shared/src/constants.ts
|
|
41
|
+
// package.json
|
|
42
|
+
var version = "5.15.0";
|
|
43
|
+
// ../../internals/shared/src/constants.ts
|
|
46
44
|
const KUBB_CONFIG_FILENAME = "kubb.config.ts";
|
|
47
45
|
/** File extensions a Kubb config file may use. */
|
|
48
46
|
const CONFIG_EXTENSIONS = [
|
|
@@ -53,8 +51,7 @@ const CONFIG_EXTENSIONS = [
|
|
|
53
51
|
".mjs",
|
|
54
52
|
".cjs"
|
|
55
53
|
];
|
|
56
|
-
|
|
57
|
-
//#region ../../internals/shared/src/loader.ts
|
|
54
|
+
// ../../internals/shared/src/loader.ts
|
|
58
55
|
/**
|
|
59
56
|
* jiti options for loading Kubb config modules: the automatic JSX runtime pointed at
|
|
60
57
|
* `@kubb/renderer-jsx`, and `moduleCache` off so a re-load re-evaluates the file.
|
|
@@ -92,8 +89,7 @@ async function loadModule(filePath, options) {
|
|
|
92
89
|
});
|
|
93
90
|
return options?.default ? mod?.default ?? mod : mod;
|
|
94
91
|
}
|
|
95
|
-
|
|
96
|
-
//#region ../../internals/shared/src/config.ts
|
|
92
|
+
// ../../internals/shared/src/config.ts
|
|
97
93
|
const CONFIG_FOLDERS = [".config", "configs"];
|
|
98
94
|
const SEARCH_FILES = ["", ...CONFIG_FOLDERS.map((folder) => `${folder}/`)].flatMap((prefix) => [`${prefix}.kubbrc`, `${prefix}kubb.config`]);
|
|
99
95
|
/**
|
|
@@ -128,8 +124,7 @@ async function loadConfigFile({ file, cli }) {
|
|
|
128
124
|
root: (0, node_path.resolve)(dir, config.root ?? ".")
|
|
129
125
|
}));
|
|
130
126
|
}
|
|
131
|
-
|
|
132
|
-
//#region ../../internals/shared/src/init.ts
|
|
127
|
+
// ../../internals/shared/src/init.ts
|
|
133
128
|
/** The `kubb.config.ts` `kubb init` writes before `kubb add` puts each plugin in. */
|
|
134
129
|
function generateConfigFile({ inputPath, outputPath }) {
|
|
135
130
|
return `import { defineConfig } from 'kubb/config'
|
|
@@ -144,8 +139,7 @@ export default defineConfig({
|
|
|
144
139
|
})
|
|
145
140
|
`;
|
|
146
141
|
}
|
|
147
|
-
|
|
148
|
-
//#region ../../internals/utils/src/fs.ts
|
|
142
|
+
// ../../internals/utils/src/fs.ts
|
|
149
143
|
/**
|
|
150
144
|
* Resolves to `true` when `path` is `parent` itself or nested inside it. Both sides are resolved
|
|
151
145
|
* to absolute paths first, so relative and `..`-containing inputs compare correctly.
|
|
@@ -167,8 +161,7 @@ function isPathInside(path, parent) {
|
|
|
167
161
|
const rel = (0, node_path.relative)(resolvedParent, resolvedPath);
|
|
168
162
|
return rel !== "" && !rel.startsWith("..") && !(0, node_path.isAbsolute)(rel);
|
|
169
163
|
}
|
|
170
|
-
|
|
171
|
-
//#region src/utils.ts
|
|
164
|
+
// src/utils.ts
|
|
172
165
|
/**
|
|
173
166
|
* Renders diagnostics as a plain-text block for an AI assistant, through the same
|
|
174
167
|
* `Diagnostics.format` the CLI uses for agents, without ANSI styling. Each entry keeps the stable
|
|
@@ -178,8 +171,7 @@ function isPathInside(path, parent) {
|
|
|
178
171
|
function formatDiagnostics(diagnostics) {
|
|
179
172
|
return diagnostics.map((diagnostic) => (0, node_util.stripVTControlCharacters)(_kubb_core.Diagnostics.format(diagnostic, { audience: "agent" }).join("\n"))).join("\n\n");
|
|
180
173
|
}
|
|
181
|
-
|
|
182
|
-
//#region src/tools/generate.ts
|
|
174
|
+
// src/tools/generate.ts
|
|
183
175
|
const generateSchema = valibot.object({
|
|
184
176
|
config: valibot.optional(valibot.pipe(valibot.string(), valibot.minLength(1), valibot.description(`Path to kubb.config file (supports ${CONFIG_EXTENSIONS.join(", ")}). If not provided, will look for kubb.config.* or .kubbrc.* in the current directory, its .config/ and configs/ folders, then each parent directory`))),
|
|
185
177
|
input: valibot.optional(valibot.pipe(valibot.string(), valibot.minLength(1), valibot.description("Path to OpenAPI/Swagger spec file (overrides config)"))),
|
|
@@ -266,8 +258,7 @@ const generateTool = (0, tmcp_tool.defineTool)({
|
|
|
266
258
|
return failure("Build error", [_kubb_core.Diagnostics.from(caughtError)]);
|
|
267
259
|
}
|
|
268
260
|
});
|
|
269
|
-
|
|
270
|
-
//#region src/tools/init.ts
|
|
261
|
+
// src/tools/init.ts
|
|
271
262
|
const initSchema = valibot.object({
|
|
272
263
|
input: valibot.optional(valibot.pipe(valibot.string(), valibot.minLength(1), valibot.description("Path to OpenAPI spec (default: ./openapi.yaml)"))),
|
|
273
264
|
output: valibot.optional(valibot.pipe(valibot.string(), valibot.minLength(1), valibot.description("Output directory (default: ./src/gen)")))
|
|
@@ -285,8 +276,7 @@ const initTool = (0, tmcp_tool.defineTool)({
|
|
|
285
276
|
}), "utf-8");
|
|
286
277
|
return tmcp_utils.tool.text(`Created ${KUBB_CONFIG_FILENAME}\n\nInstall Kubb:\n npm install kubb\n\nAdd each plugin with its registry id, which installs it and adds it to the config:\n npx kubb add plugin-ts --yes\n\nThen run:\n npx kubb generate`);
|
|
287
278
|
});
|
|
288
|
-
|
|
289
|
-
//#region src/tools/validate.ts
|
|
279
|
+
// src/tools/validate.ts
|
|
290
280
|
const validateSchema = valibot.object({ input: valibot.pipe(valibot.string(), valibot.minLength(1), valibot.description("Path or URL to the OpenAPI/Swagger specification")) });
|
|
291
281
|
const validateTool = (0, tmcp_tool.defineTool)({
|
|
292
282
|
name: "validate",
|
|
@@ -302,8 +292,7 @@ const validateTool = (0, tmcp_tool.defineTool)({
|
|
|
302
292
|
return tmcp_utils.tool.error(`Validation failed:\n${formatDiagnostics([diagnostic])}\n\n\`\`\`json\n${JSON.stringify(serialized, null, 2)}\n\`\`\``);
|
|
303
293
|
}
|
|
304
294
|
});
|
|
305
|
-
|
|
306
|
-
//#region src/server.ts
|
|
295
|
+
// src/server.ts
|
|
307
296
|
/**
|
|
308
297
|
* Builds the Kubb MCP server with the generate, validate, and init tools registered.
|
|
309
298
|
*
|
|
@@ -334,7 +323,6 @@ function startServer() {
|
|
|
334
323
|
new _tmcp_transport_stdio.StdioTransport(server).listen();
|
|
335
324
|
return server;
|
|
336
325
|
}
|
|
337
|
-
//#endregion
|
|
338
326
|
exports.createMcpServer = createMcpServer;
|
|
339
327
|
exports.run = startServer;
|
|
340
328
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["jiti","createJiti","readFile","join","process","resolve","dirname","existsSync","basename","resolve","relative","isAbsolute","stripVTControlCharacters","Diagnostics","v","defineTool","Diagnostics","tool","Hookable","path","process","createKubb","v","defineTool","path","process","fs","tool","v","defineTool","adapterOas","tool","Diagnostics","McpServer","ValibotJsonSchemaAdapter","StdioTransport"],"sources":["../package.json","../../../internals/shared/src/constants.ts","../../../internals/shared/src/loader.ts","../../../internals/shared/src/config.ts","../../../internals/shared/src/init.ts","../../../internals/utils/src/fs.ts","../src/utils.ts","../src/tools/generate.ts","../src/tools/init.ts","../src/tools/validate.ts","../src/server.ts"],"sourcesContent":["","export const KUBB_CONFIG_FILENAME = 'kubb.config.ts' as const\n\n/** File extensions a Kubb config file may use. */\nexport const CONFIG_EXTENSIONS = ['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'] as const\n\nexport const KUBB_PACKAGE_NAME = 'kubb' as const\n\n/**\n * Extensions `kubb` ships at its own version, so they count as installed without being a direct\n * dependency. `constants.test.ts` checks it against the `kubb` package's dependencies.\n */\nexport const BUNDLED_PACKAGES: ReadonlyArray<string> = ['@kubb/adapter-oas', '@kubb/parser-ts', '@kubb/parser-md', '@kubb/plugin-barrel']\n\nexport const initDefaults = {\n inputPath: './openapi.yaml',\n outputPath: './src/gen',\n plugins: ['plugin-ts'],\n} as const\n","import { readFile } from 'node:fs/promises'\nimport { createJiti } from 'jiti'\n\n/**\n * jiti options for loading Kubb config modules: the automatic JSX runtime pointed at\n * `@kubb/renderer-jsx`, and `moduleCache` off so a re-load re-evaluates the file.\n */\nconst JITI_OPTIONS = {\n jsx: { runtime: 'automatic', importSource: '@kubb/renderer-jsx' },\n moduleCache: false,\n} satisfies Parameters<typeof createJiti>[1]\n\n/**\n * Plain JavaScript files. jiti hands these to Node's native `import()`, whose module cache never\n * lets go of a file, so `moduleCache: false` alone would keep returning the first version of it.\n */\nconst JAVASCRIPT_EXTENSION = /\\.[cm]?jsx?$/\n\n/**\n * Per-call options for {@link loadModule}.\n */\ntype LoadModuleOptions = {\n /**\n * Return the module's default export instead of the full namespace.\n */\n default?: boolean\n}\n\nconst jiti = createJiti(import.meta.url, JITI_OPTIONS)\n\n/**\n * Loads a Kubb TypeScript or JavaScript config module via jiti.\n *\n * jiti transpiles TypeScript and the `@kubb/renderer-jsx` JSX runtime on the fly. Every load\n * re-evaluates the file, so a config edited on disk is picked up by the next load.\n *\n * @example\n * ```ts\n * const config = await loadModule('/abs/kubb.config.ts', { default: true })\n * ```\n */\nexport async function loadModule<T = unknown>(filePath: string, options?: LoadModuleOptions): Promise<T> {\n if (!JAVASCRIPT_EXTENSION.test(filePath)) {\n return (options?.default ? jiti.import(filePath, { default: true }) : jiti.import(filePath)) as Promise<T>\n }\n\n // Transpiled through jiti instead, so every load re-evaluates the file as it is on disk now.\n // A TypeScript file it imports reloads too. A plain JavaScript file it imports still goes\n // through Node's `import()` and stays cached until the process restarts.\n const mod = (await jiti.evalModule(await readFile(filePath, 'utf8'), { filename: filePath, async: true, forceTranspile: true })) as\n | { default?: unknown }\n | undefined\n return (options?.default ? (mod?.default ?? mod) : mod) as T\n}\n","import { existsSync } from 'node:fs'\nimport { basename, dirname, join, resolve } from 'node:path'\nimport process from 'node:process'\nimport { CONFIG_EXTENSIONS } from './constants.ts'\nimport { loadModule } from './loader.ts'\n\n// A config in one of these folders belongs to the folder above it.\nconst CONFIG_FOLDERS = ['.config', 'configs']\nconst SEARCH_FILES = ['', ...CONFIG_FOLDERS.map((folder) => `${folder}/`)].flatMap((prefix) => [`${prefix}.kubbrc`, `${prefix}kubb.config`])\n\n/**\n * Every config file path the Kubb CLI checks in `dir`, in the order it checks them.\n */\nexport function configFileCandidates(dir: string): Array<string> {\n return SEARCH_FILES.flatMap((file) => CONFIG_EXTENSIONS.map((extension) => join(dir, `${file}${extension}`)))\n}\n\n/**\n * The first Kubb config file in `cwd` or the nearest parent folder that has one: `.kubbrc` before\n * `kubb.config`, the folder itself before its `.config/` and `configs/`, and {@link CONFIG_EXTENSIONS} in order.\n */\nexport function findConfigFile(cwd: string = process.cwd()): string | undefined {\n for (let dir = resolve(cwd); ; dir = dirname(dir)) {\n const found = configFileCandidates(dir).find((file) => existsSync(file))\n if (found || dirname(dir) === dir) return found\n }\n}\n\n/**\n * Loads a Kubb config module, calls it with `cli` when it exports a function, and returns its\n * configs as a list, so a single config and a `defineConfig([...])` array read the same. Each\n * `root` resolves from the folder the config belongs to: the file's folder, or the folder above\n * `.config/` and `configs/`. A missing `root` becomes that folder, so the CLI, the bundler, and\n * an editor read the same paths wherever they run.\n */\nexport async function loadConfigFile<T extends { root?: string }>({ file, cli }: { file: string; cli: unknown }): Promise<Array<T>> {\n const loaded = await loadModule<unknown>(file, { default: true })\n const resolved = (await (typeof loaded === 'function' ? loaded(cli) : loaded)) as T | Array<T>\n const dir = CONFIG_FOLDERS.includes(basename(dirname(file))) ? dirname(dirname(file)) : dirname(file)\n return (Array.isArray(resolved) ? resolved : [resolved]).map((config) => ({ ...config, root: resolve(dir, config.root ?? '.') }))\n}\n","/** The `kubb.config.ts` `kubb init` writes before `kubb add` puts each plugin in. */\nexport function generateConfigFile({ inputPath, outputPath }: { inputPath: string; outputPath: string }): string {\n return `import { defineConfig } from 'kubb/config'\n\nexport default defineConfig({\n input: '${inputPath}',\n output: {\n path: '${outputPath}',\n clean: true,\n },\n plugins: [],\n})\n`\n}\n","import { access, glob as globNode, mkdir, readFile, writeFile } from 'node:fs/promises'\n\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { runtime } from './runtime.ts'\n\nexport { existsSync } from 'node:fs'\nexport { mkdir, mkdtemp, rm } from 'node:fs/promises'\n\n/**\n * Resolves to `true` when the file or directory at `path` exists.\n * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.\n *\n * @example\n * ```ts\n * if (await exists('./kubb.config.ts')) {\n * const content = await read('./kubb.config.ts')\n * }\n * ```\n */\nexport async function exists(path: string): Promise<boolean> {\n if (runtime.isBun) {\n return Bun.file(path).exists()\n }\n return access(path).then(\n () => true,\n () => false,\n )\n}\n\n/**\n * Reads the file at `path` as a UTF-8 string.\n * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.\n *\n * @example\n * ```ts\n * const source = await read('./src/Pet.ts')\n * ```\n */\nexport async function read(path: string): Promise<string> {\n if (runtime.isBun) {\n return Bun.file(path).text()\n }\n return readFile(path, { encoding: 'utf8' })\n}\n\ntype WriteOptions = {\n /**\n * Previously read content, or `null` when the file does not exist.\n * Omitting this value reads the file before writing.\n */\n stored?: string | null\n /**\n * When `true`, re-reads the file immediately after writing and throws if the\n * content does not match — useful for catching write failures on unreliable file systems.\n */\n sanity?: boolean\n}\n\n/**\n * Whether `stored` already holds `source`, comparing on the trimmed text rather than the exact\n * bytes. Surrounding whitespace is what a formatter adds and what editors strip, and neither is a\n * reason to rewrite the file.\n *\n * Both sides are trimmed, so a storage that keeps bytes verbatim settles on the same answer as one\n * that normalizes what it stores. Trimming only `stored` would leave a source with leading\n * whitespace rewritten on every build, since the stored copy keeps the whitespace the comparison\n * has already dropped.\n */\nexport function matchesStored({ stored, source }: { stored: string; source: string }): boolean {\n return stored.trim() === source.trim()\n}\n\n/**\n * Writes `data` to `path`, trimming surrounding whitespace and ending the file with a single newline\n * the way prettier, biome, and oxfmt all do.\n * Skips the write when the trimmed content is empty, or when the file already holds that content.\n * Creates any missing parent directories automatically.\n * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.\n *\n * @example\n * ```ts\n * await write('./src/Pet.ts', source) // writes and returns the trimmed content plus a newline\n * await write('./src/Pet.ts', source) // null — file unchanged\n * await write('./src/Pet.ts', ' ') // null — empty content skipped\n * ```\n */\nexport async function write(path: string, data: string, options: WriteOptions = {}): Promise<string | null> {\n const trimmed = data.trim()\n if (trimmed === '') return null\n\n const content = `${trimmed}\\n`\n const resolved = resolve(path)\n let stored = options.stored\n\n if (stored === undefined) {\n if (runtime.isBun) {\n const file = Bun.file(resolved)\n stored = (await file.exists()) ? await file.text() : null\n } else {\n try {\n stored = await readFile(resolved, { encoding: 'utf-8' })\n } catch {\n /* file doesn't exist yet */\n stored = null\n }\n }\n }\n if (matchesStored({ stored: stored ?? '', source: trimmed })) return null\n\n await writeRaw(resolved, content)\n\n if (options.sanity) {\n const savedData = await read(resolved)\n if (savedData !== content) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n return savedData\n }\n\n return content\n}\n\n/**\n * Writes UTF-8 content verbatim, including empty files and surrounding whitespace.\n * Uses Bun.write under Bun and creates missing parent directories under either runtime.\n *\n * @example\n * await writeRaw('./cache/output.ts', ' // keep these bytes\\n\\n')\n */\nexport async function writeRaw(path: string, content: string): Promise<void> {\n const resolved = resolve(path)\n if (runtime.isBun) {\n await Bun.write(resolved, content)\n return\n }\n try {\n await writeFile(resolved, content, { encoding: 'utf-8' })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n await mkdir(dirname(resolved), { recursive: true })\n await writeFile(resolved, content, { encoding: 'utf-8' })\n }\n}\n\n/**\n * Lists non-hidden regular files below `directory` as relative POSIX paths, excluding directories and symlinks.\n * Uses Bun.Glob under Bun because its Node glob compatibility API lacks directory-entry support.\n *\n * @example\n * for await (const path of listFiles('./src')) console.log(path)\n */\nexport async function* listFiles(directory: string): AsyncGenerator<string> {\n const cwd = resolve(directory)\n if (runtime.isBun) {\n yield* new Bun.Glob('**/*').scan({ cwd, dot: false, onlyFiles: true, followSymlinks: false })\n return\n }\n for await (const entry of globNode('**/*', { cwd, withFileTypes: true })) {\n if (entry.isFile()) yield toPosixPath(relative(cwd, join(entry.parentPath, entry.name)))\n }\n}\n\n/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n\n/**\n * Resolves to `true` when `path` is `parent` itself or nested inside it. Both sides are resolved\n * to absolute paths first, so relative and `..`-containing inputs compare correctly.\n *\n * Guards a destructive or an out-of-tree operation: before wiping an output directory, check that\n * it does not contain the project root, and before loading a path a caller supplied, check that it\n * did not escape the directory it is allowed to read from.\n *\n * @example\n * isPathInside('./src/gen', '.') // true — nested inside the root\n * isPathInside('.', '.') // true — the same directory counts as inside\n * isPathInside('.', './src/gen') // false — the root is not inside its own output\n * isPathInside('../other', '.') // false — escapes the root\n */\nexport function isPathInside(path: string, parent: string): boolean {\n const resolvedPath = resolve(path)\n const resolvedParent = resolve(parent)\n if (resolvedPath === resolvedParent) {\n return true\n }\n\n const rel = relative(resolvedParent, resolvedPath)\n\n return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel)\n}\n","import { stripVTControlCharacters } from 'node:util'\nimport { type Diagnostic, Diagnostics } from '@kubb/core'\n\n/**\n * Renders diagnostics as a plain-text block for an AI assistant, through the same\n * `Diagnostics.format` the CLI uses for agents, without ANSI styling. Each entry keeps the stable\n * code, the source pointer, the cause, the fix, the underlying errors, the docs link, and the issue\n * tracker, so the agent can act on the problem rather than parsing a bare message.\n */\nexport function formatDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): string {\n return diagnostics.map((diagnostic) => stripVTControlCharacters(Diagnostics.format(diagnostic, { audience: 'agent' }).join('\\n'))).join('\\n\\n')\n}\n","import path from 'node:path'\nimport process from 'node:process'\nimport { CONFIG_EXTENSIONS, findConfigFile, loadConfigFile } from '@internals/shared'\nimport { isPathInside } from '@internals/utils'\nimport { type Config, createKubb, type Diagnostic, Diagnostics, type KubbHooks, Hookable } from '@kubb/core'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\nimport { formatDiagnostics } from '../utils.ts'\n\nconst generateSchema = v.object({\n config: v.optional(\n v.pipe(\n v.string(),\n v.minLength(1),\n v.description(\n `Path to kubb.config file (supports ${CONFIG_EXTENSIONS.join(', ')}). If not provided, will look for kubb.config.* or .kubbrc.* in the current directory, its .config/ and configs/ folders, then each parent directory`,\n ),\n ),\n ),\n input: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Path to OpenAPI/Swagger spec file (overrides config)'))),\n output: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Output directory path (overrides config)'))),\n logLevel: v.optional(v.pipe(v.picklist(['silent', 'info', 'verbose']), v.description('Log level for build output')), 'info'),\n})\n\nexport const generateTool = defineTool(\n {\n name: 'generate',\n description: 'Generate OpenAPI spec helpers using Kubb configuration',\n schema: generateSchema,\n },\n async function generate(schema: v.InferInput<typeof generateSchema>) {\n const { config: configPath, input, output, logLevel } = schema\n const messages: Array<string> = []\n\n /**\n * The failure response: the diagnostics as text and JSON, then the messages collected so far,\n * such as warnings, so the agent sees everything the run said.\n */\n const failure = (title: string, diagnostics: ReadonlyArray<Diagnostic>) => {\n const serialized = diagnostics.map((diagnostic) => Diagnostics.serialize(diagnostic))\n const log = messages.length ? `\\n\\nMessages:\\n${messages.join('\\n')}` : ''\n return tool.error(`${title}:\\n${formatDiagnostics(diagnostics)}\\n\\n\\`\\`\\`json\\n${JSON.stringify(serialized, null, 2)}\\n\\`\\`\\`${log}`)\n }\n\n try {\n const hooks = new Hookable<KubbHooks>()\n\n const notify = (type: string, message: string, data?: Record<string, unknown>) => {\n messages.push(data ? `${type}: ${message} ${JSON.stringify(data)}` : `${type}: ${message}`)\n }\n\n hooks.hook('kubb:error', ({ error }) => notify('ERROR', error.message))\n hooks.hook('kubb:warn', ({ message }) => notify('WARN', message))\n hooks.hook('kubb:diagnostic', ({ diagnostic }) => notify('DIAGNOSTIC', diagnostic.message, Diagnostics.serialize(diagnostic)))\n\n // The AI client supplies the path, so it must carry a config extension and stay inside the working directory.\n const base = path.resolve(process.cwd())\n let file: string | undefined\n if (configPath) {\n const ext = path.extname(configPath)\n if (!CONFIG_EXTENSIONS.some((extension) => extension === ext)) {\n return tool.error(`Invalid config file extension \"${ext}\". Allowed: ${CONFIG_EXTENSIONS.join(', ')}`)\n }\n file = path.resolve(base, configPath)\n if (!isPathInside(file, base)) {\n return tool.error('Invalid config file path: must be within the current working directory')\n }\n } else {\n file = findConfigFile(base)\n if (!file) {\n return tool.error(\n `No config file found. Please provide a config path or create one of: ${CONFIG_EXTENSIONS.map((extension) => `kubb.config${extension}`).join(', ')}`,\n )\n }\n }\n\n let userConfig: Config\n try {\n const [first] = await loadConfigFile<Config>({ file, cli: { logLevel, config: configPath } })\n if (!first)\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The config file exports an empty array of configurations',\n })\n userConfig = first\n } catch (error) {\n return failure(`Failed to load config ${file}`, [Diagnostics.from(error)])\n }\n\n const config: Config = {\n ...userConfig,\n input: input ?? userConfig.input,\n output: output\n ? {\n ...userConfig.output,\n path: output,\n }\n : userConfig.output,\n }\n\n notify('CONFIG_READY', 'Configuration ready')\n\n const kubb = createKubb(config, { hooks })\n const result = await kubb.generate()\n notify('BUILD_END', `Build complete - Generated ${result.files.length} files`)\n\n const problems = result.diagnostics.filter(Diagnostics.isProblem)\n const errors = problems.filter((diagnostic) => diagnostic.severity === 'error')\n if (errors.length > 0) {\n notify('BUILD_FAILED', `Build failed with ${errors.length} diagnostic(s)`)\n\n return failure('Build failed', problems)\n }\n\n notify('BUILD_SUCCESS', `Build completed successfully - Generated ${result.files.length} files`)\n\n return tool.text(`Build completed successfully!\\n\\nGenerated ${result.files.length} files\\n\\n${messages.join('\\n')}`)\n } catch (caughtError) {\n return failure('Build error', [Diagnostics.from(caughtError)])\n }\n },\n)\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { generateConfigFile, KUBB_CONFIG_FILENAME } from '@internals/shared'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\n\nconst initSchema = v.object({\n input: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Path to OpenAPI spec (default: ./openapi.yaml)'))),\n output: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Output directory (default: ./src/gen)'))),\n})\n\nexport const initTool = defineTool(\n {\n name: 'init',\n description:\n 'Scaffold a kubb.config.ts in the current directory (non-interactive). Does not install packages or add plugins: run `kubb add <id> --yes` for each plugin afterwards.',\n schema: initSchema,\n },\n async ({ input = './openapi.yaml', output = './src/gen' }) => {\n const dest = path.join(process.cwd(), KUBB_CONFIG_FILENAME)\n if (fs.existsSync(dest)) {\n return tool.error(`${KUBB_CONFIG_FILENAME} already exists at ${dest}. Delete it first before running init again.`)\n }\n fs.writeFileSync(dest, generateConfigFile({ inputPath: input, outputPath: output }), 'utf-8')\n return tool.text(\n `Created ${KUBB_CONFIG_FILENAME}\\n\\nInstall Kubb:\\n npm install kubb\\n\\nAdd each plugin with its registry id, which installs it and adds it to the config:\\n npx kubb add plugin-ts --yes\\n\\nThen run:\\n npx kubb generate`,\n )\n },\n)\n","import { adapterOas } from '@kubb/adapter-oas'\nimport { Diagnostics } from '@kubb/core'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\nimport { formatDiagnostics } from '../utils.ts'\n\nconst validateSchema = v.object({\n input: v.pipe(v.string(), v.minLength(1), v.description('Path or URL to the OpenAPI/Swagger specification')),\n})\n\nexport const validateTool = defineTool(\n {\n name: 'validate',\n description: 'Validate an OpenAPI/Swagger specification file or URL',\n schema: validateSchema,\n },\n async ({ input }) => {\n try {\n await adapterOas().validate(input, { throwOnError: true })\n return tool.text(`Validation successful: ${input}`)\n } catch (err) {\n const diagnostic = Diagnostics.from(err)\n const serialized = Diagnostics.serialize(diagnostic)\n return tool.error(`Validation failed:\\n${formatDiagnostics([diagnostic])}\\n\\n\\`\\`\\`json\\n${JSON.stringify(serialized, null, 2)}\\n\\`\\`\\``)\n }\n },\n)\n","import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot'\nimport { StdioTransport } from '@tmcp/transport-stdio'\nimport { McpServer } from 'tmcp'\nimport { version } from '../package.json'\nimport { generateTool } from './tools/generate.ts'\nimport { initTool } from './tools/init.ts'\nimport { validateTool } from './tools/validate.ts'\n\n/**\n * Builds the Kubb MCP server with the generate, validate, and init tools registered.\n *\n * @example\n * `const server = createMcpServer()`\n */\nexport function createMcpServer() {\n const server = new McpServer({ name: 'Kubb', version }, { adapter: new ValibotJsonSchemaAdapter(), capabilities: { tools: {} } })\n server.tools([generateTool, validateTool, initTool])\n return server\n}\n\n/**\n * Starts the Kubb MCP server over stdio, the transport every local MCP client\n * (Claude, Copilot, editors) uses when it launches the server as a subprocess.\n */\nexport function startServer() {\n const server = createMcpServer()\n new StdioTransport(server).listen()\n return server\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["jiti","createJiti","readFile","join","process","resolve","dirname","existsSync","basename","resolve","relative","isAbsolute","stripVTControlCharacters","Diagnostics","v","defineTool","Diagnostics","tool","Hookable","path","process","createKubb","v","defineTool","path","process","fs","tool","v","defineTool","adapterOas","tool","Diagnostics","McpServer","ValibotJsonSchemaAdapter","StdioTransport"],"sources":["../package.json","../../../internals/shared/src/constants.ts","../../../internals/shared/src/loader.ts","../../../internals/shared/src/config.ts","../../../internals/shared/src/init.ts","../../../internals/utils/src/fs.ts","../src/utils.ts","../src/tools/generate.ts","../src/tools/init.ts","../src/tools/validate.ts","../src/server.ts"],"sourcesContent":["","export const KUBB_CONFIG_FILENAME = 'kubb.config.ts' as const\n\n/** File extensions a Kubb config file may use. */\nexport const CONFIG_EXTENSIONS = ['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'] as const\n\nexport const KUBB_PACKAGE_NAME = 'kubb' as const\n\n/**\n * Extensions `kubb` ships at its own version, so they count as installed without being a direct\n * dependency. `constants.test.ts` checks it against the `kubb` package's dependencies.\n */\nexport const BUNDLED_PACKAGES: ReadonlyArray<string> = ['@kubb/adapter-oas', '@kubb/parser-ts', '@kubb/parser-md', '@kubb/plugin-barrel']\n\nexport const initDefaults = {\n inputPath: './openapi.yaml',\n outputPath: './src/gen',\n plugins: ['plugin-ts'],\n} as const\n","import { readFile } from 'node:fs/promises'\nimport { createJiti } from 'jiti'\n\n/**\n * jiti options for loading Kubb config modules: the automatic JSX runtime pointed at\n * `@kubb/renderer-jsx`, and `moduleCache` off so a re-load re-evaluates the file.\n */\nconst JITI_OPTIONS = {\n jsx: { runtime: 'automatic', importSource: '@kubb/renderer-jsx' },\n moduleCache: false,\n} satisfies Parameters<typeof createJiti>[1]\n\n/**\n * Plain JavaScript files. jiti hands these to Node's native `import()`, whose module cache never\n * lets go of a file, so `moduleCache: false` alone would keep returning the first version of it.\n */\nconst JAVASCRIPT_EXTENSION = /\\.[cm]?jsx?$/\n\n/**\n * Per-call options for {@link loadModule}.\n */\ntype LoadModuleOptions = {\n /**\n * Return the module's default export instead of the full namespace.\n */\n default?: boolean\n}\n\nconst jiti = createJiti(import.meta.url, JITI_OPTIONS)\n\n/**\n * Loads a Kubb TypeScript or JavaScript config module via jiti.\n *\n * jiti transpiles TypeScript and the `@kubb/renderer-jsx` JSX runtime on the fly. Every load\n * re-evaluates the file, so a config edited on disk is picked up by the next load.\n *\n * @example\n * ```ts\n * const config = await loadModule('/abs/kubb.config.ts', { default: true })\n * ```\n */\nexport async function loadModule<T = unknown>(filePath: string, options?: LoadModuleOptions): Promise<T> {\n if (!JAVASCRIPT_EXTENSION.test(filePath)) {\n return (options?.default ? jiti.import(filePath, { default: true }) : jiti.import(filePath)) as Promise<T>\n }\n\n // Transpiled through jiti instead, so every load re-evaluates the file as it is on disk now.\n // A TypeScript file it imports reloads too. A plain JavaScript file it imports still goes\n // through Node's `import()` and stays cached until the process restarts.\n const mod = (await jiti.evalModule(await readFile(filePath, 'utf8'), { filename: filePath, async: true, forceTranspile: true })) as\n | { default?: unknown }\n | undefined\n return (options?.default ? (mod?.default ?? mod) : mod) as T\n}\n","import { existsSync } from 'node:fs'\nimport { basename, dirname, join, resolve } from 'node:path'\nimport process from 'node:process'\nimport { CONFIG_EXTENSIONS } from './constants.ts'\nimport { loadModule } from './loader.ts'\n\n// A config in one of these folders belongs to the folder above it.\nconst CONFIG_FOLDERS = ['.config', 'configs']\nconst SEARCH_FILES = ['', ...CONFIG_FOLDERS.map((folder) => `${folder}/`)].flatMap((prefix) => [`${prefix}.kubbrc`, `${prefix}kubb.config`])\n\n/**\n * Every config file path the Kubb CLI checks in `dir`, in the order it checks them.\n */\nexport function configFileCandidates(dir: string): Array<string> {\n return SEARCH_FILES.flatMap((file) => CONFIG_EXTENSIONS.map((extension) => join(dir, `${file}${extension}`)))\n}\n\n/**\n * The first Kubb config file in `cwd` or the nearest parent folder that has one: `.kubbrc` before\n * `kubb.config`, the folder itself before its `.config/` and `configs/`, and {@link CONFIG_EXTENSIONS} in order.\n */\nexport function findConfigFile(cwd: string = process.cwd()): string | undefined {\n for (let dir = resolve(cwd); ; dir = dirname(dir)) {\n const found = configFileCandidates(dir).find((file) => existsSync(file))\n if (found || dirname(dir) === dir) return found\n }\n}\n\n/**\n * Loads a Kubb config module, calls it with `cli` when it exports a function, and returns its\n * configs as a list, so a single config and a `defineConfig([...])` array read the same. Each\n * `root` resolves from the folder the config belongs to: the file's folder, or the folder above\n * `.config/` and `configs/`. A missing `root` becomes that folder, so the CLI, the bundler, and\n * an editor read the same paths wherever they run.\n */\nexport async function loadConfigFile<T extends { root?: string }>({ file, cli }: { file: string; cli: unknown }): Promise<Array<T>> {\n const loaded = await loadModule<unknown>(file, { default: true })\n const resolved = (await (typeof loaded === 'function' ? loaded(cli) : loaded)) as T | Array<T>\n const dir = CONFIG_FOLDERS.includes(basename(dirname(file))) ? dirname(dirname(file)) : dirname(file)\n return (Array.isArray(resolved) ? resolved : [resolved]).map((config) => ({ ...config, root: resolve(dir, config.root ?? '.') }))\n}\n","/** The `kubb.config.ts` `kubb init` writes before `kubb add` puts each plugin in. */\nexport function generateConfigFile({ inputPath, outputPath }: { inputPath: string; outputPath: string }): string {\n return `import { defineConfig } from 'kubb/config'\n\nexport default defineConfig({\n input: '${inputPath}',\n output: {\n path: '${outputPath}',\n clean: true,\n },\n plugins: [],\n})\n`\n}\n","import { access, glob as globNode, mkdir, readFile, writeFile } from 'node:fs/promises'\n\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { runtime } from './runtime.ts'\n\nexport { existsSync } from 'node:fs'\nexport { mkdir, mkdtemp, rm } from 'node:fs/promises'\n\n/**\n * Resolves to `true` when the file or directory at `path` exists.\n * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.\n *\n * @example\n * ```ts\n * if (await exists('./kubb.config.ts')) {\n * const content = await read('./kubb.config.ts')\n * }\n * ```\n */\nexport async function exists(path: string): Promise<boolean> {\n if (runtime.isBun) {\n return Bun.file(path).exists()\n }\n return access(path).then(\n () => true,\n () => false,\n )\n}\n\n/**\n * Reads the file at `path` as a UTF-8 string.\n * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.\n *\n * @example\n * ```ts\n * const source = await read('./src/Pet.ts')\n * ```\n */\nexport async function read(path: string): Promise<string> {\n if (runtime.isBun) {\n return Bun.file(path).text()\n }\n return readFile(path, { encoding: 'utf8' })\n}\n\ntype WriteOptions = {\n /**\n * Previously read content, or `null` when the file does not exist.\n * Omitting this value reads the file before writing.\n */\n stored?: string | null\n /**\n * When `true`, re-reads the file immediately after writing and throws if the\n * content does not match — useful for catching write failures on unreliable file systems.\n */\n sanity?: boolean\n}\n\n/**\n * Whether `stored` already holds `source`, comparing on the trimmed text rather than the exact\n * bytes. Surrounding whitespace is what a formatter adds and what editors strip, and neither is a\n * reason to rewrite the file.\n *\n * Both sides are trimmed, so a storage that keeps bytes verbatim settles on the same answer as one\n * that normalizes what it stores. Trimming only `stored` would leave a source with leading\n * whitespace rewritten on every build, since the stored copy keeps the whitespace the comparison\n * has already dropped.\n */\nexport function matchesStored({ stored, source }: { stored: string; source: string }): boolean {\n return stored.trim() === source.trim()\n}\n\n/**\n * Writes `data` to `path`, trimming surrounding whitespace and ending the file with a single newline\n * the way prettier, biome, and oxfmt all do.\n * Skips the write when the trimmed content is empty, or when the file already holds that content.\n * Creates any missing parent directories automatically.\n * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.\n *\n * @example\n * ```ts\n * await write('./src/Pet.ts', source) // writes and returns the trimmed content plus a newline\n * await write('./src/Pet.ts', source) // null — file unchanged\n * await write('./src/Pet.ts', ' ') // null — empty content skipped\n * ```\n */\nexport async function write(path: string, data: string, options: WriteOptions = {}): Promise<string | null> {\n const trimmed = data.trim()\n if (trimmed === '') return null\n\n const content = `${trimmed}\\n`\n const resolved = resolve(path)\n let stored = options.stored\n\n if (stored === undefined) {\n if (runtime.isBun) {\n const file = Bun.file(resolved)\n stored = (await file.exists()) ? await file.text() : null\n } else {\n try {\n stored = await readFile(resolved, { encoding: 'utf-8' })\n } catch {\n /* file doesn't exist yet */\n stored = null\n }\n }\n }\n if (matchesStored({ stored: stored ?? '', source: trimmed })) return null\n\n await writeRaw(resolved, content)\n\n if (options.sanity) {\n const savedData = await read(resolved)\n if (savedData !== content) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n return savedData\n }\n\n return content\n}\n\n/**\n * Writes UTF-8 content verbatim, including empty files and surrounding whitespace.\n * Uses Bun.write under Bun and creates missing parent directories under either runtime.\n *\n * @example\n * await writeRaw('./cache/output.ts', ' // keep these bytes\\n\\n')\n */\nexport async function writeRaw(path: string, content: string): Promise<void> {\n const resolved = resolve(path)\n if (runtime.isBun) {\n await Bun.write(resolved, content)\n return\n }\n try {\n await writeFile(resolved, content, { encoding: 'utf-8' })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n await mkdir(dirname(resolved), { recursive: true })\n await writeFile(resolved, content, { encoding: 'utf-8' })\n }\n}\n\n/**\n * Lists non-hidden regular files below `directory` as relative POSIX paths, excluding directories and symlinks.\n * Uses Bun.Glob under Bun because its Node glob compatibility API lacks directory-entry support.\n *\n * @example\n * for await (const path of listFiles('./src')) console.log(path)\n */\nexport async function* listFiles(directory: string): AsyncGenerator<string> {\n const cwd = resolve(directory)\n if (runtime.isBun) {\n yield* new Bun.Glob('**/*').scan({ cwd, dot: false, onlyFiles: true, followSymlinks: false })\n return\n }\n for await (const entry of globNode('**/*', { cwd, withFileTypes: true })) {\n if (entry.isFile()) yield toPosixPath(relative(cwd, join(entry.parentPath, entry.name)))\n }\n}\n\n/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n\n/**\n * Resolves to `true` when `path` is `parent` itself or nested inside it. Both sides are resolved\n * to absolute paths first, so relative and `..`-containing inputs compare correctly.\n *\n * Guards a destructive or an out-of-tree operation: before wiping an output directory, check that\n * it does not contain the project root, and before loading a path a caller supplied, check that it\n * did not escape the directory it is allowed to read from.\n *\n * @example\n * isPathInside('./src/gen', '.') // true — nested inside the root\n * isPathInside('.', '.') // true — the same directory counts as inside\n * isPathInside('.', './src/gen') // false — the root is not inside its own output\n * isPathInside('../other', '.') // false — escapes the root\n */\nexport function isPathInside(path: string, parent: string): boolean {\n const resolvedPath = resolve(path)\n const resolvedParent = resolve(parent)\n if (resolvedPath === resolvedParent) {\n return true\n }\n\n const rel = relative(resolvedParent, resolvedPath)\n\n return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel)\n}\n","import { stripVTControlCharacters } from 'node:util'\nimport { type Diagnostic, Diagnostics } from '@kubb/core'\n\n/**\n * Renders diagnostics as a plain-text block for an AI assistant, through the same\n * `Diagnostics.format` the CLI uses for agents, without ANSI styling. Each entry keeps the stable\n * code, the source pointer, the cause, the fix, the underlying errors, the docs link, and the issue\n * tracker, so the agent can act on the problem rather than parsing a bare message.\n */\nexport function formatDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): string {\n return diagnostics.map((diagnostic) => stripVTControlCharacters(Diagnostics.format(diagnostic, { audience: 'agent' }).join('\\n'))).join('\\n\\n')\n}\n","import path from 'node:path'\nimport process from 'node:process'\nimport { CONFIG_EXTENSIONS, findConfigFile, loadConfigFile } from '@internals/shared'\nimport { isPathInside } from '@internals/utils'\nimport { type Config, createKubb, type Diagnostic, Diagnostics, type KubbHooks, Hookable } from '@kubb/core'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\nimport { formatDiagnostics } from '../utils.ts'\n\nconst generateSchema = v.object({\n config: v.optional(\n v.pipe(\n v.string(),\n v.minLength(1),\n v.description(\n `Path to kubb.config file (supports ${CONFIG_EXTENSIONS.join(', ')}). If not provided, will look for kubb.config.* or .kubbrc.* in the current directory, its .config/ and configs/ folders, then each parent directory`,\n ),\n ),\n ),\n input: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Path to OpenAPI/Swagger spec file (overrides config)'))),\n output: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Output directory path (overrides config)'))),\n logLevel: v.optional(v.pipe(v.picklist(['silent', 'info', 'verbose']), v.description('Log level for build output')), 'info'),\n})\n\nexport const generateTool = defineTool(\n {\n name: 'generate',\n description: 'Generate OpenAPI spec helpers using Kubb configuration',\n schema: generateSchema,\n },\n async function generate(schema: v.InferInput<typeof generateSchema>) {\n const { config: configPath, input, output, logLevel } = schema\n const messages: Array<string> = []\n\n /**\n * The failure response: the diagnostics as text and JSON, then the messages collected so far,\n * such as warnings, so the agent sees everything the run said.\n */\n const failure = (title: string, diagnostics: ReadonlyArray<Diagnostic>) => {\n const serialized = diagnostics.map((diagnostic) => Diagnostics.serialize(diagnostic))\n const log = messages.length ? `\\n\\nMessages:\\n${messages.join('\\n')}` : ''\n return tool.error(`${title}:\\n${formatDiagnostics(diagnostics)}\\n\\n\\`\\`\\`json\\n${JSON.stringify(serialized, null, 2)}\\n\\`\\`\\`${log}`)\n }\n\n try {\n const hooks = new Hookable<KubbHooks>()\n\n const notify = (type: string, message: string, data?: Record<string, unknown>) => {\n messages.push(data ? `${type}: ${message} ${JSON.stringify(data)}` : `${type}: ${message}`)\n }\n\n hooks.hook('kubb:error', ({ error }) => notify('ERROR', error.message))\n hooks.hook('kubb:warn', ({ message }) => notify('WARN', message))\n hooks.hook('kubb:diagnostic', ({ diagnostic }) => notify('DIAGNOSTIC', diagnostic.message, Diagnostics.serialize(diagnostic)))\n\n // The AI client supplies the path, so it must carry a config extension and stay inside the working directory.\n const base = path.resolve(process.cwd())\n let file: string | undefined\n if (configPath) {\n const ext = path.extname(configPath)\n if (!CONFIG_EXTENSIONS.some((extension) => extension === ext)) {\n return tool.error(`Invalid config file extension \"${ext}\". Allowed: ${CONFIG_EXTENSIONS.join(', ')}`)\n }\n file = path.resolve(base, configPath)\n if (!isPathInside(file, base)) {\n return tool.error('Invalid config file path: must be within the current working directory')\n }\n } else {\n file = findConfigFile(base)\n if (!file) {\n return tool.error(\n `No config file found. Please provide a config path or create one of: ${CONFIG_EXTENSIONS.map((extension) => `kubb.config${extension}`).join(', ')}`,\n )\n }\n }\n\n let userConfig: Config\n try {\n const [first] = await loadConfigFile<Config>({ file, cli: { logLevel, config: configPath } })\n if (!first)\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The config file exports an empty array of configurations',\n })\n userConfig = first\n } catch (error) {\n return failure(`Failed to load config ${file}`, [Diagnostics.from(error)])\n }\n\n const config: Config = {\n ...userConfig,\n input: input ?? userConfig.input,\n output: output\n ? {\n ...userConfig.output,\n path: output,\n }\n : userConfig.output,\n }\n\n notify('CONFIG_READY', 'Configuration ready')\n\n const kubb = createKubb(config, { hooks })\n const result = await kubb.generate()\n notify('BUILD_END', `Build complete - Generated ${result.files.length} files`)\n\n const problems = result.diagnostics.filter(Diagnostics.isProblem)\n const errors = problems.filter((diagnostic) => diagnostic.severity === 'error')\n if (errors.length > 0) {\n notify('BUILD_FAILED', `Build failed with ${errors.length} diagnostic(s)`)\n\n return failure('Build failed', problems)\n }\n\n notify('BUILD_SUCCESS', `Build completed successfully - Generated ${result.files.length} files`)\n\n return tool.text(`Build completed successfully!\\n\\nGenerated ${result.files.length} files\\n\\n${messages.join('\\n')}`)\n } catch (caughtError) {\n return failure('Build error', [Diagnostics.from(caughtError)])\n }\n },\n)\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { generateConfigFile, KUBB_CONFIG_FILENAME } from '@internals/shared'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\n\nconst initSchema = v.object({\n input: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Path to OpenAPI spec (default: ./openapi.yaml)'))),\n output: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Output directory (default: ./src/gen)'))),\n})\n\nexport const initTool = defineTool(\n {\n name: 'init',\n description:\n 'Scaffold a kubb.config.ts in the current directory (non-interactive). Does not install packages or add plugins: run `kubb add <id> --yes` for each plugin afterwards.',\n schema: initSchema,\n },\n async ({ input = './openapi.yaml', output = './src/gen' }) => {\n const dest = path.join(process.cwd(), KUBB_CONFIG_FILENAME)\n if (fs.existsSync(dest)) {\n return tool.error(`${KUBB_CONFIG_FILENAME} already exists at ${dest}. Delete it first before running init again.`)\n }\n fs.writeFileSync(dest, generateConfigFile({ inputPath: input, outputPath: output }), 'utf-8')\n return tool.text(\n `Created ${KUBB_CONFIG_FILENAME}\\n\\nInstall Kubb:\\n npm install kubb\\n\\nAdd each plugin with its registry id, which installs it and adds it to the config:\\n npx kubb add plugin-ts --yes\\n\\nThen run:\\n npx kubb generate`,\n )\n },\n)\n","import { adapterOas } from '@kubb/adapter-oas'\nimport { Diagnostics } from '@kubb/core'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\nimport { formatDiagnostics } from '../utils.ts'\n\nconst validateSchema = v.object({\n input: v.pipe(v.string(), v.minLength(1), v.description('Path or URL to the OpenAPI/Swagger specification')),\n})\n\nexport const validateTool = defineTool(\n {\n name: 'validate',\n description: 'Validate an OpenAPI/Swagger specification file or URL',\n schema: validateSchema,\n },\n async ({ input }) => {\n try {\n await adapterOas().validate(input, { throwOnError: true })\n return tool.text(`Validation successful: ${input}`)\n } catch (err) {\n const diagnostic = Diagnostics.from(err)\n const serialized = Diagnostics.serialize(diagnostic)\n return tool.error(`Validation failed:\\n${formatDiagnostics([diagnostic])}\\n\\n\\`\\`\\`json\\n${JSON.stringify(serialized, null, 2)}\\n\\`\\`\\``)\n }\n },\n)\n","import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot'\nimport { StdioTransport } from '@tmcp/transport-stdio'\nimport { McpServer } from 'tmcp'\nimport { version } from '../package.json'\nimport { generateTool } from './tools/generate.ts'\nimport { initTool } from './tools/init.ts'\nimport { validateTool } from './tools/validate.ts'\n\n/**\n * Builds the Kubb MCP server with the generate, validate, and init tools registered.\n *\n * @example\n * `const server = createMcpServer()`\n */\nexport function createMcpServer() {\n const server = new McpServer({ name: 'Kubb', version }, { adapter: new ValibotJsonSchemaAdapter(), capabilities: { tools: {} } })\n server.tools([generateTool, validateTool, initTool])\n return server\n}\n\n/**\n * Starts the Kubb MCP server over stdio, the transport every local MCP client\n * (Claude, Copilot, editors) uses when it launches the server as a subprocess.\n */\nexport function startServer() {\n const server = createMcpServer()\n new StdioTransport(server).listen()\n return server\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { McpServer } from "tmcp";
|
|
2
|
-
//#region src/server.d.ts
|
|
3
2
|
/**
|
|
4
3
|
* Builds the Kubb MCP server with the generate, validate, and init tools registered.
|
|
5
4
|
*
|
|
@@ -12,6 +11,5 @@ export declare function createMcpServer(): McpServer<import("valibot").GenericSc
|
|
|
12
11
|
* (Claude, Copilot, editors) uses when it launches the server as a subprocess.
|
|
13
12
|
*/
|
|
14
13
|
declare function startServer(): McpServer<import("valibot").GenericSchema, undefined>;
|
|
15
|
-
//#endregion
|
|
16
14
|
export { startServer as run };
|
|
17
15
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { McpServer } from "tmcp";
|
|
2
|
-
//#region src/server.d.ts
|
|
3
2
|
/**
|
|
4
3
|
* Builds the Kubb MCP server with the generate, validate, and init tools registered.
|
|
5
4
|
*
|
|
@@ -12,6 +11,5 @@ export declare function createMcpServer(): McpServer<import("valibot").GenericSc
|
|
|
12
11
|
* (Claude, Copilot, editors) uses when it launches the server as a subprocess.
|
|
13
12
|
*/
|
|
14
13
|
declare function startServer(): McpServer<import("valibot").GenericSchema, undefined>;
|
|
15
|
-
//#endregion
|
|
16
14
|
export { startServer as run };
|
|
17
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -12,11 +12,9 @@ import { tool } from "tmcp/utils";
|
|
|
12
12
|
import * as v from "valibot";
|
|
13
13
|
import { stripVTControlCharacters } from "node:util";
|
|
14
14
|
import { adapterOas } from "@kubb/adapter-oas";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
//#endregion
|
|
19
|
-
//#region ../../internals/shared/src/constants.ts
|
|
15
|
+
// package.json
|
|
16
|
+
var version = "5.15.0";
|
|
17
|
+
// ../../internals/shared/src/constants.ts
|
|
20
18
|
const KUBB_CONFIG_FILENAME = "kubb.config.ts";
|
|
21
19
|
/** File extensions a Kubb config file may use. */
|
|
22
20
|
const CONFIG_EXTENSIONS = [
|
|
@@ -27,8 +25,7 @@ const CONFIG_EXTENSIONS = [
|
|
|
27
25
|
".mjs",
|
|
28
26
|
".cjs"
|
|
29
27
|
];
|
|
30
|
-
|
|
31
|
-
//#region ../../internals/shared/src/loader.ts
|
|
28
|
+
// ../../internals/shared/src/loader.ts
|
|
32
29
|
/**
|
|
33
30
|
* jiti options for loading Kubb config modules: the automatic JSX runtime pointed at
|
|
34
31
|
* `@kubb/renderer-jsx`, and `moduleCache` off so a re-load re-evaluates the file.
|
|
@@ -66,8 +63,7 @@ async function loadModule(filePath, options) {
|
|
|
66
63
|
});
|
|
67
64
|
return options?.default ? mod?.default ?? mod : mod;
|
|
68
65
|
}
|
|
69
|
-
|
|
70
|
-
//#region ../../internals/shared/src/config.ts
|
|
66
|
+
// ../../internals/shared/src/config.ts
|
|
71
67
|
const CONFIG_FOLDERS = [".config", "configs"];
|
|
72
68
|
const SEARCH_FILES = ["", ...CONFIG_FOLDERS.map((folder) => `${folder}/`)].flatMap((prefix) => [`${prefix}.kubbrc`, `${prefix}kubb.config`]);
|
|
73
69
|
/**
|
|
@@ -102,8 +98,7 @@ async function loadConfigFile({ file, cli }) {
|
|
|
102
98
|
root: resolve(dir, config.root ?? ".")
|
|
103
99
|
}));
|
|
104
100
|
}
|
|
105
|
-
|
|
106
|
-
//#region ../../internals/shared/src/init.ts
|
|
101
|
+
// ../../internals/shared/src/init.ts
|
|
107
102
|
/** The `kubb.config.ts` `kubb init` writes before `kubb add` puts each plugin in. */
|
|
108
103
|
function generateConfigFile({ inputPath, outputPath }) {
|
|
109
104
|
return `import { defineConfig } from 'kubb/config'
|
|
@@ -118,8 +113,7 @@ export default defineConfig({
|
|
|
118
113
|
})
|
|
119
114
|
`;
|
|
120
115
|
}
|
|
121
|
-
|
|
122
|
-
//#region ../../internals/utils/src/fs.ts
|
|
116
|
+
// ../../internals/utils/src/fs.ts
|
|
123
117
|
/**
|
|
124
118
|
* Resolves to `true` when `path` is `parent` itself or nested inside it. Both sides are resolved
|
|
125
119
|
* to absolute paths first, so relative and `..`-containing inputs compare correctly.
|
|
@@ -141,8 +135,7 @@ function isPathInside(path, parent) {
|
|
|
141
135
|
const rel = relative(resolvedParent, resolvedPath);
|
|
142
136
|
return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
|
143
137
|
}
|
|
144
|
-
|
|
145
|
-
//#region src/utils.ts
|
|
138
|
+
// src/utils.ts
|
|
146
139
|
/**
|
|
147
140
|
* Renders diagnostics as a plain-text block for an AI assistant, through the same
|
|
148
141
|
* `Diagnostics.format` the CLI uses for agents, without ANSI styling. Each entry keeps the stable
|
|
@@ -152,8 +145,7 @@ function isPathInside(path, parent) {
|
|
|
152
145
|
function formatDiagnostics(diagnostics) {
|
|
153
146
|
return diagnostics.map((diagnostic) => stripVTControlCharacters(Diagnostics.format(diagnostic, { audience: "agent" }).join("\n"))).join("\n\n");
|
|
154
147
|
}
|
|
155
|
-
|
|
156
|
-
//#region src/tools/generate.ts
|
|
148
|
+
// src/tools/generate.ts
|
|
157
149
|
const generateSchema = v.object({
|
|
158
150
|
config: v.optional(v.pipe(v.string(), v.minLength(1), v.description(`Path to kubb.config file (supports ${CONFIG_EXTENSIONS.join(", ")}). If not provided, will look for kubb.config.* or .kubbrc.* in the current directory, its .config/ and configs/ folders, then each parent directory`))),
|
|
159
151
|
input: v.optional(v.pipe(v.string(), v.minLength(1), v.description("Path to OpenAPI/Swagger spec file (overrides config)"))),
|
|
@@ -240,8 +232,7 @@ const generateTool = defineTool({
|
|
|
240
232
|
return failure("Build error", [Diagnostics.from(caughtError)]);
|
|
241
233
|
}
|
|
242
234
|
});
|
|
243
|
-
|
|
244
|
-
//#region src/tools/init.ts
|
|
235
|
+
// src/tools/init.ts
|
|
245
236
|
const initSchema = v.object({
|
|
246
237
|
input: v.optional(v.pipe(v.string(), v.minLength(1), v.description("Path to OpenAPI spec (default: ./openapi.yaml)"))),
|
|
247
238
|
output: v.optional(v.pipe(v.string(), v.minLength(1), v.description("Output directory (default: ./src/gen)")))
|
|
@@ -259,8 +250,7 @@ const initTool = defineTool({
|
|
|
259
250
|
}), "utf-8");
|
|
260
251
|
return tool.text(`Created ${KUBB_CONFIG_FILENAME}\n\nInstall Kubb:\n npm install kubb\n\nAdd each plugin with its registry id, which installs it and adds it to the config:\n npx kubb add plugin-ts --yes\n\nThen run:\n npx kubb generate`);
|
|
261
252
|
});
|
|
262
|
-
|
|
263
|
-
//#region src/tools/validate.ts
|
|
253
|
+
// src/tools/validate.ts
|
|
264
254
|
const validateSchema = v.object({ input: v.pipe(v.string(), v.minLength(1), v.description("Path or URL to the OpenAPI/Swagger specification")) });
|
|
265
255
|
const validateTool = defineTool({
|
|
266
256
|
name: "validate",
|
|
@@ -276,8 +266,7 @@ const validateTool = defineTool({
|
|
|
276
266
|
return tool.error(`Validation failed:\n${formatDiagnostics([diagnostic])}\n\n\`\`\`json\n${JSON.stringify(serialized, null, 2)}\n\`\`\``);
|
|
277
267
|
}
|
|
278
268
|
});
|
|
279
|
-
|
|
280
|
-
//#region src/server.ts
|
|
269
|
+
// src/server.ts
|
|
281
270
|
/**
|
|
282
271
|
* Builds the Kubb MCP server with the generate, validate, and init tools registered.
|
|
283
272
|
*
|
|
@@ -308,7 +297,6 @@ function startServer() {
|
|
|
308
297
|
new StdioTransport(server).listen();
|
|
309
298
|
return server;
|
|
310
299
|
}
|
|
311
|
-
//#endregion
|
|
312
300
|
export { createMcpServer, startServer as run };
|
|
313
301
|
|
|
314
302
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../package.json","../../../internals/shared/src/constants.ts","../../../internals/shared/src/loader.ts","../../../internals/shared/src/config.ts","../../../internals/shared/src/init.ts","../../../internals/utils/src/fs.ts","../src/utils.ts","../src/tools/generate.ts","../src/tools/init.ts","../src/tools/validate.ts","../src/server.ts"],"sourcesContent":["","export const KUBB_CONFIG_FILENAME = 'kubb.config.ts' as const\n\n/** File extensions a Kubb config file may use. */\nexport const CONFIG_EXTENSIONS = ['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'] as const\n\nexport const KUBB_PACKAGE_NAME = 'kubb' as const\n\n/**\n * Extensions `kubb` ships at its own version, so they count as installed without being a direct\n * dependency. `constants.test.ts` checks it against the `kubb` package's dependencies.\n */\nexport const BUNDLED_PACKAGES: ReadonlyArray<string> = ['@kubb/adapter-oas', '@kubb/parser-ts', '@kubb/parser-md', '@kubb/plugin-barrel']\n\nexport const initDefaults = {\n inputPath: './openapi.yaml',\n outputPath: './src/gen',\n plugins: ['plugin-ts'],\n} as const\n","import { readFile } from 'node:fs/promises'\nimport { createJiti } from 'jiti'\n\n/**\n * jiti options for loading Kubb config modules: the automatic JSX runtime pointed at\n * `@kubb/renderer-jsx`, and `moduleCache` off so a re-load re-evaluates the file.\n */\nconst JITI_OPTIONS = {\n jsx: { runtime: 'automatic', importSource: '@kubb/renderer-jsx' },\n moduleCache: false,\n} satisfies Parameters<typeof createJiti>[1]\n\n/**\n * Plain JavaScript files. jiti hands these to Node's native `import()`, whose module cache never\n * lets go of a file, so `moduleCache: false` alone would keep returning the first version of it.\n */\nconst JAVASCRIPT_EXTENSION = /\\.[cm]?jsx?$/\n\n/**\n * Per-call options for {@link loadModule}.\n */\ntype LoadModuleOptions = {\n /**\n * Return the module's default export instead of the full namespace.\n */\n default?: boolean\n}\n\nconst jiti = createJiti(import.meta.url, JITI_OPTIONS)\n\n/**\n * Loads a Kubb TypeScript or JavaScript config module via jiti.\n *\n * jiti transpiles TypeScript and the `@kubb/renderer-jsx` JSX runtime on the fly. Every load\n * re-evaluates the file, so a config edited on disk is picked up by the next load.\n *\n * @example\n * ```ts\n * const config = await loadModule('/abs/kubb.config.ts', { default: true })\n * ```\n */\nexport async function loadModule<T = unknown>(filePath: string, options?: LoadModuleOptions): Promise<T> {\n if (!JAVASCRIPT_EXTENSION.test(filePath)) {\n return (options?.default ? jiti.import(filePath, { default: true }) : jiti.import(filePath)) as Promise<T>\n }\n\n // Transpiled through jiti instead, so every load re-evaluates the file as it is on disk now.\n // A TypeScript file it imports reloads too. A plain JavaScript file it imports still goes\n // through Node's `import()` and stays cached until the process restarts.\n const mod = (await jiti.evalModule(await readFile(filePath, 'utf8'), { filename: filePath, async: true, forceTranspile: true })) as\n | { default?: unknown }\n | undefined\n return (options?.default ? (mod?.default ?? mod) : mod) as T\n}\n","import { existsSync } from 'node:fs'\nimport { basename, dirname, join, resolve } from 'node:path'\nimport process from 'node:process'\nimport { CONFIG_EXTENSIONS } from './constants.ts'\nimport { loadModule } from './loader.ts'\n\n// A config in one of these folders belongs to the folder above it.\nconst CONFIG_FOLDERS = ['.config', 'configs']\nconst SEARCH_FILES = ['', ...CONFIG_FOLDERS.map((folder) => `${folder}/`)].flatMap((prefix) => [`${prefix}.kubbrc`, `${prefix}kubb.config`])\n\n/**\n * Every config file path the Kubb CLI checks in `dir`, in the order it checks them.\n */\nexport function configFileCandidates(dir: string): Array<string> {\n return SEARCH_FILES.flatMap((file) => CONFIG_EXTENSIONS.map((extension) => join(dir, `${file}${extension}`)))\n}\n\n/**\n * The first Kubb config file in `cwd` or the nearest parent folder that has one: `.kubbrc` before\n * `kubb.config`, the folder itself before its `.config/` and `configs/`, and {@link CONFIG_EXTENSIONS} in order.\n */\nexport function findConfigFile(cwd: string = process.cwd()): string | undefined {\n for (let dir = resolve(cwd); ; dir = dirname(dir)) {\n const found = configFileCandidates(dir).find((file) => existsSync(file))\n if (found || dirname(dir) === dir) return found\n }\n}\n\n/**\n * Loads a Kubb config module, calls it with `cli` when it exports a function, and returns its\n * configs as a list, so a single config and a `defineConfig([...])` array read the same. Each\n * `root` resolves from the folder the config belongs to: the file's folder, or the folder above\n * `.config/` and `configs/`. A missing `root` becomes that folder, so the CLI, the bundler, and\n * an editor read the same paths wherever they run.\n */\nexport async function loadConfigFile<T extends { root?: string }>({ file, cli }: { file: string; cli: unknown }): Promise<Array<T>> {\n const loaded = await loadModule<unknown>(file, { default: true })\n const resolved = (await (typeof loaded === 'function' ? loaded(cli) : loaded)) as T | Array<T>\n const dir = CONFIG_FOLDERS.includes(basename(dirname(file))) ? dirname(dirname(file)) : dirname(file)\n return (Array.isArray(resolved) ? resolved : [resolved]).map((config) => ({ ...config, root: resolve(dir, config.root ?? '.') }))\n}\n","/** The `kubb.config.ts` `kubb init` writes before `kubb add` puts each plugin in. */\nexport function generateConfigFile({ inputPath, outputPath }: { inputPath: string; outputPath: string }): string {\n return `import { defineConfig } from 'kubb/config'\n\nexport default defineConfig({\n input: '${inputPath}',\n output: {\n path: '${outputPath}',\n clean: true,\n },\n plugins: [],\n})\n`\n}\n","import { access, glob as globNode, mkdir, readFile, writeFile } from 'node:fs/promises'\n\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { runtime } from './runtime.ts'\n\nexport { existsSync } from 'node:fs'\nexport { mkdir, mkdtemp, rm } from 'node:fs/promises'\n\n/**\n * Resolves to `true` when the file or directory at `path` exists.\n * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.\n *\n * @example\n * ```ts\n * if (await exists('./kubb.config.ts')) {\n * const content = await read('./kubb.config.ts')\n * }\n * ```\n */\nexport async function exists(path: string): Promise<boolean> {\n if (runtime.isBun) {\n return Bun.file(path).exists()\n }\n return access(path).then(\n () => true,\n () => false,\n )\n}\n\n/**\n * Reads the file at `path` as a UTF-8 string.\n * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.\n *\n * @example\n * ```ts\n * const source = await read('./src/Pet.ts')\n * ```\n */\nexport async function read(path: string): Promise<string> {\n if (runtime.isBun) {\n return Bun.file(path).text()\n }\n return readFile(path, { encoding: 'utf8' })\n}\n\ntype WriteOptions = {\n /**\n * Previously read content, or `null` when the file does not exist.\n * Omitting this value reads the file before writing.\n */\n stored?: string | null\n /**\n * When `true`, re-reads the file immediately after writing and throws if the\n * content does not match — useful for catching write failures on unreliable file systems.\n */\n sanity?: boolean\n}\n\n/**\n * Whether `stored` already holds `source`, comparing on the trimmed text rather than the exact\n * bytes. Surrounding whitespace is what a formatter adds and what editors strip, and neither is a\n * reason to rewrite the file.\n *\n * Both sides are trimmed, so a storage that keeps bytes verbatim settles on the same answer as one\n * that normalizes what it stores. Trimming only `stored` would leave a source with leading\n * whitespace rewritten on every build, since the stored copy keeps the whitespace the comparison\n * has already dropped.\n */\nexport function matchesStored({ stored, source }: { stored: string; source: string }): boolean {\n return stored.trim() === source.trim()\n}\n\n/**\n * Writes `data` to `path`, trimming surrounding whitespace and ending the file with a single newline\n * the way prettier, biome, and oxfmt all do.\n * Skips the write when the trimmed content is empty, or when the file already holds that content.\n * Creates any missing parent directories automatically.\n * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.\n *\n * @example\n * ```ts\n * await write('./src/Pet.ts', source) // writes and returns the trimmed content plus a newline\n * await write('./src/Pet.ts', source) // null — file unchanged\n * await write('./src/Pet.ts', ' ') // null — empty content skipped\n * ```\n */\nexport async function write(path: string, data: string, options: WriteOptions = {}): Promise<string | null> {\n const trimmed = data.trim()\n if (trimmed === '') return null\n\n const content = `${trimmed}\\n`\n const resolved = resolve(path)\n let stored = options.stored\n\n if (stored === undefined) {\n if (runtime.isBun) {\n const file = Bun.file(resolved)\n stored = (await file.exists()) ? await file.text() : null\n } else {\n try {\n stored = await readFile(resolved, { encoding: 'utf-8' })\n } catch {\n /* file doesn't exist yet */\n stored = null\n }\n }\n }\n if (matchesStored({ stored: stored ?? '', source: trimmed })) return null\n\n await writeRaw(resolved, content)\n\n if (options.sanity) {\n const savedData = await read(resolved)\n if (savedData !== content) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n return savedData\n }\n\n return content\n}\n\n/**\n * Writes UTF-8 content verbatim, including empty files and surrounding whitespace.\n * Uses Bun.write under Bun and creates missing parent directories under either runtime.\n *\n * @example\n * await writeRaw('./cache/output.ts', ' // keep these bytes\\n\\n')\n */\nexport async function writeRaw(path: string, content: string): Promise<void> {\n const resolved = resolve(path)\n if (runtime.isBun) {\n await Bun.write(resolved, content)\n return\n }\n try {\n await writeFile(resolved, content, { encoding: 'utf-8' })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n await mkdir(dirname(resolved), { recursive: true })\n await writeFile(resolved, content, { encoding: 'utf-8' })\n }\n}\n\n/**\n * Lists non-hidden regular files below `directory` as relative POSIX paths, excluding directories and symlinks.\n * Uses Bun.Glob under Bun because its Node glob compatibility API lacks directory-entry support.\n *\n * @example\n * for await (const path of listFiles('./src')) console.log(path)\n */\nexport async function* listFiles(directory: string): AsyncGenerator<string> {\n const cwd = resolve(directory)\n if (runtime.isBun) {\n yield* new Bun.Glob('**/*').scan({ cwd, dot: false, onlyFiles: true, followSymlinks: false })\n return\n }\n for await (const entry of globNode('**/*', { cwd, withFileTypes: true })) {\n if (entry.isFile()) yield toPosixPath(relative(cwd, join(entry.parentPath, entry.name)))\n }\n}\n\n/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n\n/**\n * Resolves to `true` when `path` is `parent` itself or nested inside it. Both sides are resolved\n * to absolute paths first, so relative and `..`-containing inputs compare correctly.\n *\n * Guards a destructive or an out-of-tree operation: before wiping an output directory, check that\n * it does not contain the project root, and before loading a path a caller supplied, check that it\n * did not escape the directory it is allowed to read from.\n *\n * @example\n * isPathInside('./src/gen', '.') // true — nested inside the root\n * isPathInside('.', '.') // true — the same directory counts as inside\n * isPathInside('.', './src/gen') // false — the root is not inside its own output\n * isPathInside('../other', '.') // false — escapes the root\n */\nexport function isPathInside(path: string, parent: string): boolean {\n const resolvedPath = resolve(path)\n const resolvedParent = resolve(parent)\n if (resolvedPath === resolvedParent) {\n return true\n }\n\n const rel = relative(resolvedParent, resolvedPath)\n\n return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel)\n}\n","import { stripVTControlCharacters } from 'node:util'\nimport { type Diagnostic, Diagnostics } from '@kubb/core'\n\n/**\n * Renders diagnostics as a plain-text block for an AI assistant, through the same\n * `Diagnostics.format` the CLI uses for agents, without ANSI styling. Each entry keeps the stable\n * code, the source pointer, the cause, the fix, the underlying errors, the docs link, and the issue\n * tracker, so the agent can act on the problem rather than parsing a bare message.\n */\nexport function formatDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): string {\n return diagnostics.map((diagnostic) => stripVTControlCharacters(Diagnostics.format(diagnostic, { audience: 'agent' }).join('\\n'))).join('\\n\\n')\n}\n","import path from 'node:path'\nimport process from 'node:process'\nimport { CONFIG_EXTENSIONS, findConfigFile, loadConfigFile } from '@internals/shared'\nimport { isPathInside } from '@internals/utils'\nimport { type Config, createKubb, type Diagnostic, Diagnostics, type KubbHooks, Hookable } from '@kubb/core'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\nimport { formatDiagnostics } from '../utils.ts'\n\nconst generateSchema = v.object({\n config: v.optional(\n v.pipe(\n v.string(),\n v.minLength(1),\n v.description(\n `Path to kubb.config file (supports ${CONFIG_EXTENSIONS.join(', ')}). If not provided, will look for kubb.config.* or .kubbrc.* in the current directory, its .config/ and configs/ folders, then each parent directory`,\n ),\n ),\n ),\n input: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Path to OpenAPI/Swagger spec file (overrides config)'))),\n output: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Output directory path (overrides config)'))),\n logLevel: v.optional(v.pipe(v.picklist(['silent', 'info', 'verbose']), v.description('Log level for build output')), 'info'),\n})\n\nexport const generateTool = defineTool(\n {\n name: 'generate',\n description: 'Generate OpenAPI spec helpers using Kubb configuration',\n schema: generateSchema,\n },\n async function generate(schema: v.InferInput<typeof generateSchema>) {\n const { config: configPath, input, output, logLevel } = schema\n const messages: Array<string> = []\n\n /**\n * The failure response: the diagnostics as text and JSON, then the messages collected so far,\n * such as warnings, so the agent sees everything the run said.\n */\n const failure = (title: string, diagnostics: ReadonlyArray<Diagnostic>) => {\n const serialized = diagnostics.map((diagnostic) => Diagnostics.serialize(diagnostic))\n const log = messages.length ? `\\n\\nMessages:\\n${messages.join('\\n')}` : ''\n return tool.error(`${title}:\\n${formatDiagnostics(diagnostics)}\\n\\n\\`\\`\\`json\\n${JSON.stringify(serialized, null, 2)}\\n\\`\\`\\`${log}`)\n }\n\n try {\n const hooks = new Hookable<KubbHooks>()\n\n const notify = (type: string, message: string, data?: Record<string, unknown>) => {\n messages.push(data ? `${type}: ${message} ${JSON.stringify(data)}` : `${type}: ${message}`)\n }\n\n hooks.hook('kubb:error', ({ error }) => notify('ERROR', error.message))\n hooks.hook('kubb:warn', ({ message }) => notify('WARN', message))\n hooks.hook('kubb:diagnostic', ({ diagnostic }) => notify('DIAGNOSTIC', diagnostic.message, Diagnostics.serialize(diagnostic)))\n\n // The AI client supplies the path, so it must carry a config extension and stay inside the working directory.\n const base = path.resolve(process.cwd())\n let file: string | undefined\n if (configPath) {\n const ext = path.extname(configPath)\n if (!CONFIG_EXTENSIONS.some((extension) => extension === ext)) {\n return tool.error(`Invalid config file extension \"${ext}\". Allowed: ${CONFIG_EXTENSIONS.join(', ')}`)\n }\n file = path.resolve(base, configPath)\n if (!isPathInside(file, base)) {\n return tool.error('Invalid config file path: must be within the current working directory')\n }\n } else {\n file = findConfigFile(base)\n if (!file) {\n return tool.error(\n `No config file found. Please provide a config path or create one of: ${CONFIG_EXTENSIONS.map((extension) => `kubb.config${extension}`).join(', ')}`,\n )\n }\n }\n\n let userConfig: Config\n try {\n const [first] = await loadConfigFile<Config>({ file, cli: { logLevel, config: configPath } })\n if (!first)\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The config file exports an empty array of configurations',\n })\n userConfig = first\n } catch (error) {\n return failure(`Failed to load config ${file}`, [Diagnostics.from(error)])\n }\n\n const config: Config = {\n ...userConfig,\n input: input ?? userConfig.input,\n output: output\n ? {\n ...userConfig.output,\n path: output,\n }\n : userConfig.output,\n }\n\n notify('CONFIG_READY', 'Configuration ready')\n\n const kubb = createKubb(config, { hooks })\n const result = await kubb.generate()\n notify('BUILD_END', `Build complete - Generated ${result.files.length} files`)\n\n const problems = result.diagnostics.filter(Diagnostics.isProblem)\n const errors = problems.filter((diagnostic) => diagnostic.severity === 'error')\n if (errors.length > 0) {\n notify('BUILD_FAILED', `Build failed with ${errors.length} diagnostic(s)`)\n\n return failure('Build failed', problems)\n }\n\n notify('BUILD_SUCCESS', `Build completed successfully - Generated ${result.files.length} files`)\n\n return tool.text(`Build completed successfully!\\n\\nGenerated ${result.files.length} files\\n\\n${messages.join('\\n')}`)\n } catch (caughtError) {\n return failure('Build error', [Diagnostics.from(caughtError)])\n }\n },\n)\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { generateConfigFile, KUBB_CONFIG_FILENAME } from '@internals/shared'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\n\nconst initSchema = v.object({\n input: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Path to OpenAPI spec (default: ./openapi.yaml)'))),\n output: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Output directory (default: ./src/gen)'))),\n})\n\nexport const initTool = defineTool(\n {\n name: 'init',\n description:\n 'Scaffold a kubb.config.ts in the current directory (non-interactive). Does not install packages or add plugins: run `kubb add <id> --yes` for each plugin afterwards.',\n schema: initSchema,\n },\n async ({ input = './openapi.yaml', output = './src/gen' }) => {\n const dest = path.join(process.cwd(), KUBB_CONFIG_FILENAME)\n if (fs.existsSync(dest)) {\n return tool.error(`${KUBB_CONFIG_FILENAME} already exists at ${dest}. Delete it first before running init again.`)\n }\n fs.writeFileSync(dest, generateConfigFile({ inputPath: input, outputPath: output }), 'utf-8')\n return tool.text(\n `Created ${KUBB_CONFIG_FILENAME}\\n\\nInstall Kubb:\\n npm install kubb\\n\\nAdd each plugin with its registry id, which installs it and adds it to the config:\\n npx kubb add plugin-ts --yes\\n\\nThen run:\\n npx kubb generate`,\n )\n },\n)\n","import { adapterOas } from '@kubb/adapter-oas'\nimport { Diagnostics } from '@kubb/core'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\nimport { formatDiagnostics } from '../utils.ts'\n\nconst validateSchema = v.object({\n input: v.pipe(v.string(), v.minLength(1), v.description('Path or URL to the OpenAPI/Swagger specification')),\n})\n\nexport const validateTool = defineTool(\n {\n name: 'validate',\n description: 'Validate an OpenAPI/Swagger specification file or URL',\n schema: validateSchema,\n },\n async ({ input }) => {\n try {\n await adapterOas().validate(input, { throwOnError: true })\n return tool.text(`Validation successful: ${input}`)\n } catch (err) {\n const diagnostic = Diagnostics.from(err)\n const serialized = Diagnostics.serialize(diagnostic)\n return tool.error(`Validation failed:\\n${formatDiagnostics([diagnostic])}\\n\\n\\`\\`\\`json\\n${JSON.stringify(serialized, null, 2)}\\n\\`\\`\\``)\n }\n },\n)\n","import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot'\nimport { StdioTransport } from '@tmcp/transport-stdio'\nimport { McpServer } from 'tmcp'\nimport { version } from '../package.json'\nimport { generateTool } from './tools/generate.ts'\nimport { initTool } from './tools/init.ts'\nimport { validateTool } from './tools/validate.ts'\n\n/**\n * Builds the Kubb MCP server with the generate, validate, and init tools registered.\n *\n * @example\n * `const server = createMcpServer()`\n */\nexport function createMcpServer() {\n const server = new McpServer({ name: 'Kubb', version }, { adapter: new ValibotJsonSchemaAdapter(), capabilities: { tools: {} } })\n server.tools([generateTool, validateTool, initTool])\n return server\n}\n\n/**\n * Starts the Kubb MCP server over stdio, the transport every local MCP client\n * (Claude, Copilot, editors) uses when it launches the server as a subprocess.\n */\nexport function startServer() {\n const server = createMcpServer()\n new StdioTransport(server).listen()\n return server\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../package.json","../../../internals/shared/src/constants.ts","../../../internals/shared/src/loader.ts","../../../internals/shared/src/config.ts","../../../internals/shared/src/init.ts","../../../internals/utils/src/fs.ts","../src/utils.ts","../src/tools/generate.ts","../src/tools/init.ts","../src/tools/validate.ts","../src/server.ts"],"sourcesContent":["","export const KUBB_CONFIG_FILENAME = 'kubb.config.ts' as const\n\n/** File extensions a Kubb config file may use. */\nexport const CONFIG_EXTENSIONS = ['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'] as const\n\nexport const KUBB_PACKAGE_NAME = 'kubb' as const\n\n/**\n * Extensions `kubb` ships at its own version, so they count as installed without being a direct\n * dependency. `constants.test.ts` checks it against the `kubb` package's dependencies.\n */\nexport const BUNDLED_PACKAGES: ReadonlyArray<string> = ['@kubb/adapter-oas', '@kubb/parser-ts', '@kubb/parser-md', '@kubb/plugin-barrel']\n\nexport const initDefaults = {\n inputPath: './openapi.yaml',\n outputPath: './src/gen',\n plugins: ['plugin-ts'],\n} as const\n","import { readFile } from 'node:fs/promises'\nimport { createJiti } from 'jiti'\n\n/**\n * jiti options for loading Kubb config modules: the automatic JSX runtime pointed at\n * `@kubb/renderer-jsx`, and `moduleCache` off so a re-load re-evaluates the file.\n */\nconst JITI_OPTIONS = {\n jsx: { runtime: 'automatic', importSource: '@kubb/renderer-jsx' },\n moduleCache: false,\n} satisfies Parameters<typeof createJiti>[1]\n\n/**\n * Plain JavaScript files. jiti hands these to Node's native `import()`, whose module cache never\n * lets go of a file, so `moduleCache: false` alone would keep returning the first version of it.\n */\nconst JAVASCRIPT_EXTENSION = /\\.[cm]?jsx?$/\n\n/**\n * Per-call options for {@link loadModule}.\n */\ntype LoadModuleOptions = {\n /**\n * Return the module's default export instead of the full namespace.\n */\n default?: boolean\n}\n\nconst jiti = createJiti(import.meta.url, JITI_OPTIONS)\n\n/**\n * Loads a Kubb TypeScript or JavaScript config module via jiti.\n *\n * jiti transpiles TypeScript and the `@kubb/renderer-jsx` JSX runtime on the fly. Every load\n * re-evaluates the file, so a config edited on disk is picked up by the next load.\n *\n * @example\n * ```ts\n * const config = await loadModule('/abs/kubb.config.ts', { default: true })\n * ```\n */\nexport async function loadModule<T = unknown>(filePath: string, options?: LoadModuleOptions): Promise<T> {\n if (!JAVASCRIPT_EXTENSION.test(filePath)) {\n return (options?.default ? jiti.import(filePath, { default: true }) : jiti.import(filePath)) as Promise<T>\n }\n\n // Transpiled through jiti instead, so every load re-evaluates the file as it is on disk now.\n // A TypeScript file it imports reloads too. A plain JavaScript file it imports still goes\n // through Node's `import()` and stays cached until the process restarts.\n const mod = (await jiti.evalModule(await readFile(filePath, 'utf8'), { filename: filePath, async: true, forceTranspile: true })) as\n | { default?: unknown }\n | undefined\n return (options?.default ? (mod?.default ?? mod) : mod) as T\n}\n","import { existsSync } from 'node:fs'\nimport { basename, dirname, join, resolve } from 'node:path'\nimport process from 'node:process'\nimport { CONFIG_EXTENSIONS } from './constants.ts'\nimport { loadModule } from './loader.ts'\n\n// A config in one of these folders belongs to the folder above it.\nconst CONFIG_FOLDERS = ['.config', 'configs']\nconst SEARCH_FILES = ['', ...CONFIG_FOLDERS.map((folder) => `${folder}/`)].flatMap((prefix) => [`${prefix}.kubbrc`, `${prefix}kubb.config`])\n\n/**\n * Every config file path the Kubb CLI checks in `dir`, in the order it checks them.\n */\nexport function configFileCandidates(dir: string): Array<string> {\n return SEARCH_FILES.flatMap((file) => CONFIG_EXTENSIONS.map((extension) => join(dir, `${file}${extension}`)))\n}\n\n/**\n * The first Kubb config file in `cwd` or the nearest parent folder that has one: `.kubbrc` before\n * `kubb.config`, the folder itself before its `.config/` and `configs/`, and {@link CONFIG_EXTENSIONS} in order.\n */\nexport function findConfigFile(cwd: string = process.cwd()): string | undefined {\n for (let dir = resolve(cwd); ; dir = dirname(dir)) {\n const found = configFileCandidates(dir).find((file) => existsSync(file))\n if (found || dirname(dir) === dir) return found\n }\n}\n\n/**\n * Loads a Kubb config module, calls it with `cli` when it exports a function, and returns its\n * configs as a list, so a single config and a `defineConfig([...])` array read the same. Each\n * `root` resolves from the folder the config belongs to: the file's folder, or the folder above\n * `.config/` and `configs/`. A missing `root` becomes that folder, so the CLI, the bundler, and\n * an editor read the same paths wherever they run.\n */\nexport async function loadConfigFile<T extends { root?: string }>({ file, cli }: { file: string; cli: unknown }): Promise<Array<T>> {\n const loaded = await loadModule<unknown>(file, { default: true })\n const resolved = (await (typeof loaded === 'function' ? loaded(cli) : loaded)) as T | Array<T>\n const dir = CONFIG_FOLDERS.includes(basename(dirname(file))) ? dirname(dirname(file)) : dirname(file)\n return (Array.isArray(resolved) ? resolved : [resolved]).map((config) => ({ ...config, root: resolve(dir, config.root ?? '.') }))\n}\n","/** The `kubb.config.ts` `kubb init` writes before `kubb add` puts each plugin in. */\nexport function generateConfigFile({ inputPath, outputPath }: { inputPath: string; outputPath: string }): string {\n return `import { defineConfig } from 'kubb/config'\n\nexport default defineConfig({\n input: '${inputPath}',\n output: {\n path: '${outputPath}',\n clean: true,\n },\n plugins: [],\n})\n`\n}\n","import { access, glob as globNode, mkdir, readFile, writeFile } from 'node:fs/promises'\n\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { runtime } from './runtime.ts'\n\nexport { existsSync } from 'node:fs'\nexport { mkdir, mkdtemp, rm } from 'node:fs/promises'\n\n/**\n * Resolves to `true` when the file or directory at `path` exists.\n * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.\n *\n * @example\n * ```ts\n * if (await exists('./kubb.config.ts')) {\n * const content = await read('./kubb.config.ts')\n * }\n * ```\n */\nexport async function exists(path: string): Promise<boolean> {\n if (runtime.isBun) {\n return Bun.file(path).exists()\n }\n return access(path).then(\n () => true,\n () => false,\n )\n}\n\n/**\n * Reads the file at `path` as a UTF-8 string.\n * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.\n *\n * @example\n * ```ts\n * const source = await read('./src/Pet.ts')\n * ```\n */\nexport async function read(path: string): Promise<string> {\n if (runtime.isBun) {\n return Bun.file(path).text()\n }\n return readFile(path, { encoding: 'utf8' })\n}\n\ntype WriteOptions = {\n /**\n * Previously read content, or `null` when the file does not exist.\n * Omitting this value reads the file before writing.\n */\n stored?: string | null\n /**\n * When `true`, re-reads the file immediately after writing and throws if the\n * content does not match — useful for catching write failures on unreliable file systems.\n */\n sanity?: boolean\n}\n\n/**\n * Whether `stored` already holds `source`, comparing on the trimmed text rather than the exact\n * bytes. Surrounding whitespace is what a formatter adds and what editors strip, and neither is a\n * reason to rewrite the file.\n *\n * Both sides are trimmed, so a storage that keeps bytes verbatim settles on the same answer as one\n * that normalizes what it stores. Trimming only `stored` would leave a source with leading\n * whitespace rewritten on every build, since the stored copy keeps the whitespace the comparison\n * has already dropped.\n */\nexport function matchesStored({ stored, source }: { stored: string; source: string }): boolean {\n return stored.trim() === source.trim()\n}\n\n/**\n * Writes `data` to `path`, trimming surrounding whitespace and ending the file with a single newline\n * the way prettier, biome, and oxfmt all do.\n * Skips the write when the trimmed content is empty, or when the file already holds that content.\n * Creates any missing parent directories automatically.\n * When `sanity` is `true`, re-reads the file after writing and throws if the content does not match.\n *\n * @example\n * ```ts\n * await write('./src/Pet.ts', source) // writes and returns the trimmed content plus a newline\n * await write('./src/Pet.ts', source) // null — file unchanged\n * await write('./src/Pet.ts', ' ') // null — empty content skipped\n * ```\n */\nexport async function write(path: string, data: string, options: WriteOptions = {}): Promise<string | null> {\n const trimmed = data.trim()\n if (trimmed === '') return null\n\n const content = `${trimmed}\\n`\n const resolved = resolve(path)\n let stored = options.stored\n\n if (stored === undefined) {\n if (runtime.isBun) {\n const file = Bun.file(resolved)\n stored = (await file.exists()) ? await file.text() : null\n } else {\n try {\n stored = await readFile(resolved, { encoding: 'utf-8' })\n } catch {\n /* file doesn't exist yet */\n stored = null\n }\n }\n }\n if (matchesStored({ stored: stored ?? '', source: trimmed })) return null\n\n await writeRaw(resolved, content)\n\n if (options.sanity) {\n const savedData = await read(resolved)\n if (savedData !== content) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n return savedData\n }\n\n return content\n}\n\n/**\n * Writes UTF-8 content verbatim, including empty files and surrounding whitespace.\n * Uses Bun.write under Bun and creates missing parent directories under either runtime.\n *\n * @example\n * await writeRaw('./cache/output.ts', ' // keep these bytes\\n\\n')\n */\nexport async function writeRaw(path: string, content: string): Promise<void> {\n const resolved = resolve(path)\n if (runtime.isBun) {\n await Bun.write(resolved, content)\n return\n }\n try {\n await writeFile(resolved, content, { encoding: 'utf-8' })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n await mkdir(dirname(resolved), { recursive: true })\n await writeFile(resolved, content, { encoding: 'utf-8' })\n }\n}\n\n/**\n * Lists non-hidden regular files below `directory` as relative POSIX paths, excluding directories and symlinks.\n * Uses Bun.Glob under Bun because its Node glob compatibility API lacks directory-entry support.\n *\n * @example\n * for await (const path of listFiles('./src')) console.log(path)\n */\nexport async function* listFiles(directory: string): AsyncGenerator<string> {\n const cwd = resolve(directory)\n if (runtime.isBun) {\n yield* new Bun.Glob('**/*').scan({ cwd, dot: false, onlyFiles: true, followSymlinks: false })\n return\n }\n for await (const entry of globNode('**/*', { cwd, withFileTypes: true })) {\n if (entry.isFile()) yield toPosixPath(relative(cwd, join(entry.parentPath, entry.name)))\n }\n}\n\n/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n\n/**\n * Strips the file extension from a path or file name.\n * Only removes the last `.ext` segment when the dot is not part of a directory name.\n *\n * @example\n * trimExtName('petStore.ts') // 'petStore'\n * trimExtName('/src/models/pet.ts') // '/src/models/pet'\n * trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'\n * trimExtName('noExtension') // 'noExtension'\n */\nexport function trimExtName(text: string): string {\n const dotIndex = text.lastIndexOf('.')\n if (dotIndex > 0 && !text.includes('/', dotIndex)) {\n return text.slice(0, dotIndex)\n }\n return text\n}\n\n/**\n * Resolves to `true` when `path` is `parent` itself or nested inside it. Both sides are resolved\n * to absolute paths first, so relative and `..`-containing inputs compare correctly.\n *\n * Guards a destructive or an out-of-tree operation: before wiping an output directory, check that\n * it does not contain the project root, and before loading a path a caller supplied, check that it\n * did not escape the directory it is allowed to read from.\n *\n * @example\n * isPathInside('./src/gen', '.') // true — nested inside the root\n * isPathInside('.', '.') // true — the same directory counts as inside\n * isPathInside('.', './src/gen') // false — the root is not inside its own output\n * isPathInside('../other', '.') // false — escapes the root\n */\nexport function isPathInside(path: string, parent: string): boolean {\n const resolvedPath = resolve(path)\n const resolvedParent = resolve(parent)\n if (resolvedPath === resolvedParent) {\n return true\n }\n\n const rel = relative(resolvedParent, resolvedPath)\n\n return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel)\n}\n","import { stripVTControlCharacters } from 'node:util'\nimport { type Diagnostic, Diagnostics } from '@kubb/core'\n\n/**\n * Renders diagnostics as a plain-text block for an AI assistant, through the same\n * `Diagnostics.format` the CLI uses for agents, without ANSI styling. Each entry keeps the stable\n * code, the source pointer, the cause, the fix, the underlying errors, the docs link, and the issue\n * tracker, so the agent can act on the problem rather than parsing a bare message.\n */\nexport function formatDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): string {\n return diagnostics.map((diagnostic) => stripVTControlCharacters(Diagnostics.format(diagnostic, { audience: 'agent' }).join('\\n'))).join('\\n\\n')\n}\n","import path from 'node:path'\nimport process from 'node:process'\nimport { CONFIG_EXTENSIONS, findConfigFile, loadConfigFile } from '@internals/shared'\nimport { isPathInside } from '@internals/utils'\nimport { type Config, createKubb, type Diagnostic, Diagnostics, type KubbHooks, Hookable } from '@kubb/core'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\nimport { formatDiagnostics } from '../utils.ts'\n\nconst generateSchema = v.object({\n config: v.optional(\n v.pipe(\n v.string(),\n v.minLength(1),\n v.description(\n `Path to kubb.config file (supports ${CONFIG_EXTENSIONS.join(', ')}). If not provided, will look for kubb.config.* or .kubbrc.* in the current directory, its .config/ and configs/ folders, then each parent directory`,\n ),\n ),\n ),\n input: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Path to OpenAPI/Swagger spec file (overrides config)'))),\n output: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Output directory path (overrides config)'))),\n logLevel: v.optional(v.pipe(v.picklist(['silent', 'info', 'verbose']), v.description('Log level for build output')), 'info'),\n})\n\nexport const generateTool = defineTool(\n {\n name: 'generate',\n description: 'Generate OpenAPI spec helpers using Kubb configuration',\n schema: generateSchema,\n },\n async function generate(schema: v.InferInput<typeof generateSchema>) {\n const { config: configPath, input, output, logLevel } = schema\n const messages: Array<string> = []\n\n /**\n * The failure response: the diagnostics as text and JSON, then the messages collected so far,\n * such as warnings, so the agent sees everything the run said.\n */\n const failure = (title: string, diagnostics: ReadonlyArray<Diagnostic>) => {\n const serialized = diagnostics.map((diagnostic) => Diagnostics.serialize(diagnostic))\n const log = messages.length ? `\\n\\nMessages:\\n${messages.join('\\n')}` : ''\n return tool.error(`${title}:\\n${formatDiagnostics(diagnostics)}\\n\\n\\`\\`\\`json\\n${JSON.stringify(serialized, null, 2)}\\n\\`\\`\\`${log}`)\n }\n\n try {\n const hooks = new Hookable<KubbHooks>()\n\n const notify = (type: string, message: string, data?: Record<string, unknown>) => {\n messages.push(data ? `${type}: ${message} ${JSON.stringify(data)}` : `${type}: ${message}`)\n }\n\n hooks.hook('kubb:error', ({ error }) => notify('ERROR', error.message))\n hooks.hook('kubb:warn', ({ message }) => notify('WARN', message))\n hooks.hook('kubb:diagnostic', ({ diagnostic }) => notify('DIAGNOSTIC', diagnostic.message, Diagnostics.serialize(diagnostic)))\n\n // The AI client supplies the path, so it must carry a config extension and stay inside the working directory.\n const base = path.resolve(process.cwd())\n let file: string | undefined\n if (configPath) {\n const ext = path.extname(configPath)\n if (!CONFIG_EXTENSIONS.some((extension) => extension === ext)) {\n return tool.error(`Invalid config file extension \"${ext}\". Allowed: ${CONFIG_EXTENSIONS.join(', ')}`)\n }\n file = path.resolve(base, configPath)\n if (!isPathInside(file, base)) {\n return tool.error('Invalid config file path: must be within the current working directory')\n }\n } else {\n file = findConfigFile(base)\n if (!file) {\n return tool.error(\n `No config file found. Please provide a config path or create one of: ${CONFIG_EXTENSIONS.map((extension) => `kubb.config${extension}`).join(', ')}`,\n )\n }\n }\n\n let userConfig: Config\n try {\n const [first] = await loadConfigFile<Config>({ file, cli: { logLevel, config: configPath } })\n if (!first)\n throw new Diagnostics.Error({\n code: Diagnostics.code.unknown,\n severity: 'error',\n message: 'The config file exports an empty array of configurations',\n })\n userConfig = first\n } catch (error) {\n return failure(`Failed to load config ${file}`, [Diagnostics.from(error)])\n }\n\n const config: Config = {\n ...userConfig,\n input: input ?? userConfig.input,\n output: output\n ? {\n ...userConfig.output,\n path: output,\n }\n : userConfig.output,\n }\n\n notify('CONFIG_READY', 'Configuration ready')\n\n const kubb = createKubb(config, { hooks })\n const result = await kubb.generate()\n notify('BUILD_END', `Build complete - Generated ${result.files.length} files`)\n\n const problems = result.diagnostics.filter(Diagnostics.isProblem)\n const errors = problems.filter((diagnostic) => diagnostic.severity === 'error')\n if (errors.length > 0) {\n notify('BUILD_FAILED', `Build failed with ${errors.length} diagnostic(s)`)\n\n return failure('Build failed', problems)\n }\n\n notify('BUILD_SUCCESS', `Build completed successfully - Generated ${result.files.length} files`)\n\n return tool.text(`Build completed successfully!\\n\\nGenerated ${result.files.length} files\\n\\n${messages.join('\\n')}`)\n } catch (caughtError) {\n return failure('Build error', [Diagnostics.from(caughtError)])\n }\n },\n)\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { generateConfigFile, KUBB_CONFIG_FILENAME } from '@internals/shared'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\n\nconst initSchema = v.object({\n input: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Path to OpenAPI spec (default: ./openapi.yaml)'))),\n output: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Output directory (default: ./src/gen)'))),\n})\n\nexport const initTool = defineTool(\n {\n name: 'init',\n description:\n 'Scaffold a kubb.config.ts in the current directory (non-interactive). Does not install packages or add plugins: run `kubb add <id> --yes` for each plugin afterwards.',\n schema: initSchema,\n },\n async ({ input = './openapi.yaml', output = './src/gen' }) => {\n const dest = path.join(process.cwd(), KUBB_CONFIG_FILENAME)\n if (fs.existsSync(dest)) {\n return tool.error(`${KUBB_CONFIG_FILENAME} already exists at ${dest}. Delete it first before running init again.`)\n }\n fs.writeFileSync(dest, generateConfigFile({ inputPath: input, outputPath: output }), 'utf-8')\n return tool.text(\n `Created ${KUBB_CONFIG_FILENAME}\\n\\nInstall Kubb:\\n npm install kubb\\n\\nAdd each plugin with its registry id, which installs it and adds it to the config:\\n npx kubb add plugin-ts --yes\\n\\nThen run:\\n npx kubb generate`,\n )\n },\n)\n","import { adapterOas } from '@kubb/adapter-oas'\nimport { Diagnostics } from '@kubb/core'\nimport { defineTool } from 'tmcp/tool'\nimport { tool } from 'tmcp/utils'\nimport * as v from 'valibot'\nimport { formatDiagnostics } from '../utils.ts'\n\nconst validateSchema = v.object({\n input: v.pipe(v.string(), v.minLength(1), v.description('Path or URL to the OpenAPI/Swagger specification')),\n})\n\nexport const validateTool = defineTool(\n {\n name: 'validate',\n description: 'Validate an OpenAPI/Swagger specification file or URL',\n schema: validateSchema,\n },\n async ({ input }) => {\n try {\n await adapterOas().validate(input, { throwOnError: true })\n return tool.text(`Validation successful: ${input}`)\n } catch (err) {\n const diagnostic = Diagnostics.from(err)\n const serialized = Diagnostics.serialize(diagnostic)\n return tool.error(`Validation failed:\\n${formatDiagnostics([diagnostic])}\\n\\n\\`\\`\\`json\\n${JSON.stringify(serialized, null, 2)}\\n\\`\\`\\``)\n }\n },\n)\n","import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot'\nimport { StdioTransport } from '@tmcp/transport-stdio'\nimport { McpServer } from 'tmcp'\nimport { version } from '../package.json'\nimport { generateTool } from './tools/generate.ts'\nimport { initTool } from './tools/init.ts'\nimport { validateTool } from './tools/validate.ts'\n\n/**\n * Builds the Kubb MCP server with the generate, validate, and init tools registered.\n *\n * @example\n * `const server = createMcpServer()`\n */\nexport function createMcpServer() {\n const server = new McpServer({ name: 'Kubb', version }, { adapter: new ValibotJsonSchemaAdapter(), capabilities: { tools: {} } })\n server.tools([generateTool, validateTool, initTool])\n return server\n}\n\n/**\n * Starts the Kubb MCP server over stdio, the transport every local MCP client\n * (Claude, Copilot, editors) uses when it launches the server as a subprocess.\n */\nexport function startServer() {\n const server = createMcpServer()\n new StdioTransport(server).listen()\n return server\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/mcp",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.15.0",
|
|
4
4
|
"description": "MCP server for Kubb. Exposes code generation as a tool over the Model Context Protocol so AI assistants like Claude, Cursor, and other MCP-compatible clients can generate TypeScript types, clients, and more.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"registry": "https://registry.npmjs.org/"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@kubb/adapter-oas": "5.
|
|
71
|
-
"@kubb/core": "5.
|
|
70
|
+
"@kubb/adapter-oas": "5.15.0",
|
|
71
|
+
"@kubb/core": "5.15.0",
|
|
72
72
|
"@tmcp/adapter-valibot": "^0.1.6",
|
|
73
73
|
"@tmcp/transport-stdio": "^0.5.0",
|
|
74
74
|
"jiti": "^2.7.0",
|
|
@@ -78,10 +78,10 @@
|
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@internals/shared": "0.0.1",
|
|
80
80
|
"@internals/utils": "0.0.1",
|
|
81
|
-
"@kubb/renderer-jsx": "5.
|
|
81
|
+
"@kubb/renderer-jsx": "5.15.0"
|
|
82
82
|
},
|
|
83
83
|
"peerDependencies": {
|
|
84
|
-
"@kubb/renderer-jsx": "5.
|
|
84
|
+
"@kubb/renderer-jsx": "5.15.0"
|
|
85
85
|
},
|
|
86
86
|
"engines": {
|
|
87
87
|
"node": ">=22.22"
|