@kubb/mcp 5.0.0-beta.63 → 5.0.0-beta.64
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 +14 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -23
- package/dist/index.js +15 -38
- package/dist/index.js.map +1 -1
- package/package.json +5 -8
- package/src/constants.ts +0 -33
- package/src/index.ts +0 -12
- package/src/schemas/generateSchema.ts +0 -13
- package/src/schemas/initSchema.ts +0 -7
- package/src/schemas/validateSchema.ts +0 -5
- package/src/server.ts +0 -75
- package/src/tools/generate.ts +0 -144
- package/src/tools/init.ts +0 -41
- package/src/tools/validate.ts +0 -28
- package/src/utils.ts +0 -152
- /package/dist/{chunk-C0LytTxp.js → rolldown-runtime-C0LytTxp.js} +0 -0
package/src/tools/init.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import process from 'node:process'
|
|
4
|
-
import { availablePlugins, generateConfigFile, KUBB_CONFIG_FILENAME, type PluginOption } from '@internals/shared'
|
|
5
|
-
import { defineTool } from 'tmcp/tool'
|
|
6
|
-
import { tool } from 'tmcp/utils'
|
|
7
|
-
import { initSchema } from '../schemas/initSchema.ts'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Resolves a comma-separated plugin flag into the matching known plugin options.
|
|
11
|
-
* Unrecognized names are dropped, and a missing flag yields an empty list.
|
|
12
|
-
*/
|
|
13
|
-
export function resolvePlugins(pluginsFlag: string | undefined): Array<PluginOption> {
|
|
14
|
-
if (!pluginsFlag) {
|
|
15
|
-
return []
|
|
16
|
-
}
|
|
17
|
-
const requested = pluginsFlag
|
|
18
|
-
.split(',')
|
|
19
|
-
.map((v) => v.trim())
|
|
20
|
-
.filter(Boolean)
|
|
21
|
-
return availablePlugins.filter((p) => requested.includes(p.value))
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const initTool = defineTool(
|
|
25
|
-
{
|
|
26
|
-
name: 'init',
|
|
27
|
-
description: 'Scaffold a kubb.config.ts in the current directory (non-interactive). Does not install packages.',
|
|
28
|
-
schema: initSchema,
|
|
29
|
-
},
|
|
30
|
-
async ({ input = './openapi.yaml', output = './src/gen', plugins }) => {
|
|
31
|
-
const selected = resolvePlugins(plugins)
|
|
32
|
-
const content = generateConfigFile({ selectedPlugins: selected, inputPath: input, outputPath: output })
|
|
33
|
-
const dest = path.join(process.cwd(), KUBB_CONFIG_FILENAME)
|
|
34
|
-
if (fs.existsSync(dest)) {
|
|
35
|
-
return tool.error(`${KUBB_CONFIG_FILENAME} already exists at ${dest}. Delete it first before running init again.`)
|
|
36
|
-
}
|
|
37
|
-
fs.writeFileSync(dest, content, 'utf-8')
|
|
38
|
-
const packageList = ['kubb', ...selected.map((p) => p.packageName)].join(' ')
|
|
39
|
-
return tool.text(`Created kubb.config.ts\n\nInstall packages:\n npm install ${packageList}\n\nThen run:\n npx kubb generate`)
|
|
40
|
-
},
|
|
41
|
-
)
|
package/src/tools/validate.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Diagnostics } from '@kubb/core'
|
|
2
|
-
import { defineTool } from 'tmcp/tool'
|
|
3
|
-
import { tool } from 'tmcp/utils'
|
|
4
|
-
import { validateSchema } from '../schemas/validateSchema.ts'
|
|
5
|
-
import { formatDiagnostics } from '../utils.ts'
|
|
6
|
-
|
|
7
|
-
export const validateTool = defineTool(
|
|
8
|
-
{
|
|
9
|
-
name: 'validate',
|
|
10
|
-
description: 'Validate an OpenAPI/Swagger specification file or URL',
|
|
11
|
-
schema: validateSchema,
|
|
12
|
-
},
|
|
13
|
-
async ({ input }) => {
|
|
14
|
-
let mod: typeof import('@kubb/adapter-oas')
|
|
15
|
-
try {
|
|
16
|
-
mod = await import('@kubb/adapter-oas')
|
|
17
|
-
} catch {
|
|
18
|
-
return tool.error('The validate tool requires @kubb/adapter-oas.\nInstall: npm install @kubb/adapter-oas')
|
|
19
|
-
}
|
|
20
|
-
try {
|
|
21
|
-
await mod.adapterOas().validate(input, { throwOnError: true })
|
|
22
|
-
return tool.text(`Validation successful: ${input}`)
|
|
23
|
-
} catch (err) {
|
|
24
|
-
const serialized = Diagnostics.serialize(Diagnostics.from(err))
|
|
25
|
-
return tool.error(`Validation failed:\n${formatDiagnostics([serialized])}\n\n\`\`\`json\n${JSON.stringify(serialized, null, 2)}\n\`\`\``)
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
)
|
package/src/utils.ts
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import { createModuleLoader } from '@internals/shared'
|
|
4
|
-
import { isPromise } from '@internals/utils'
|
|
5
|
-
import type { CLIOptions, Config, PossibleConfig, SerializedDiagnostic } from '@kubb/core'
|
|
6
|
-
import { ALLOWED_CONFIG_EXTENSIONS, NotifyTypes } from './constants.ts'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Renders serialized diagnostics as a plain-text block for an AI assistant. Each entry
|
|
10
|
-
* keeps the stable `code`, the source pointer, the suggested fix, and the docs link, so
|
|
11
|
-
* the agent can act on the problem rather than parsing a bare message. No ANSI styling,
|
|
12
|
-
* unlike the CLI renderer.
|
|
13
|
-
*/
|
|
14
|
-
export function formatDiagnostics(diagnostics: ReadonlyArray<SerializedDiagnostic>): string {
|
|
15
|
-
return diagnostics.map((diagnostic) => formatDiagnostic(diagnostic)).join('\n\n')
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function formatDiagnostic(diagnostic: SerializedDiagnostic): string {
|
|
19
|
-
const { code, severity, message, location, help, plugin, docsUrl } = diagnostic
|
|
20
|
-
const rule = plugin ? `${plugin}(${code})` : code
|
|
21
|
-
const lines = [`${severity} ${rule}: ${message}`]
|
|
22
|
-
|
|
23
|
-
if (location && 'pointer' in location) {
|
|
24
|
-
lines.push(` at ${location.pointer}`)
|
|
25
|
-
}
|
|
26
|
-
if (help) {
|
|
27
|
-
lines.push(` help: ${help}`)
|
|
28
|
-
}
|
|
29
|
-
if (docsUrl) {
|
|
30
|
-
lines.push(` docs: ${docsUrl}`)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return lines.join('\n')
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
type NotifyFunction = (type: string, message: string, data?: Record<string, unknown>) => Promise<void>
|
|
37
|
-
|
|
38
|
-
const loader = createModuleLoader()
|
|
39
|
-
|
|
40
|
-
const loadedModules = new Map<string, unknown>()
|
|
41
|
-
|
|
42
|
-
async function loadModule(filePath: string): Promise<unknown> {
|
|
43
|
-
const ext = path.extname(filePath)
|
|
44
|
-
if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {
|
|
45
|
-
throw new Error(`Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`)
|
|
46
|
-
}
|
|
47
|
-
if (loadedModules.has(filePath)) {
|
|
48
|
-
return loadedModules.get(filePath)
|
|
49
|
-
}
|
|
50
|
-
const mod = await loader.load(filePath, { default: true })
|
|
51
|
-
loadedModules.set(filePath, mod)
|
|
52
|
-
return mod
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Loads the user's Kubb config and returns it with the directory it was found in.
|
|
57
|
-
*
|
|
58
|
-
* When `configPath` is given it must use an allowed extension and resolve inside
|
|
59
|
-
* the current working directory, otherwise loading throws. When omitted, the
|
|
60
|
-
* known `kubb.config.*` file names are tried in the current directory. Every
|
|
61
|
-
* outcome is reported through `notify` before the function returns or throws.
|
|
62
|
-
*/
|
|
63
|
-
export async function loadUserConfig(configPath: string | undefined, { notify }: { notify: NotifyFunction }): Promise<{ userConfig: Config; cwd: string }> {
|
|
64
|
-
if (configPath) {
|
|
65
|
-
const ext = path.extname(configPath)
|
|
66
|
-
if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {
|
|
67
|
-
const msg = `Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`
|
|
68
|
-
await notify(NotifyTypes.CONFIG_ERROR, msg)
|
|
69
|
-
throw new Error(msg)
|
|
70
|
-
}
|
|
71
|
-
const base = path.resolve(process.cwd())
|
|
72
|
-
const resolvedConfigPath = path.resolve(base, configPath)
|
|
73
|
-
const relative = path.relative(base, resolvedConfigPath)
|
|
74
|
-
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
75
|
-
const msg = 'Invalid config file path: must be within the current working directory'
|
|
76
|
-
await notify(NotifyTypes.CONFIG_ERROR, msg)
|
|
77
|
-
throw new Error(msg)
|
|
78
|
-
}
|
|
79
|
-
const cwd = path.dirname(resolvedConfigPath)
|
|
80
|
-
try {
|
|
81
|
-
const userConfig = (await loadModule(resolvedConfigPath)) as Config
|
|
82
|
-
await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${resolvedConfigPath}`)
|
|
83
|
-
return { userConfig, cwd }
|
|
84
|
-
} catch (error) {
|
|
85
|
-
const msg = `Failed to load config: ${error instanceof Error ? error.message : String(error)}`
|
|
86
|
-
await notify(NotifyTypes.CONFIG_ERROR, msg)
|
|
87
|
-
throw new Error(msg)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const cwd = process.cwd()
|
|
92
|
-
const configFileNames = ['kubb.config.ts', 'kubb.config.mts', 'kubb.config.cts', 'kubb.config.js', 'kubb.config.cjs']
|
|
93
|
-
|
|
94
|
-
for (const configFileName of configFileNames) {
|
|
95
|
-
const configFilePath = path.resolve(process.cwd(), configFileName)
|
|
96
|
-
if (!existsSync(configFilePath)) continue
|
|
97
|
-
try {
|
|
98
|
-
const userConfig = (await loadModule(configFilePath)) as Config
|
|
99
|
-
await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)
|
|
100
|
-
return { userConfig, cwd }
|
|
101
|
-
} catch (err) {
|
|
102
|
-
await notify(NotifyTypes.CONFIG_ERROR, `Failed to load ${configFileName}: ${err instanceof Error ? err.message : String(err)}`)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
await notify(NotifyTypes.CONFIG_ERROR, 'No config file found')
|
|
107
|
-
throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(', ')}`)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Determine the root directory based on userConfig.root and resolvedConfigDir
|
|
112
|
-
* 1. If userConfig.root exists and is absolute, use it as-is
|
|
113
|
-
* 2. If userConfig.root exists and is relative, resolve it relative to config directory
|
|
114
|
-
* 3. Otherwise, use the config directory as root
|
|
115
|
-
*/
|
|
116
|
-
export function resolveCwd(userConfig: Config, cwd: string): string {
|
|
117
|
-
if (userConfig.root) {
|
|
118
|
-
if (path.isAbsolute(userConfig.root)) {
|
|
119
|
-
return userConfig.root
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return path.resolve(cwd, userConfig.root)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return cwd
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Inputs forwarded to a config when it is defined as a function.
|
|
130
|
-
*/
|
|
131
|
-
export type ResolveUserConfigOptions = {
|
|
132
|
-
/**
|
|
133
|
-
* Path of the loaded config, passed through to the config function as `config`.
|
|
134
|
-
*/
|
|
135
|
-
configPath?: string
|
|
136
|
-
/**
|
|
137
|
-
* Log level passed through to the config function.
|
|
138
|
-
*/
|
|
139
|
-
logLevel?: string
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Normalizes a possible config into a single resolved `Config`.
|
|
144
|
-
*
|
|
145
|
-
* Calls the config when it is a function, awaits it when it is a promise, and
|
|
146
|
-
* picks the first entry when it resolves to an array.
|
|
147
|
-
*/
|
|
148
|
-
export async function resolveUserConfig(config: PossibleConfig<CLIOptions>, options: ResolveUserConfigOptions): Promise<Config> {
|
|
149
|
-
const result = typeof config === 'function' ? config({ logLevel: options.logLevel as CLIOptions['logLevel'], config: options.configPath }) : config
|
|
150
|
-
const resolved = isPromise(result) ? await result : result
|
|
151
|
-
return (Array.isArray(resolved) ? resolved[0] : resolved) as Config
|
|
152
|
-
}
|
|
File without changes
|