@jmoak/vibrissa 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/args.ts","../src/cli/format.ts","../src/cli/resolve.ts","../src/config.ts","../src/cli/call.ts","../src/cli/init.ts","../src/cli/inspect.ts","../src/cli/record.ts","../src/cli/run.ts","../src/cli/tools.ts","../src/cli.ts"],"sourcesContent":["import path from 'node:path'\nimport type { JsonValue } from '../types.js'\n\nexport function takeFlag(argv: string[], name: string): string | undefined {\n const index = argv.indexOf(name)\n if (index === -1) return undefined\n return argv[index + 1]\n}\n\nexport function hasFlag(argv: string[], name: string): boolean {\n return argv.includes(name)\n}\n\nexport function takeAllFlags(argv: string[], name: string): string[] {\n const values: string[] = []\n for (let i = 0; i < argv.length; i++) {\n if (argv[i] === name && argv[i + 1] !== undefined) {\n values.push(argv[i + 1])\n i++\n }\n }\n return values\n}\n\nexport function splitCommandLine(input: string): { cmd: string; args: string[] } {\n const tokens: string[] = []\n let current = ''\n let quote: '\"' | \"'\" | null = null\n for (let i = 0; i < input.length; i++) {\n const ch = input[i]\n if (quote) {\n if (ch === quote) quote = null\n else current += ch\n continue\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch\n continue\n }\n if (/\\s/.test(ch)) {\n if (current) {\n tokens.push(current)\n current = ''\n }\n continue\n }\n current += ch\n }\n if (current) tokens.push(current)\n if (tokens.length === 0) throw new Error('Empty --server command')\n return { cmd: tokens[0], args: tokens.slice(1) }\n}\n\nexport function parseEnvPairs(pairs: string[]): Record<string, string> {\n const env: Record<string, string> = {}\n for (const pair of pairs) {\n const eq = pair.indexOf('=')\n if (eq <= 0) throw new Error(`Invalid --env value \"${pair}\" (expected KEY=VALUE)`)\n env[pair.slice(0, eq)] = pair.slice(eq + 1)\n }\n return env\n}\n\nexport function parseArgValue(raw: string): JsonValue {\n if (raw === 'true') return true\n if (raw === 'false') return false\n if (raw === 'null') return null\n if (/^-?\\d+(\\.\\d+)?$/.test(raw)) return Number(raw)\n if (\n (raw.startsWith('{') && raw.endsWith('}')) ||\n (raw.startsWith('[') && raw.endsWith(']')) ||\n (raw.startsWith('\"') && raw.endsWith('\"'))\n ) {\n try {\n return JSON.parse(raw) as JsonValue\n } catch {\n return raw\n }\n }\n return raw\n}\n\nexport function parseToolArgs(argv: string[]): Record<string, JsonValue> {\n const json = takeFlag(argv, '--args')\n const pairs = takeAllFlags(argv, '--arg')\n let args: Record<string, JsonValue> = {}\n if (json !== undefined) {\n let parsed: unknown\n try {\n parsed = JSON.parse(json)\n } catch (err) {\n throw new Error(`Invalid --args JSON: ${err instanceof Error ? err.message : String(err)}`)\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new Error('--args must be a JSON object')\n }\n args = { ...(parsed as Record<string, JsonValue>) }\n }\n for (const pair of pairs) {\n const eq = pair.indexOf('=')\n if (eq <= 0) throw new Error(`Invalid --arg value \"${pair}\" (expected key=value)`)\n args[pair.slice(0, eq)] = parseArgValue(pair.slice(eq + 1))\n }\n return args\n}\n\nexport function resolvePathFromCwd(value: string): string {\n return path.isAbsolute(value) ? value : path.resolve(process.cwd(), value)\n}\n\nexport function printJson(value: unknown): void {\n console.log(JSON.stringify(value, null, 2))\n}\n","import type { ToolSummary } from '../mcp-session.js'\n\nconst RESET = '\\x1b[0m'\nconst BOLD = '\\x1b[1m'\nconst DIM = '\\x1b[2m'\nconst FG_CYAN = '\\x1b[36m'\nconst FG_GRAY = '\\x1b[90m'\nconst FG_GREEN = '\\x1b[32m'\nconst FG_RED = '\\x1b[31m'\nconst FG_YELLOW = '\\x1b[33m'\n\nfunction color(text: string, code: string): string {\n return `${code}${text}${RESET}`\n}\n\nexport function formatToolList(tools: ToolSummary[]): string {\n if (tools.length === 0) return 'No tools registered on this server.'\n const lines: string[] = [\n color(`${tools.length} tool${tools.length === 1 ? '' : 's'}`, BOLD + FG_CYAN),\n '',\n ]\n for (const tool of tools) {\n lines.push(`${color('▸', FG_GREEN)} ${color(tool.name, BOLD + FG_CYAN)}`)\n if (tool.description) lines.push(` ${color(tool.description, FG_GRAY)}`)\n const schema = tool.inputSchema\n if (schema && typeof schema === 'object' && !Array.isArray(schema)) {\n const props =\n typeof schema.properties === 'object' && schema.properties !== null\n ? Object.keys(schema.properties as Record<string, unknown>)\n : []\n const required = Array.isArray(schema.required)\n ? (schema.required as unknown[]).filter((v): v is string => typeof v === 'string')\n : []\n if (props.length > 0) {\n const rendered = props\n .map((name) => (required.includes(name) ? `${name}*` : name))\n .join(', ')\n lines.push(` ${color(`args: ${rendered}`, DIM)}`)\n }\n }\n lines.push('')\n }\n return lines.join('\\n').trimEnd()\n}\n\nexport function formatCallHeader(tool: string, args: unknown): string {\n return `${color('call', FG_CYAN)} ${color(tool, BOLD)} ${color(JSON.stringify(args), FG_GRAY)}`\n}\n\nexport function formatSuccessBanner(text: string): string {\n return color(text, FG_GREEN)\n}\n\nexport function formatErrorBanner(text: string): string {\n return color(text, FG_RED)\n}\n\nexport function formatWarnBanner(text: string): string {\n return color(text, FG_YELLOW)\n}\n","import path from 'node:path'\nimport { resolveOptions } from '../config.js'\nimport { resolveRootDir, resolveServerConfig } from '../paths.js'\nimport type { RunCasesOptions, ServerConfig } from '../types.js'\nimport {\n hasFlag,\n parseEnvPairs,\n resolvePathFromCwd,\n splitCommandLine,\n takeAllFlags,\n takeFlag,\n} from './args.js'\n\nexport interface CommonCliFlags {\n configPath?: string\n serverCmd?: string\n serverArgs?: string[]\n serverCwd?: string\n env?: Record<string, string>\n timeoutMs?: number\n json?: boolean\n}\n\nexport function parseCommonFlags(argv: string[]): CommonCliFlags {\n const configPath = takeFlag(argv, '--config')\n const serverRaw = takeFlag(argv, '--server')\n const serverCwd = takeFlag(argv, '--server-cwd')\n const timeoutRaw = takeFlag(argv, '--timeout')\n const env = parseEnvPairs(takeAllFlags(argv, '--env'))\n\n let serverCmd: string | undefined\n let serverArgs: string[] | undefined\n if (serverRaw !== undefined) {\n const split = splitCommandLine(serverRaw)\n serverCmd = split.cmd\n serverArgs = split.args\n }\n\n return {\n configPath,\n serverCmd,\n serverArgs,\n serverCwd,\n env: Object.keys(env).length > 0 ? env : undefined,\n timeoutMs:\n timeoutRaw !== undefined && Number.isFinite(Number(timeoutRaw))\n ? Number(timeoutRaw)\n : undefined,\n json: hasFlag(argv, '--json'),\n }\n}\n\nexport function mergeCliOptions(\n flags: CommonCliFlags,\n overrides: Partial<RunCasesOptions> = {},\n): RunCasesOptions {\n const resolved = resolveOptions(process.cwd(), flags.configPath)\n const serverCwd = flags.serverCwd\n ? path.isAbsolute(flags.serverCwd)\n ? flags.serverCwd\n : resolvePathFromCwd(flags.serverCwd)\n : undefined\n\n return {\n ...resolved,\n ...overrides,\n server: {\n ...resolved.server,\n ...(overrides.server ?? {}),\n ...(flags.serverCmd ? { cmd: flags.serverCmd } : {}),\n ...(flags.serverArgs ? { args: flags.serverArgs } : {}),\n ...(serverCwd ? { cwd: serverCwd } : {}),\n env: {\n ...(resolved.server.env ?? {}),\n ...(overrides.server?.env ?? {}),\n ...(flags.env ?? {}),\n },\n },\n ...(typeof flags.timeoutMs === 'number' ? { timeoutMs: flags.timeoutMs } : {}),\n }\n}\n\nexport function openSessionOptions(flags: CommonCliFlags): {\n options: RunCasesOptions\n server: ServerConfig\n rootDir: string\n timeoutMs: number\n} {\n const options = mergeCliOptions(flags)\n return {\n options,\n server: resolveServerConfig(options),\n rootDir: resolveRootDir(options),\n timeoutMs: options.timeoutMs,\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { defaultRunCasesOptions } from './defaults.js'\nimport type { RunCasesOptions } from './types.js'\n\nexport function stripJsonComments(input: string): string {\n let result = ''\n let inString = false\n let stringQuote: string | null = null\n let escaped = false\n let inBlockComment = false\n let inLineComment = false\n\n for (let i = 0; i < input.length; i++) {\n const char = input[i]\n const next = i + 1 < input.length ? input[i + 1] : ''\n\n if (inLineComment) {\n if (char === '\\n') {\n inLineComment = false\n result += char\n }\n continue\n }\n\n if (inBlockComment) {\n if (char === '*' && next === '/') {\n inBlockComment = false\n i++\n }\n continue\n }\n\n if (!inString && char === '/' && next === '*') {\n inBlockComment = true\n i++\n continue\n }\n if (!inString && char === '/' && next === '/') {\n inLineComment = true\n i++\n continue\n }\n\n if (inString) {\n result += char\n if (!escaped && char === stringQuote) {\n inString = false\n stringQuote = null\n }\n escaped = !escaped && char === '\\\\'\n continue\n }\n\n if (char === '\"' || char === \"'\" || char === '`') {\n inString = true\n stringQuote = char\n result += char\n escaped = false\n continue\n }\n\n result += char\n }\n\n return result\n}\n\nexport function loadConfigObjectFromPath(configPath: string): Partial<RunCasesOptions> {\n const raw = fs.readFileSync(configPath, 'utf8')\n const json = JSON.parse(stripJsonComments(raw))\n return json as Partial<RunCasesOptions>\n}\n\nexport interface LoadedConfig {\n config: Partial<RunCasesOptions>\n rootDir: string\n configPath?: string\n}\n\nexport function loadConfigFile(cwd: string, explicitPath?: string): LoadedConfig | undefined {\n if (explicitPath) {\n const abs = path.isAbsolute(explicitPath) ? explicitPath : path.join(cwd, explicitPath)\n if (!fs.existsSync(abs)) throw new Error(`Config not found: ${abs}`)\n return {\n config: loadConfigObjectFromPath(abs),\n rootDir: path.dirname(abs),\n configPath: abs,\n }\n }\n\n const candidates = ['vibrissa.json', 'vibrissa.jsonc']\n for (const name of candidates) {\n const file = path.join(cwd, name)\n if (fs.existsSync(file)) {\n return {\n config: loadConfigObjectFromPath(file),\n rootDir: path.dirname(file),\n configPath: file,\n }\n }\n }\n\n const pkgPath = path.join(cwd, 'package.json')\n if (fs.existsSync(pkgPath)) {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))\n if (pkg?.vibrissa && typeof pkg.vibrissa === 'object') {\n return {\n config: pkg.vibrissa as Partial<RunCasesOptions>,\n rootDir: path.dirname(pkgPath),\n configPath: pkgPath,\n }\n }\n }\n return undefined\n}\n\nexport function resolveOptions(cwd: string, explicitPath?: string): RunCasesOptions {\n const loaded = loadConfigFile(cwd, explicitPath)\n const fileConfig = loaded?.config\n const rootDir = loaded?.rootDir ?? path.resolve(cwd)\n const resolved: RunCasesOptions = {\n ...defaultRunCasesOptions,\n ...fileConfig,\n server: {\n ...defaultRunCasesOptions.server,\n ...(fileConfig?.server ?? {}),\n },\n rootDir,\n }\n return resolved\n}\n","import { McpSession } from '../mcp-session.js'\nimport { parseToolArgs, printJson } from './args.js'\nimport { formatCallHeader, formatErrorBanner, formatSuccessBanner } from './format.js'\nimport { openSessionOptions, parseCommonFlags } from './resolve.js'\n\nexport async function callCommand(argv: string[]): Promise<number> {\n const tool = argv[0] && !argv[0].startsWith('--') ? argv[0] : undefined\n if (!tool) {\n console.error('Usage: vib-test call <tool> [--args \\'{\"key\":\"value\"}\\'] [--arg key=value]')\n return 1\n }\n const flags = parseCommonFlags(argv.slice(1))\n const args = parseToolArgs(argv.slice(1))\n const { server, timeoutMs } = openSessionOptions(flags)\n const spawnTimeoutMs = Math.max(2000, Math.min(10000, timeoutMs))\n const session = await McpSession.start(server, spawnTimeoutMs)\n try {\n if (!flags.json) console.log(formatCallHeader(tool, args))\n const outcome = await session.callTool(tool, args, timeoutMs)\n if (outcome.kind === 'error') {\n if (flags.json) {\n printJson({ ok: false, error: outcome.error })\n } else {\n const label = outcome.error.codeName ? ` [${outcome.error.codeName}]` : ''\n console.error(\n formatErrorBanner(`error${label} (${outcome.error.kind}): ${outcome.error.message}`),\n )\n }\n return 1\n }\n if (flags.json) printJson({ ok: true, result: outcome.result })\n else {\n console.log(formatSuccessBanner('ok'))\n printJson(outcome.result)\n }\n return 0\n } finally {\n await session.close()\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { hasFlag, resolvePathFromCwd, takeFlag } from './args.js'\nimport { formatSuccessBanner, formatWarnBanner } from './format.js'\nimport { parseCommonFlags } from './resolve.js'\n\nfunction writeFile(pathName: string, contents: string, force: boolean): 'wrote' | 'skipped' {\n if (fs.existsSync(pathName) && !force) return 'skipped'\n fs.mkdirSync(path.dirname(pathName), { recursive: true })\n fs.writeFileSync(pathName, contents, 'utf8')\n return 'wrote'\n}\n\nfunction detectServerCommand(dir: string): { cmd: string; args: string[] } {\n const distCandidates = ['dist/index.js', 'build/index.js', 'src/index.js']\n for (const candidate of distCandidates) {\n if (fs.existsSync(path.join(dir, candidate))) {\n return { cmd: 'node', args: [candidate] }\n }\n }\n return { cmd: 'node', args: ['dist/index.js'] }\n}\n\nfunction schemaRef(fromFile: string, rootDir: string, schemaName: string): string {\n const local = path.join(rootDir, 'node_modules', 'vibrissa', 'schema', schemaName)\n if (fs.existsSync(local)) {\n return path.relative(path.dirname(fromFile), local).replace(/\\\\/g, '/')\n }\n return `https://unpkg.com/vibrissa/schema/${schemaName}`\n}\n\nexport async function initCommand(argv: string[]): Promise<number> {\n const flags = parseCommonFlags(argv)\n const dir = resolvePathFromCwd(takeFlag(argv, '--dir') ?? '.')\n const force = hasFlag(argv, '--force')\n const serverOverride = flags.serverCmd\n ? { cmd: flags.serverCmd, args: flags.serverArgs ?? [] }\n : detectServerCommand(dir)\n\n const configPath = path.join(dir, 'vibrissa.json')\n const casesDir = path.join(dir, 'tests', 'integration')\n const samplePath = path.join(casesDir, 'echo.basic.json')\n\n const config = {\n $schema: schemaRef(configPath, dir, 'vibrissa.schema.json'),\n server: {\n cmd: serverOverride.cmd,\n args: serverOverride.args,\n cwd: '.',\n },\n globs: ['tests/integration/**/*.json'],\n timeoutMs: 15000,\n failFast: false,\n }\n\n const sample = {\n $schema: schemaRef(samplePath, dir, 'case.schema.json'),\n name: 'echo basic',\n tool: 'echo',\n args: { text: 'hello', uppercase: true },\n expect: {\n content: [{ type: 'text', text: 'HELLO' }],\n },\n }\n\n const configStatus = writeFile(configPath, `${JSON.stringify(config, null, 2)}\\n`, force)\n fs.mkdirSync(casesDir, { recursive: true })\n const sampleStatus = writeFile(samplePath, `${JSON.stringify(sample, null, 2)}\\n`, force)\n\n const pkgPath = path.join(dir, 'package.json')\n let pkgNote = 'no package.json found (skipped script)'\n if (fs.existsSync(pkgPath)) {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) as {\n scripts?: Record<string, string>\n }\n pkg.scripts ??= {}\n if (!pkg.scripts['test:integration'] || force) {\n pkg.scripts['test:integration'] = 'vib-test run'\n fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\\n`, 'utf8')\n pkgNote = 'added scripts.test:integration'\n } else {\n pkgNote = 'scripts.test:integration already present'\n }\n }\n\n console.log(formatSuccessBanner('vibrissa init'))\n console.log(` config: ${configStatus.padEnd(7)} ${configPath}`)\n console.log(` sample: ${sampleStatus.padEnd(7)} ${samplePath}`)\n console.log(` package: ${pkgNote}`)\n console.log('')\n console.log('Next:')\n console.log(' 1. vib-test tools')\n console.log(' 2. vib-test call <tool> --arg key=value')\n console.log(' 3. vib-test record <tool> --arg key=value')\n console.log(' 4. vib-test run')\n console.log(' 5. vib-test inspect # open MCP Inspector with this server')\n if (configStatus === 'skipped' || sampleStatus === 'skipped') {\n console.log(\n formatWarnBanner('Some files already existed; re-run with --force to replace them.'),\n )\n }\n return 0\n}\n","import { spawn } from 'node:child_process'\nimport { hasFlag } from './args.js'\nimport { formatSuccessBanner, formatWarnBanner } from './format.js'\nimport { openSessionOptions, parseCommonFlags } from './resolve.js'\n\nexport async function inspectCommand(argv: string[]): Promise<number> {\n const dash = argv.indexOf('--')\n const ownArgs = dash === -1 ? argv : argv.slice(0, dash)\n const passthrough = dash === -1 ? [] : argv.slice(dash + 1)\n const flags = parseCommonFlags(ownArgs)\n const { server } = openSessionOptions(flags)\n\n const cliMode = hasFlag(ownArgs, '--cli') || passthrough[0] === '--cli'\n const rest = passthrough[0] === '--cli' ? passthrough.slice(1) : passthrough\n\n const inspectorArgs = [\n '--yes',\n '@modelcontextprotocol/inspector',\n ...(cliMode ? ['--cli'] : []),\n server.cmd,\n ...(server.args ?? []),\n ...rest,\n ]\n\n console.log(\n formatSuccessBanner(\n `Opening MCP Inspector for: ${server.cmd} ${(server.args ?? []).join(' ')}`.trim(),\n ),\n )\n console.log(\n formatWarnBanner(\n 'Inspector = visual exploration · Vibrissa tools/call/record/run = the regression loop',\n ),\n )\n\n const child = spawn('npx', inspectorArgs, {\n cwd: server.cwd ?? process.cwd(),\n env: { ...process.env, ...(server.env ?? {}) },\n stdio: 'inherit',\n shell: process.platform === 'win32',\n })\n\n return await new Promise<number>((resolve) => {\n child.on('error', (err) => {\n console.error(`Failed to launch MCP Inspector: ${err.message}`)\n resolve(1)\n })\n child.on('exit', (code, signal) => {\n if (signal) {\n resolve(1)\n return\n }\n resolve(code ?? 1)\n })\n })\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { McpSession } from '../mcp-session.js'\nimport type { JsonValue, TestCase } from '../types.js'\nimport { hasFlag, parseToolArgs, printJson, resolvePathFromCwd, takeFlag } from './args.js'\nimport {\n formatCallHeader,\n formatErrorBanner,\n formatSuccessBanner,\n formatWarnBanner,\n} from './format.js'\nimport { openSessionOptions, parseCommonFlags } from './resolve.js'\n\nfunction slugify(input: string): string {\n return input\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 48)\n}\n\nfunction defaultOutPath(rootDir: string, tool: string, name: string): string {\n const dir = path.join(rootDir, 'tests', 'integration')\n return path.join(dir, `${slugify(name) || slugify(tool) || 'case'}.json`)\n}\n\nfunction caseSchemaRef(outPath: string, rootDir: string): string {\n const localSchema = path.join(rootDir, 'node_modules', 'vibrissa', 'schema', 'case.schema.json')\n if (fs.existsSync(localSchema)) {\n return path.relative(path.dirname(outPath), localSchema).replace(/\\\\/g, '/')\n }\n return 'https://unpkg.com/vibrissa/schema/case.schema.json'\n}\n\nexport async function recordCommand(argv: string[]): Promise<number> {\n const tool = argv[0] && !argv[0].startsWith('--') ? argv[0] : undefined\n if (!tool) {\n console.error(\n 'Usage: vib-test record <tool> [--args \\'{\"key\":\"value\"}\\'] [--out path] [--name \"...\"] [--partial]',\n )\n return 1\n }\n\n const rest = argv.slice(1)\n const flags = parseCommonFlags(rest)\n const args = parseToolArgs(rest)\n const name = takeFlag(rest, '--name') ?? `${tool} recorded`\n const outFlag = takeFlag(rest, '--out')\n const partial = hasFlag(rest, '--partial')\n const force = hasFlag(rest, '--force')\n\n const { server, rootDir, timeoutMs } = openSessionOptions(flags)\n const outPath = outFlag ? resolvePathFromCwd(outFlag) : defaultOutPath(rootDir, tool, name)\n\n if (fs.existsSync(outPath) && !force) {\n console.error(formatErrorBanner(`Refusing to overwrite ${outPath} (pass --force to replace)`))\n return 1\n }\n\n const spawnTimeoutMs = Math.max(2000, Math.min(10000, timeoutMs))\n const session = await McpSession.start(server, spawnTimeoutMs)\n try {\n if (!flags.json) console.log(formatCallHeader(tool, args))\n const outcome = await session.callTool(tool, args, timeoutMs)\n\n const testCase: TestCase & { $schema?: string } = {\n $schema: caseSchemaRef(outPath, rootDir),\n name,\n tool,\n args,\n }\n\n if (outcome.kind === 'error') {\n testCase.expectError = {\n ...(outcome.error.codeName ? { code: outcome.error.codeName } : {}),\n message: { $regex: escapeRegex(outcome.error.message.slice(0, 80)) },\n }\n if (!flags.json) {\n console.log(\n formatWarnBanner(\n `Captured ${outcome.error.kind} error into expectError (${outcome.error.codeName ?? 'tool'})`,\n ),\n )\n }\n } else {\n const expect = outcome.result as JsonValue\n testCase.expect = partial\n ? ({ $partial: true, ...(expect as Record<string, JsonValue>) } as JsonValue)\n : expect\n if (!flags.json) console.log(formatSuccessBanner('Captured result into expect'))\n }\n\n fs.mkdirSync(path.dirname(outPath), { recursive: true })\n fs.writeFileSync(outPath, `${JSON.stringify(testCase, null, 2)}\\n`, 'utf8')\n\n if (flags.json) printJson({ ok: true, path: outPath, case: testCase })\n else console.log(`${formatSuccessBanner('wrote')} ${outPath}`)\n return 0\n } finally {\n await session.close()\n }\n}\n\nfunction escapeRegex(input: string): string {\n return input.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n","import path from 'node:path'\nimport { ConsoleResultsDisplay, PrettyConsoleResultsDisplay } from '../display.js'\nimport { Runner } from '../runner.js'\nimport { hasFlag, resolvePathFromCwd, takeFlag } from './args.js'\nimport { mergeCliOptions, parseCommonFlags } from './resolve.js'\n\nexport async function runCommand(argv: string[]): Promise<number> {\n const flags = parseCommonFlags(argv)\n const casesGlob = takeFlag(argv, '--cases')\n const failFast = hasFlag(argv, '--fail-fast')\n const allowEmpty = hasFlag(argv, '--allow-empty')\n let display: 'plain' | 'pretty' | undefined\n if (hasFlag(argv, '--pretty')) display = 'pretty'\n if (hasFlag(argv, '--no-pretty')) display = 'plain'\n const displayFlag = takeFlag(argv, '--display')\n if (displayFlag === 'plain' || displayFlag === 'pretty') display = displayFlag\n\n const options = mergeCliOptions(flags, {\n ...(display ? { display } : {}),\n ...(casesGlob\n ? {\n globs: [\n path.isAbsolute(casesGlob)\n ? casesGlob\n : resolvePathFromCwd(casesGlob).replace(/\\\\/g, '/'),\n ],\n }\n : {}),\n ...(failFast ? { failFast: true } : {}),\n ...(allowEmpty ? { allowEmpty: true } : {}),\n })\n\n const runner = new Runner(\n options,\n options.display === 'pretty' ? new PrettyConsoleResultsDisplay() : new ConsoleResultsDisplay(),\n )\n return runner.run()\n}\n","import { McpSession } from '../mcp-session.js'\nimport { printJson } from './args.js'\nimport { formatToolList } from './format.js'\nimport { openSessionOptions, parseCommonFlags } from './resolve.js'\n\nexport async function toolsCommand(argv: string[]): Promise<number> {\n const flags = parseCommonFlags(argv)\n const { server, timeoutMs } = openSessionOptions(flags)\n const spawnTimeoutMs = Math.max(2000, Math.min(10000, timeoutMs))\n const session = await McpSession.start(server, spawnTimeoutMs)\n try {\n const tools = await session.listTools()\n if (flags.json) printJson(tools)\n else console.log(formatToolList(tools))\n return 0\n } finally {\n await session.close()\n }\n}\n","#!/usr/bin/env node\nimport { callCommand } from './cli/call.js'\nimport { initCommand } from './cli/init.js'\nimport { inspectCommand } from './cli/inspect.js'\nimport { recordCommand } from './cli/record.js'\nimport { runCommand } from './cli/run.js'\nimport { toolsCommand } from './cli/tools.js'\n\nconst COMMANDS = new Set(['run', 'tools', 'call', 'record', 'init', 'inspect'])\n\nfunction printHelp(): void {\n console.log(\n [\n 'vib-test — JSON-driven MCP integration runner + authoring loop',\n '',\n 'Usage:',\n ' vib-test run [options] Run JSON cases (default)',\n ' vib-test tools [options] List tools on the server',\n ' vib-test call <tool> [options] Call a tool and print the result',\n ' vib-test record <tool> [options] Call a tool and write a case file',\n ' vib-test init [options] Scaffold vibrissa.json + sample case',\n ' vib-test inspect [options] [-- ...] Open MCP Inspector with this server',\n '',\n 'Shared options:',\n ' --config <path> vibrissa.json / .jsonc / package.json#vibrissa',\n ' --server \"<cmd ...>\" Override server command',\n ' --server-cwd <dir> Working directory for the server process',\n ' --env KEY=VALUE Extra env var (repeatable)',\n ' --timeout <ms> Per-call / spawn timeout',\n ' --json Machine-readable output (tools/call/record)',\n '',\n 'run options:',\n ' --cases <glob> Case glob (relative to shell cwd)',\n ' --fail-fast Stop on first failure',\n ' --allow-empty Exit 0 when no cases match',\n ' --pretty / --no-pretty',\n '',\n 'call / record options:',\n \" --args '{...}' JSON object of tool arguments\",\n ' --arg key=value Tool argument (repeatable; JSON-ish values ok)',\n '',\n 'record options:',\n ' --out <path> Case file path (default: tests/integration/<name>.json)',\n ' --name <string> Case name',\n ' --partial Wrap expect in \"$partial\": true',\n ' --force Overwrite an existing case file',\n '',\n 'init options:',\n ' --dir <path> Target directory (default: .)',\n ' --force Overwrite existing scaffold files',\n '',\n 'inspect options:',\n ' --cli Use Inspector CLI mode',\n ' -- ... Extra args forwarded after the server command',\n '',\n 'Workflow:',\n ' init → tools → call → record → run → inspect (when you want the UI)',\n ].join('\\n'),\n )\n}\n\nconst argv = process.argv.slice(2)\nif (argv.includes('-h') || argv.includes('--help')) {\n printHelp()\n process.exit(0)\n}\n\nlet command = 'run'\nlet rest = argv\nif (argv[0] && COMMANDS.has(argv[0])) {\n command = argv[0]\n rest = argv.slice(1)\n}\n\nlet code = 1\ntry {\n switch (command) {\n case 'run':\n code = await runCommand(rest)\n break\n case 'tools':\n code = await toolsCommand(rest)\n break\n case 'call':\n code = await callCommand(rest)\n break\n case 'record':\n code = await recordCommand(rest)\n break\n case 'init':\n code = await initCommand(rest)\n break\n case 'inspect':\n code = await inspectCommand(rest)\n break\n default:\n printHelp()\n code = 1\n }\n} catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n console.error(message)\n code = 1\n}\nprocess.exit(code)\n"],"mappings":"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","names":["argv","code","path","path","path","argv","path","argv","fs","path","fs","path","argv","argv","rest","code","fs","path","path","fs","argv","rest","path","argv","path","argv"]}
@@ -0,0 +1,73 @@
1
+ interface ServerConfig {
2
+ cmd: string;
3
+ args?: string[];
4
+ cwd?: string;
5
+ env?: Record<string, string>;
6
+ }
7
+ interface RunCasesOptions {
8
+ server: ServerConfig;
9
+ globs: string[];
10
+ timeoutMs: number;
11
+ failFast: boolean;
12
+ display?: 'plain' | 'pretty';
13
+ rootDir?: string;
14
+ allowEmpty?: boolean;
15
+ }
16
+ type JsonValue = null | boolean | number | string | JsonValue[] | {
17
+ [key: string]: JsonValue;
18
+ };
19
+ interface TestCase {
20
+ name?: string;
21
+ tool?: string;
22
+ args?: Record<string, JsonValue>;
23
+ expect?: JsonValue;
24
+ expectError?: {
25
+ code?: string;
26
+ message?: string | {
27
+ $regex?: string;
28
+ flags?: string;
29
+ };
30
+ };
31
+ }
32
+
33
+ declare const defaultRunCasesOptions: RunCasesOptions;
34
+
35
+ interface Mismatch {
36
+ path: string;
37
+ message: string;
38
+ expected?: unknown;
39
+ actual?: unknown;
40
+ }
41
+ declare function matchValue(expected: JsonValue, actual: unknown): Mismatch[];
42
+ declare function matches(expected: JsonValue, actual: unknown): boolean;
43
+
44
+ interface ToolError {
45
+ kind: 'protocol' | 'tool';
46
+ code?: number;
47
+ codeName?: string;
48
+ message: string;
49
+ }
50
+ type ToolCallOutcome = {
51
+ kind: 'result';
52
+ result: JsonValue;
53
+ } | {
54
+ kind: 'error';
55
+ error: ToolError;
56
+ };
57
+ interface ToolSummary {
58
+ name: string;
59
+ description?: string;
60
+ inputSchema: JsonValue;
61
+ }
62
+ declare class McpSession {
63
+ private readonly client;
64
+ private constructor();
65
+ static start(server: ServerConfig, timeoutMs: number): Promise<McpSession>;
66
+ callTool(name: string, args: Record<string, JsonValue>, timeoutMs: number): Promise<ToolCallOutcome>;
67
+ listTools(): Promise<ToolSummary[]>;
68
+ close(): Promise<void>;
69
+ }
70
+
71
+ declare function runCases(options: RunCasesOptions): Promise<number>;
72
+
73
+ export { type JsonValue, McpSession, type Mismatch, type RunCasesOptions, type ServerConfig, type TestCase, type ToolCallOutcome, type ToolError, type ToolSummary, defaultRunCasesOptions, matchValue, matches, runCases };
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ import {
2
+ ConsoleResultsDisplay,
3
+ McpSession,
4
+ Runner,
5
+ defaultRunCasesOptions,
6
+ matchValue,
7
+ matches
8
+ } from "./chunk-FTVETYUK.js";
9
+
10
+ // src/index.ts
11
+ async function runCases(options) {
12
+ const runner = new Runner(options, new ConsoleResultsDisplay());
13
+ return runner.run();
14
+ }
15
+ export {
16
+ McpSession,
17
+ defaultRunCasesOptions,
18
+ matchValue,
19
+ matches,
20
+ runCases
21
+ };
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type { RunCasesOptions, ServerConfig, TestCase, JsonValue } from './types.js'\nexport { defaultRunCasesOptions } from './defaults.js'\nexport { matches, matchValue } from './match.js'\nexport type { Mismatch } from './match.js'\nexport { McpSession } from './mcp-session.js'\nexport type { ToolCallOutcome, ToolError, ToolSummary } from './mcp-session.js'\nimport { ConsoleResultsDisplay } from './display.js'\nimport { Runner } from './runner.js'\nimport type { RunCasesOptions } from './types.js'\n\nexport async function runCases(options: RunCasesOptions): Promise<number> {\n const runner = new Runner(options, new ConsoleResultsDisplay())\n return runner.run()\n}\n"],"mappings":";;;;;;;;;;AAUA,eAAsB,SAAS,SAA2C;AACxE,QAAM,SAAS,IAAI,OAAO,SAAS,IAAI,sBAAsB,CAAC;AAC9D,SAAO,OAAO,IAAI;AACpB;","names":[]}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@jmoak/vibrissa",
3
+ "version": "0.1.0",
4
+ "description": "Ultra-light JSON-driven MCP integration test runner",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=20"
8
+ },
9
+ "bin": {
10
+ "vib-test": "bin/vib-test.js",
11
+ "vib": "bin/vib-test.js"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/index.js",
16
+ "types": "./dist/index.d.ts"
17
+ },
18
+ "./cli": {
19
+ "import": "./dist/cli.js"
20
+ }
21
+ },
22
+ "files": ["dist", "bin", "schema", "README.md", "LICENSE"],
23
+ "scripts": {
24
+ "build": "tsup src/cli.ts src/index.ts --format esm --target node20 --dts --clean --sourcemap --external fast-glob",
25
+ "dev": "tsup src/cli.ts src/index.ts --format esm --target node20 --dts --watch --sourcemap --external fast-glob",
26
+ "typecheck": "tsc --noEmit",
27
+ "test": "vitest run",
28
+ "test:ci": "vitest run --reporter=default --reporter=junit --outputFile.junit=reports/junit/junit.xml",
29
+ "prepublishOnly": "npm run build && npm run typecheck && npm test",
30
+ "changeset": "changeset",
31
+ "e2e": "npm run build && node bin/vib-test.js --config tests/fixtures/echo-server/vibrissa.json",
32
+ "e2e:demo": "npm run build && node bin/vib-test.js --config tests/fixtures/echo-server/vibrissa.json --cases \"tests/fixtures/echo-server/cases/**/*.json\"",
33
+ "lint": "biome check . --write",
34
+ "lint:fix": "biome check . --write --unsafe"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/JMoak/vibrissa.git"
39
+ },
40
+ "keywords": [
41
+ "mcp",
42
+ "model-context-protocol",
43
+ "mcp-testing",
44
+ "integration",
45
+ "testing",
46
+ "test-runner",
47
+ "cli",
48
+ "claude"
49
+ ],
50
+ "author": "Jordan Moak",
51
+ "license": "MIT",
52
+ "publishConfig": {
53
+ "access": "public",
54
+ "provenance": true
55
+ },
56
+ "bugs": {
57
+ "url": "https://github.com/JMoak/vibrissa/issues"
58
+ },
59
+ "homepage": "https://github.com/JMoak/vibrissa#readme",
60
+ "devDependencies": {
61
+ "@biomejs/biome": "^1.8.3",
62
+ "@changesets/cli": "^2.31.1",
63
+ "@types/node": "^20.19.13",
64
+ "@vitest/coverage-v8": "^4.1.10",
65
+ "tsup": "^8.5.0",
66
+ "typescript": "^5.9.2",
67
+ "vitest": "^4.1.10"
68
+ },
69
+ "dependencies": {
70
+ "@modelcontextprotocol/sdk": "^1.29.0",
71
+ "fast-glob": "^3.3.2",
72
+ "jest-diff": "^30.1.3"
73
+ }
74
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://unpkg.com/vibrissa/schema/case.schema.json",
4
+ "title": "Vibrissa Test Case",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["tool"],
8
+ "properties": {
9
+ "$schema": { "type": "string" },
10
+ "name": { "type": "string" },
11
+ "tool": { "type": "string", "minLength": 1 },
12
+ "args": {
13
+ "type": "object",
14
+ "additionalProperties": true
15
+ },
16
+ "expect": {},
17
+ "expectError": {
18
+ "type": "object",
19
+ "additionalProperties": false,
20
+ "properties": {
21
+ "code": { "type": "string" },
22
+ "message": {
23
+ "oneOf": [
24
+ { "type": "string" },
25
+ {
26
+ "type": "object",
27
+ "additionalProperties": false,
28
+ "properties": {
29
+ "$regex": { "type": "string" },
30
+ "flags": { "type": "string" }
31
+ },
32
+ "required": ["$regex"]
33
+ }
34
+ ]
35
+ }
36
+ }
37
+ },
38
+ "tags": {
39
+ "type": "array",
40
+ "items": { "type": "string" }
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://unpkg.com/vibrissa/schema/vibrissa.schema.json",
4
+ "title": "Vibrissa Config",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "$schema": { "type": "string" },
9
+ "server": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["cmd"],
13
+ "properties": {
14
+ "cmd": { "type": "string" },
15
+ "args": { "type": "array", "items": { "type": "string" } },
16
+ "cwd": { "type": "string" },
17
+ "env": {
18
+ "type": "object",
19
+ "additionalProperties": { "type": "string" }
20
+ }
21
+ }
22
+ },
23
+ "globs": { "type": "array", "items": { "type": "string" } },
24
+ "timeoutMs": { "type": "integer", "minimum": 0 },
25
+ "failFast": { "type": "boolean" },
26
+ "allowEmpty": {
27
+ "type": "boolean",
28
+ "description": "If true, matching zero case files exits 0. Default false (fail loud)."
29
+ }
30
+ }
31
+ }