Fix generate-cli bundling and add CI Bun coverage
This commit is contained in:
parent
44b28db644
commit
6683f35871
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@ -18,6 +18,9 @@ jobs:
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.1
|
||||
- run: pnpm install --no-frozen-lockfile
|
||||
- run: pnpm --version
|
||||
- run: pnpm check
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
_Nothing yet._
|
||||
### Code generation & metadata
|
||||
- Fixed a regression where `mcporter generate-cli --bundle/--compile` failed in directories without `commander`/`mcporter` installed by aliasing those dependencies to mcporter’s own install and verifying through a new end-to-end test that `node dist/cli.js generate-cli` runs cleanly from an empty project (fixes #1).
|
||||
|
||||
## [0.3.1] - 2025-11-07
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ Create an `mcporter generate-cli` command that produces a standalone CLI for a s
|
||||
- If `--server` matches a configured name (via `loadServerDefinitions`), use that server definition.
|
||||
- Otherwise, if the value looks like a file path, load a Cursor-style JSON definition from disk.
|
||||
- Otherwise, attempt to parse inline JSON/JSON5.
|
||||
- When `--command` is a raw HTTP selector or shell command, normalize scheme-less URLs to HTTPS and split stdio commands into `command` + `args` (e.g., `npx -y chrome-devtools-mcp@latest`).
|
||||
- When `--command` (or the first positional argument) looks like a shell command (contains whitespace), split it into `command` + `args` and treat it as stdio. Otherwise, normalize HTTP selectors (`https://`, `http://`, or `host/path.tool`) so `generate-cli mcp.context7.com/mcp` autoconfigures an HTTP transport.
|
||||
- Validate that a definition is found; prompt on failure.
|
||||
3. **Tool Introspection**
|
||||
- Use `listTools(server, { includeSchema: true })` to inspect MCP tool schemas.
|
||||
|
||||
@ -27,7 +27,7 @@ A quick reference for the primary `mcporter` subcommands. Each command inherits
|
||||
compiling with Bun).
|
||||
- Key flags:
|
||||
- `--server <name>` (or inline JSON) – choose the server definition.
|
||||
- `--command <url|command>` – point at an ad-hoc HTTP endpoint or a stdio command (e.g., `"npx -y chrome-devtools-mcp@latest"`); mcporter infers the name when omitted. Quoting the command as the first positional argument works too, so `npx mcporter generate-cli "npx -y chrome-devtools-mcp@latest"` is equivalent.
|
||||
- `--command <url|command>` – point at an ad-hoc HTTP endpoint (include `https://` or use `host/path.tool`) or a stdio command (anything with spaces, e.g., `"npx -y chrome-devtools-mcp@latest"`). If you omit `--command`, the first positional argument is inspected: whitespace → stdio, otherwise the parser probes for HTTP/HTTPS and falls back to config names.
|
||||
- `--output <path>` – where to write the TypeScript template.
|
||||
- `--bundle <path>` – emit a bundle (Node/Bun) ready for `bun x`.
|
||||
- `--compile <path>` – compile with Bun (implies `--runtime bun`).
|
||||
|
||||
@ -29,6 +29,14 @@ async function ensureDistBuilt(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function hasBun(): Promise<boolean> {
|
||||
return await new Promise<boolean>((resolve) => {
|
||||
execFile('bun', ['--version'], { cwd: process.cwd(), env: process.env }, (error) => {
|
||||
resolve(!error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('mcporter CLI integration', () => {
|
||||
let baseUrl: URL;
|
||||
let shutdown: (() => Promise<void>) | undefined;
|
||||
@ -117,4 +125,52 @@ describe('mcporter CLI integration', () => {
|
||||
expect(stats.isFile()).toBe(true);
|
||||
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {});
|
||||
});
|
||||
|
||||
it('runs "node dist/cli.js generate-cli --compile" when bun is available', async () => {
|
||||
if (!(await hasBun())) {
|
||||
console.warn('bun not available on this runner; skipping compile integration test.');
|
||||
return;
|
||||
}
|
||||
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcporter-cli-compile-'));
|
||||
await fs.writeFile(
|
||||
path.join(tempDir, 'package.json'),
|
||||
JSON.stringify({ name: 'mcporter-compile-e2e', version: '0.0.0' }, null, 2),
|
||||
'utf8'
|
||||
);
|
||||
const binaryPath = path.join(tempDir, 'context7-cli');
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
execFile(
|
||||
process.execPath,
|
||||
[CLI_ENTRY, 'generate-cli', '--command', baseUrl.toString(), '--compile', binaryPath, '--runtime', 'bun'],
|
||||
{
|
||||
cwd: tempDir,
|
||||
env: { ...process.env, MCPORTER_NO_FORCE_EXIT: '1' },
|
||||
},
|
||||
(error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const stats = await fs.stat(binaryPath);
|
||||
expect(stats.isFile()).toBe(true);
|
||||
|
||||
const { stdout } = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
|
||||
execFile(binaryPath, ['list-tools'], { env: process.env }, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve({ stdout, stderr });
|
||||
});
|
||||
});
|
||||
expect(stdout).toContain('ping - Simple health check');
|
||||
|
||||
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user