@feniix/bridgekit 0.11.0 → 0.12.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,35 @@ 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.12.0] - 2026-05-27
8
+
9
+ ### Documentation
10
+
11
+ - `README.md` gets a full `bin-wrapper` adapter section under "API
12
+ reference" — usage example, options breakdown, `runServer`
13
+ contract, trusted-literal security note, and the missing-entry
14
+ behavior matrix. Previously the subpath had a single line in the
15
+ entrypoint table and zero body documentation. Closes the largest
16
+ gap surfaced by the post-0.11.0 doc audit.
17
+ - `README.md` "Why" bullet and "Packaging" section updated for the
18
+ four-entrypoint shape and the `runBinWrapper` recommendation
19
+ (replaces the pre-0.11.0 manual checked-in-wrapper recipe).
20
+ - `llms.txt` rewrites the "Mixed source-loaded hosts and compiled
21
+ MCP bins" section to lead with `runBinWrapper`. The 8-bullet
22
+ manual-wrapper recipe is demoted to a fallback bullet for
23
+ authors writing their own wrapper.
24
+ - `dist/src/bin-wrapper.d.ts` added to the published-declarations
25
+ lists in `README.md` and `llms.txt`.
26
+ - `docs/README.md` lists `docs/rfc-host-extras.md` in the
27
+ maintainer-docs catalog. The RFC is JSDoc-linked from
28
+ `src/core/define-tool.ts` and was missing from the catalog.
29
+ - `src/adapters/mcp.typecheck.ts` fixes a wrong version stamp on
30
+ the `signalFromExtra` adversarial-pin comment (was `0.10.0 (#3)`,
31
+ should be `0.11.0 (#3)`). The pin's code is correct; only the
32
+ comment was wrong.
33
+
34
+ No API or behavior changes.
35
+
7
36
  ## [0.11.0] - 2026-05-27
8
37
 
9
38
  ### Added
package/README.md CHANGED
@@ -66,7 +66,7 @@ This package is ESM-only and supports Node.js 22.19.0 or newer. Published module
66
66
  - Define a tool once; ship it to pi and MCP without per-host forks.
67
67
  - Host-neutral tool files: no pi or MCP SDK imports in the tool definition itself.
68
68
  - TypeBox schemas pass through to MCP `inputSchema` directly — no JSON Schema conversion step.
69
- - Import-passive, `sideEffects: false`, three-entrypoint split (`.`, `./pi`, `./mcp`) so pi-only consumers do not pull the MCP SDK and vice versa.
69
+ - Import-passive, `sideEffects: false`, four-entrypoint split (`.`, `./pi`, `./mcp`, `./bin-wrapper`) so pi-only consumers do not pull the MCP SDK and vice versa.
70
70
  - Conformance-tested public surface: a packed-install smoke test enforces the runtime export set, deep-import rejection, and type-level strictness against the installed declarations.
71
71
 
72
72
  ## API reference
@@ -233,6 +233,41 @@ Portable validation failures and portable `isError: true` results return `CallTo
233
233
 
234
234
  The two adapters now read in parallel: invalid args and portable `isError` results return `{ isError: true }` from both hosts by default, and the same result-guard helpers (`isValidationFailure`, `isDomainFailure`) narrow them on either side.
235
235
 
236
+ ### bin-wrapper (since 0.11.0)
237
+
238
+ The `bin-wrapper` subpath ships a helper for npm `bin` scripts that load a compiled MCP entrypoint and build it on first invocation when the compiled output is missing. Replaces the ~25-line "resolve dist path → spawn build if missing → import and run" boilerplate that downstream consumers with mixed source-loaded pi + compiled MCP packages previously hand-rolled.
239
+
240
+ ```js
241
+ #!/usr/bin/env node
242
+ import { runBinWrapper } from "@feniix/bridgekit/bin-wrapper";
243
+
244
+ await runBinWrapper({
245
+ metaUrl: import.meta.url,
246
+ mcpEntry: "dist/extensions/mcp-server.js",
247
+ buildScript: "build:mcp",
248
+ });
249
+ ```
250
+
251
+ Options:
252
+
253
+ - `metaUrl` (required): `import.meta.url` of the bin script. Used to locate the package root (the bin's parent directory).
254
+ - `mcpEntry` (required): path to the compiled MCP entry, relative to the package root (e.g. `"dist/extensions/mcp-server.js"`).
255
+ - `buildScript` (required): npm script to invoke when the entry is missing (e.g. `"build:mcp"`).
256
+ - `buildTimeoutMs` (optional, default `60_000`): timeout for the build subprocess. Distinct "Build timed out…" diagnostic fires when exceeded.
257
+ - `logPrefix` (optional, default `"bridgekit-bin"`): prefix on the "Failed to build…" diagnostic.
258
+
259
+ The MCP entry module must export `async function runServer(): Promise<void>`. Consumers with a different export name can alias on export.
260
+
261
+ **Security: `mcpEntry` and `buildScript` must be literal strings in the caller's source.** The helper joins `mcpEntry` onto the resolved package root and dynamically `import()`s it, and it passes `buildScript` to `spawnSync` (with `shell: true` on Windows where `&`, `|`, and `^` are shell metacharacters). Sourcing either from CLI args or environment variables exposes arbitrary-file import and Windows command injection.
262
+
263
+ Behavior on missing entry:
264
+
265
+ - Build emits the entry → import and call `runServer()`.
266
+ - Build exits non-zero but the entry exists → recover (import and call `runServer()`).
267
+ - Build exits 0 but the entry is still missing → exit with code 1, generic "Failed to build…" diagnostic.
268
+ - Build exits non-zero with entry missing → exit with the build's status code, generic diagnostic.
269
+ - Build killed by timeout (SIGTERM) → exit 1, distinct timeout diagnostic naming `buildTimeoutMs`.
270
+
236
271
  ## Best practices
237
272
 
238
273
  Tool definition best practices:
@@ -258,7 +293,7 @@ Package and release checklist:
258
293
  - Avoid `workspace:` or `file:` dependency ranges in publishable packages.
259
294
  - Avoid dangling `sourceMappingURL` comments: publish maps and useful sources together, or disable source maps for package builds.
260
295
  - For MCP stdio bins, ensure the executable entrypoint starts with a Node shebang, has executable mode (`chmod +x` or equivalent), and is included by `npm pack --dry-run --json`.
261
- - If an npm-launched bin depends on generated output, prefer a checked-in wrapper under `bin/` over pointing `bin` directly at `dist/`; the wrapper should resolve the package-local generated file and may run the package-local build for workspace/local execution.
296
+ - If an npm-launched bin depends on generated output, use `runBinWrapper` from `@feniix/bridgekit/bin-wrapper` (since 0.11.0) — it resolves the package-local generated entry, runs the package-local build when output is missing in workspace/local execution, preserves build failures, and distinguishes timeout from build error in its diagnostic. The bin script becomes a three-line invocation; no hand-rolled wrapper needed.
262
297
  - If a package keeps a source-loaded host entrypoint (for example a pi extension source file), use a package-local MCP build behind that wrapper and narrow the build to the MCP entrypoint plus shared host-neutral modules.
263
298
  - Declare a compatible Node engine (`>=22.19.0`) in downstream packages that expose BridgeKit-powered MCP bins.
264
299
  - Run `npm run check`, `npm run test`, `npm run pack:dry-run`, and `npm run package-smoke` before publishing.
@@ -272,5 +307,5 @@ Read these files in order:
272
307
 
273
308
  1. `README.md` — public API, contracts, and best practices.
274
309
  2. `llms.txt` — compact agent-facing usage rules and anti-patterns.
275
- 3. `examples/README.md` — copyable layouts for shared tools, pi extensions, MCP stdio servers, and per-host metadata via `hostExtras`.
276
- 4. Published declarations such as `dist/src/index.d.ts`, `dist/src/pi.d.ts`, and `dist/src/mcp.d.ts` — canonical installed-package type contracts. In a source checkout, the matching `src/` files contain the same implementation context.
310
+ 3. `examples/README.md` — copyable layouts for shared tools, pi extensions, MCP stdio servers, per-host metadata via `hostExtras`, and bin wrappers via `runBinWrapper`.
311
+ 4. Published declarations such as `dist/src/index.d.ts`, `dist/src/pi.d.ts`, `dist/src/mcp.d.ts`, and `dist/src/bin-wrapper.d.ts` — canonical installed-package type contracts. In a source checkout, the matching `src/` files contain the same implementation context.
package/llms.txt CHANGED
@@ -7,7 +7,7 @@ Use this package when you need to define a tool once and expose it through both
7
7
  1. `README.md` — public API, contracts, best practices, packaging notes.
8
8
  2. `llms.txt` — compact agent-facing usage rules and anti-patterns.
9
9
  3. `examples/README.md` — copyable end-to-end layouts for shared tools, pi extension wiring, MCP stdio server wiring, and per-host metadata via `hostExtras`.
10
- 4. Published declarations such as `dist/src/index.d.ts`, `dist/src/pi.d.ts`, and `dist/src/mcp.d.ts` — canonical installed-package type contracts. In a source checkout, the matching `src/` files contain implementation context.
10
+ 4. Published declarations such as `dist/src/index.d.ts`, `dist/src/pi.d.ts`, `dist/src/mcp.d.ts`, and `dist/src/bin-wrapper.d.ts` — canonical installed-package type contracts. In a source checkout, the matching `src/` files contain implementation context.
11
11
 
12
12
  ## Import map
13
13
 
@@ -104,12 +104,24 @@ Some hosts, such as pi in source-extension packages, may intentionally load Type
104
104
 
105
105
  - Keep the host source entrypoint if that is the package convention, e.g. `pi.extensions: ["./extensions/index.ts"]`.
106
106
  - Add a package-local MCP build and point npm `bin` at a checked-in wrapper under `bin/`, not directly at generated `dist/` output.
107
- - The wrapper should resolve the package-local generated MCP server, run the package-local build when output is missing in workspace/local execution, and preserve non-zero build failures.
107
+ - **Use the built-in `runBinWrapper` helper** (since 0.11.0) instead of a hand-rolled wrapper. It resolves the package-local generated entry, runs the package-local build when output is missing in workspace/local execution, preserves non-zero build failures, recovers when the build emits the entry despite a non-zero exit, and emits a distinct timeout diagnostic when `spawnSync` is killed by `buildTimeoutMs`:
108
+
109
+ ```js
110
+ #!/usr/bin/env node
111
+ import { runBinWrapper } from "@feniix/bridgekit/bin-wrapper";
112
+ await runBinWrapper({
113
+ metaUrl: import.meta.url,
114
+ mcpEntry: "dist/extensions/mcp-server.js",
115
+ buildScript: "build:mcp",
116
+ });
117
+ ```
118
+
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>`.
108
120
  - Narrow the MCP build to the MCP entrypoint and shared host-neutral modules; avoid compiling pi adapter entrypoints into the standalone MCP path.
109
121
  - Put runtime imports used by the compiled MCP bin in `dependencies`, not only peers or dev dependencies.
110
122
  - Declare BridgeKit's Node engine requirement in the downstream package (`>=22.19.0`).
111
- - Ensure the checked-in wrapper is executable (`chmod +x` or equivalent) and verify the mode with `npm pack --dry-run --json`.
112
- - Test wrapper behavior for existing output, missing output, failed builds, and builds that exit successfully without creating the expected file.
123
+ - Ensure the bin script is executable (`chmod +x` or equivalent) and verify the mode with `npm pack --dry-run --json`.
124
+ - If you write your own wrapper instead of using `runBinWrapper`, test the four behavior modes: existing output, missing output that the build creates, failed builds (non-zero exit), and builds that exit successfully without creating the expected file.
113
125
 
114
126
  ## Anti-patterns
115
127
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feniix/bridgekit",
3
- "version": "0.11.0",
3
+ "version": "0.12.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",