@feniix/bridgekit
Advanced tools
+34
-0
@@ -7,2 +7,36 @@ # Changelog | ||
| ## [0.13.0] - 2026-05-27 | ||
| ### Added | ||
| - New `buildStdio` option on `BinWrapperOptions` | ||
| (`@feniix/bridgekit/bin-wrapper`). Default `"inherit"` preserves | ||
| existing behavior. **MCP stdio server bins should pass | ||
| `["ignore", "inherit", "inherit"]`** — the build subprocess's stdout | ||
| otherwise contaminates the parent's JSON-RPC framing on its own | ||
| stdout. The default-`"inherit"` behavior was a latent risk for the | ||
| two current consumers that adopted `runBinWrapper` (works today only | ||
| because `npm run <script> --silent` happens to be quiet under tsc) and | ||
| an active blocker for `pi-exa`, which could not migrate from its | ||
| hand-rolled wrapper. Resolves | ||
| [#59](https://github.com/feniix/bridgekit/issues/59). | ||
| ### Changed | ||
| - `PiToolDefinition.promptGuidelines` (the internal tool-shape declared | ||
| in `src/adapters/pi.ts` and exposed via | ||
| `PiToolRegistration["registerTool"]`'s parameter) widened from | ||
| `readonly string[]` to `string[]` to close a contravariance gap with | ||
| pi-coding-agent's `ExtensionAPI`. The runtime contract is unchanged — | ||
| `registerPiTools` has spread-copied the source array into a fresh | ||
| `string[]` before handing it to `pi.registerTool` since 0.9.1 | ||
| (PR #48); only the type declaration catches up to reality. Consumers | ||
| (`pi-exa`, `pi-code-reasoning`, `pi-sequential-thinking`) can drop | ||
| the `pi as unknown as PiToolRegistration` cast at their | ||
| `registerPiTools` call sites. | ||
| `PortableTool.hostExtras.pi.promptGuidelines` (the consumer-facing | ||
| metadata type) stays `readonly string[]` — that's the right contract | ||
| for immutable consumer-owned data that bridgekit reads. Resolves | ||
| [#60](https://github.com/feniix/bridgekit/issues/60). | ||
| ## [0.12.0] - 2026-05-27 | ||
@@ -9,0 +43,0 @@ |
@@ -23,3 +23,3 @@ import type { TSchema } from "typebox"; | ||
| promptSnippet?: string; | ||
| promptGuidelines?: readonly string[]; | ||
| promptGuidelines?: string[]; | ||
| }; | ||
@@ -26,0 +26,0 @@ export type PiToolRegistration = { |
@@ -33,2 +33,16 @@ import { type SpawnSyncOptions, type SpawnSyncReturns } from "node:child_process"; | ||
| logPrefix?: string; | ||
| /** | ||
| * stdio mode passed to `spawnSync` when the build script runs. Defaults to | ||
| * `"inherit"`. | ||
| * | ||
| * **MCP stdio server bins must override this.** `process.stdout` IS the | ||
| * JSON-RPC channel for an MCP stdio server; any output the build subprocess | ||
| * emits to stdout (npm warnings, postinstall scripts, tsc diagnostics) flows | ||
| * directly into the parent's stdout via `stdio: "inherit"` and contaminates | ||
| * JSON-RPC framing. Pass `["ignore", "inherit", "inherit"]` to route the | ||
| * build's stdout to `/dev/null` while keeping stderr visible. | ||
| * | ||
| * @default "inherit" | ||
| */ | ||
| buildStdio?: SpawnSyncOptions["stdio"]; | ||
| } | ||
@@ -35,0 +49,0 @@ export interface BinWrapperDeps { |
@@ -23,3 +23,3 @@ // Internal implementation of bin-wrapper. Ships in the published tarball | ||
| cwd: packageRoot, | ||
| stdio: "inherit", | ||
| stdio: options.buildStdio ?? "inherit", | ||
| shell: process.platform === "win32", | ||
@@ -26,0 +26,0 @@ timeout: timeoutMs, |
+4
-1
@@ -116,6 +116,9 @@ # @feniix/bridgekit | ||
| buildScript: "build:mcp", | ||
| // MCP stdio bins: route the build subprocess's stdout to /dev/null so it | ||
| // cannot contaminate the parent's JSON-RPC framing on process.stdout. | ||
| buildStdio: ["ignore", "inherit", "inherit"], | ||
| }); | ||
| ``` | ||
| `mcpEntry` and `buildScript` must be literal strings — sourcing them from CLI args or env vars opens arbitrary-file import and Windows command injection. The MCP entry module must export `async function runServer(): Promise<void>`. | ||
| `mcpEntry` and `buildScript` must be literal strings — sourcing them from CLI args or env vars opens arbitrary-file import and Windows command injection. The MCP entry module must export `async function runServer(): Promise<void>`. `buildStdio` defaults to `"inherit"`; MCP stdio server bins should override to `["ignore", "inherit", "inherit"]` (since 0.13.0) because `process.stdout` is the JSON-RPC channel and the build subprocess otherwise contaminates framing. | ||
| - Narrow the MCP build to the MCP entrypoint and shared host-neutral modules; avoid compiling pi adapter entrypoints into the standalone MCP path. | ||
@@ -122,0 +125,0 @@ - Put runtime imports used by the compiled MCP bin in `dependencies`, not only peers or dev dependencies. |
+1
-1
| { | ||
| "name": "@feniix/bridgekit", | ||
| "version": "0.12.0", | ||
| "version": "0.13.0", | ||
| "description": "BridgeKit defines TypeBox-backed tools once and adapts them to pi, MCP, and other hosts.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
+1
-0
@@ -258,2 +258,3 @@ # BridgeKit | ||
| - `logPrefix` (optional, default `"bridgekit-bin"`): prefix on the "Failed to build…" diagnostic. | ||
| - `buildStdio` (optional, default `"inherit"`): `stdio` mode passed to `spawnSync` when the build script runs. **MCP stdio server bins should pass `["ignore", "inherit", "inherit"]`** so the build subprocess's stdout cannot contaminate the parent's JSON-RPC framing channel (`process.stdout`). stderr stays inherited so build diagnostics remain visible. | ||
@@ -260,0 +261,0 @@ The MCP entry module must export `async function runServer(): Promise<void>`. Consumers with a different export name can alias on export. |
134413
2.4%1329
1.06%313
0.32%