@feniix/bridgekit 0.12.0 → 0.13.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/CHANGELOG.md CHANGED
@@ -4,6 +4,40 @@ All notable changes to `@feniix/bridgekit` are documented here. The format
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project
5
5
  adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.13.0] - 2026-05-27
8
+
9
+ ### Added
10
+
11
+ - New `buildStdio` option on `BinWrapperOptions`
12
+ (`@feniix/bridgekit/bin-wrapper`). Default `"inherit"` preserves
13
+ existing behavior. **MCP stdio server bins should pass
14
+ `["ignore", "inherit", "inherit"]`** — the build subprocess's stdout
15
+ otherwise contaminates the parent's JSON-RPC framing on its own
16
+ stdout. The default-`"inherit"` behavior was a latent risk for the
17
+ two current consumers that adopted `runBinWrapper` (works today only
18
+ because `npm run <script> --silent` happens to be quiet under tsc) and
19
+ an active blocker for `pi-exa`, which could not migrate from its
20
+ hand-rolled wrapper. Resolves
21
+ [#59](https://github.com/feniix/bridgekit/issues/59).
22
+
23
+ ### Changed
24
+
25
+ - `PiToolDefinition.promptGuidelines` (the internal tool-shape declared
26
+ in `src/adapters/pi.ts` and exposed via
27
+ `PiToolRegistration["registerTool"]`'s parameter) widened from
28
+ `readonly string[]` to `string[]` to close a contravariance gap with
29
+ pi-coding-agent's `ExtensionAPI`. The runtime contract is unchanged —
30
+ `registerPiTools` has spread-copied the source array into a fresh
31
+ `string[]` before handing it to `pi.registerTool` since 0.9.1
32
+ (PR #48); only the type declaration catches up to reality. Consumers
33
+ (`pi-exa`, `pi-code-reasoning`, `pi-sequential-thinking`) can drop
34
+ the `pi as unknown as PiToolRegistration` cast at their
35
+ `registerPiTools` call sites.
36
+ `PortableTool.hostExtras.pi.promptGuidelines` (the consumer-facing
37
+ metadata type) stays `readonly string[]` — that's the right contract
38
+ for immutable consumer-owned data that bridgekit reads. Resolves
39
+ [#60](https://github.com/feniix/bridgekit/issues/60).
40
+
7
41
  ## [0.12.0] - 2026-05-27
8
42
 
9
43
  ### Documentation
package/README.md CHANGED
@@ -255,6 +255,7 @@ Options:
255
255
  - `buildScript` (required): npm script to invoke when the entry is missing (e.g. `"build:mcp"`).
256
256
  - `buildTimeoutMs` (optional, default `60_000`): timeout for the build subprocess. Distinct "Build timed out…" diagnostic fires when exceeded.
257
257
  - `logPrefix` (optional, default `"bridgekit-bin"`): prefix on the "Failed to build…" diagnostic.
258
+ - `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.
258
259
 
259
260
  The MCP entry module must export `async function runServer(): Promise<void>`. Consumers with a different export name can alias on export.
260
261
 
@@ -20,7 +20,7 @@ type PiToolDefinition = {
20
20
  parameters: TSchema;
21
21
  execute(toolCallId: string, params: unknown, signal?: AbortSignal, onUpdate?: (update: PiToolUpdate) => void, ctx?: unknown): Promise<PiToolResult>;
22
22
  promptSnippet?: string;
23
- promptGuidelines?: readonly string[];
23
+ promptGuidelines?: string[];
24
24
  };
25
25
  export type PiToolRegistration = {
26
26
  registerTool(tool: PiToolDefinition): unknown;
@@ -30,6 +30,20 @@ export interface BinWrapperOptions {
30
30
  buildScript: string;
31
31
  buildTimeoutMs?: number;
32
32
  logPrefix?: string;
33
+ /**
34
+ * stdio mode passed to `spawnSync` when the build script runs. Defaults to
35
+ * `"inherit"`.
36
+ *
37
+ * **MCP stdio server bins must override this.** `process.stdout` IS the
38
+ * JSON-RPC channel for an MCP stdio server; any output the build subprocess
39
+ * emits to stdout (npm warnings, postinstall scripts, tsc diagnostics) flows
40
+ * directly into the parent's stdout via `stdio: "inherit"` and contaminates
41
+ * JSON-RPC framing. Pass `["ignore", "inherit", "inherit"]` to route the
42
+ * build's stdout to `/dev/null` while keeping stderr visible.
43
+ *
44
+ * @default "inherit"
45
+ */
46
+ buildStdio?: SpawnSyncOptions["stdio"];
33
47
  }
34
48
  export interface BinWrapperDeps {
35
49
  spawnSync: BinWrapperSpawnSync;
@@ -20,7 +20,7 @@ export async function runBinWrapperWithDeps(options, deps) {
20
20
  const timeoutMs = options.buildTimeoutMs ?? DEFAULT_BUILD_TIMEOUT_MS;
21
21
  const build = deps.spawnSync("npm", ["run", options.buildScript, "--silent"], {
22
22
  cwd: packageRoot,
23
- stdio: "inherit",
23
+ stdio: options.buildStdio ?? "inherit",
24
24
  shell: process.platform === "win32",
25
25
  timeout: timeoutMs,
26
26
  });
package/llms.txt CHANGED
@@ -113,10 +113,13 @@ Some hosts, such as pi in source-extension packages, may intentionally load Type
113
113
  metaUrl: import.meta.url,
114
114
  mcpEntry: "dist/extensions/mcp-server.js",
115
115
  buildScript: "build:mcp",
116
+ // MCP stdio bins: route the build subprocess's stdout to /dev/null so it
117
+ // cannot contaminate the parent's JSON-RPC framing on process.stdout.
118
+ buildStdio: ["ignore", "inherit", "inherit"],
116
119
  });
117
120
  ```
118
121
 
119
- `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>`.
122
+ `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.
120
123
  - Narrow the MCP build to the MCP entrypoint and shared host-neutral modules; avoid compiling pi adapter entrypoints into the standalone MCP path.
121
124
  - Put runtime imports used by the compiled MCP bin in `dependencies`, not only peers or dev dependencies.
122
125
  - Declare BridgeKit's Node engine requirement in the downstream package (`>=22.19.0`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feniix/bridgekit",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "BridgeKit defines TypeBox-backed tools once and adapts them to pi, MCP, and other hosts.",
5
5
  "keywords": [
6
6
  "pi",