@feniix/bridgekit 0.9.4 → 0.10.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 +56 -0
- package/README.md +89 -84
- package/dist/src/core/define-tool.d.ts +5 -6
- package/dist/src/core/execute-tool.d.ts +3 -3
- package/dist/src/index.d.ts +1 -1
- package/examples/README.md +3 -49
- package/llms.txt +1 -18
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,62 @@ 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.10.0] - Unreleased
|
|
8
|
+
|
|
9
|
+
### Removed (breaking)
|
|
10
|
+
|
|
11
|
+
- `PortableToolHost<TExtension extends string>` type alias — replaced by the
|
|
12
|
+
fixed `PortableToolBuiltInHost = "pi" | "mcp" | "test"` union.
|
|
13
|
+
- `<THost extends string>` generic parameter on `PortableTool`,
|
|
14
|
+
`PortableToolContext`, `definePortableTool`, `executePortableTool`, and
|
|
15
|
+
`validatePortableToolArgs`. Host is now a fixed literal union; adapters
|
|
16
|
+
outside `"pi" | "mcp"` should cast at their adapter boundary instead of
|
|
17
|
+
extending the type union.
|
|
18
|
+
|
|
19
|
+
Migration: drop the second generic argument from any of those types.
|
|
20
|
+
`PortableTool<typeof params, "custom">` becomes `PortableTool<typeof params>`.
|
|
21
|
+
`PortableToolContext<"custom">` becomes `PortableToolContext` (cast `host`
|
|
22
|
+
at the consumer if a custom literal is needed).
|
|
23
|
+
|
|
24
|
+
Cast pattern (custom literal at the adapter boundary):
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// PortableToolContext.host is fixed to PortableToolBuiltInHost.
|
|
28
|
+
// A direct `as "custom-runtime"` fails under strict (TS2352 — no overlap);
|
|
29
|
+
// cast through `unknown` instead.
|
|
30
|
+
const ctx: PortableToolContext = {
|
|
31
|
+
host: "custom-runtime" as unknown as PortableToolBuiltInHost,
|
|
32
|
+
};
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Caveat: the cast lies at the type-system boundary, so
|
|
36
|
+
`switch (ctx.host) { ... default: assertNever(ctx.host); }` patterns will
|
|
37
|
+
fall through on the custom literal at runtime. For custom dispatch, carry
|
|
38
|
+
the host identifier on an adapter-owned field rather than on `ctx.host`,
|
|
39
|
+
or do a runtime allowlist check before exhaustive narrowing.
|
|
40
|
+
|
|
41
|
+
No consumer in tree or in the three known downstream consumers
|
|
42
|
+
(pi-sequential-thinking, pi-exa, pi-code-reasoning) used the generic.
|
|
43
|
+
Resolves [#5](https://github.com/feniix/bridgekit/issues/5).
|
|
44
|
+
|
|
45
|
+
## [0.9.5] - 2026-05-27
|
|
46
|
+
|
|
47
|
+
### Documentation
|
|
48
|
+
|
|
49
|
+
- README restructured to quickstart-first ordering: a copy-pasteable
|
|
50
|
+
three-file working example (`tools.ts`, `mcp-server.ts`,
|
|
51
|
+
`pi-extension.ts`) now lands above the fold; runtime requirements,
|
|
52
|
+
the import map, best practices, packaging, and the coding-agent
|
|
53
|
+
section all move below. Content preserved; no new entrypoints, no
|
|
54
|
+
API changes, no behavioral effects. Resolves
|
|
55
|
+
[#19](https://github.com/feniix/bridgekit/issues/19).
|
|
56
|
+
- `docs/packaging-invariants.md` adds a cross-reference under
|
|
57
|
+
`inv-mcp-sdk-major` pointing at `toInputSchema`'s JSDoc in
|
|
58
|
+
`src/adapters/mcp.ts` as the canonical record of the SDK-v1
|
|
59
|
+
`inputSchema.type` Zod-validation quirk that the `allOf` →
|
|
60
|
+
`type: "object"` synthesis addresses. Resolves
|
|
61
|
+
[#45](https://github.com/feniix/bridgekit/issues/45).
|
|
62
|
+
|
|
7
63
|
## [0.9.4] - 2026-05-27
|
|
8
64
|
|
|
9
65
|
### Fixed
|
package/README.md
CHANGED
|
@@ -2,20 +2,74 @@
|
|
|
2
2
|
|
|
3
3
|
BridgeKit provides reusable TypeBox-backed tool definitions and adapters for exposing one tool implementation through pi, MCP, and other hosts.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Quickstart
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```ts
|
|
8
|
+
// src/tools.ts
|
|
9
|
+
import { Type } from "typebox";
|
|
10
|
+
import { definePortableTool } from "@feniix/bridgekit";
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
export const echoTool = definePortableTool({
|
|
13
|
+
name: "echo",
|
|
14
|
+
title: "Echo",
|
|
15
|
+
description: "Echo text back to the caller.",
|
|
16
|
+
parameters: Type.Object({ text: Type.String() }),
|
|
17
|
+
execute(args, ctx) {
|
|
18
|
+
return {
|
|
19
|
+
text: args.text,
|
|
20
|
+
structuredContent: { text: args.text, host: ctx.host },
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
hostExtras: {
|
|
24
|
+
pi: { pendingMessage: "Echoing..." },
|
|
25
|
+
mcp: { annotations: { readOnlyHint: true } },
|
|
26
|
+
},
|
|
27
|
+
});
|
|
10
28
|
|
|
11
|
-
|
|
29
|
+
export function createTools() {
|
|
30
|
+
return [echoTool];
|
|
31
|
+
}
|
|
32
|
+
```
|
|
12
33
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
34
|
+
```ts
|
|
35
|
+
// src/mcp-server.ts
|
|
36
|
+
import { runMcpStdioServer } from "@feniix/bridgekit/mcp";
|
|
37
|
+
import { createTools } from "./tools.js";
|
|
38
|
+
|
|
39
|
+
await runMcpStdioServer({
|
|
40
|
+
name: "my-tools",
|
|
41
|
+
version: "0.1.0",
|
|
42
|
+
tools: createTools(),
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
// src/pi-extension.ts
|
|
48
|
+
import { registerPiTools } from "@feniix/bridgekit/pi";
|
|
49
|
+
import { createTools } from "./tools.js";
|
|
17
50
|
|
|
18
|
-
|
|
51
|
+
export default function extension(pi: Parameters<typeof registerPiTools>[0]) {
|
|
52
|
+
registerPiTools(pi, createTools());
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install @feniix/bridgekit typebox
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This package is ESM-only and supports Node.js 22.19.0 or newer. Published modules are import-passive and marked as side-effect free; tools are registered or servers are started only when the exported adapter functions are called.
|
|
63
|
+
|
|
64
|
+
## Why
|
|
65
|
+
|
|
66
|
+
- Define a tool once; ship it to pi and MCP without per-host forks.
|
|
67
|
+
- Host-neutral tool files: no pi or MCP SDK imports in the tool definition itself.
|
|
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.
|
|
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
|
+
|
|
72
|
+
## API reference
|
|
19
73
|
|
|
20
74
|
```ts
|
|
21
75
|
import {
|
|
@@ -26,7 +80,6 @@ import {
|
|
|
26
80
|
type PortableTool,
|
|
27
81
|
type PortableToolBuiltInHost,
|
|
28
82
|
type PortableToolContext,
|
|
29
|
-
type PortableToolHost,
|
|
30
83
|
type PortableToolResult,
|
|
31
84
|
type PortableValidationError,
|
|
32
85
|
} from "@feniix/bridgekit";
|
|
@@ -40,46 +93,7 @@ import { createMcpServer, runMcpStdioServer } from "@feniix/bridgekit/mcp";
|
|
|
40
93
|
|
|
41
94
|
Do not deep-import from `dist/` or `src/` in consuming packages.
|
|
42
95
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Define tools once in host-neutral files:
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
import { Type } from "typebox";
|
|
49
|
-
import { definePortableTool } from "@feniix/bridgekit";
|
|
50
|
-
|
|
51
|
-
export const echoTool = definePortableTool({
|
|
52
|
-
name: "echo",
|
|
53
|
-
title: "Echo",
|
|
54
|
-
description: "Echo text.",
|
|
55
|
-
parameters: Type.Object({ text: Type.String() }),
|
|
56
|
-
execute(args, ctx) {
|
|
57
|
-
return {
|
|
58
|
-
text: args.text,
|
|
59
|
-
structuredContent: { text: args.text, host: ctx.host },
|
|
60
|
-
};
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
export function createTools() {
|
|
65
|
-
return [echoTool];
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Tool definition best practices:
|
|
70
|
-
|
|
71
|
-
- Keep tool files host-neutral: no pi imports, no MCP SDK imports.
|
|
72
|
-
- Use TypeBox `Type.Object(...)` schemas so MCP can expose input schemas directly.
|
|
73
|
-
- Return `text` for model-visible output and `structuredContent` for machine-readable data.
|
|
74
|
-
- Use `isError: true` for expected/domain failures that should be represented as tool output.
|
|
75
|
-
- Throw only for unexpected programmer, adapter, or runtime failures.
|
|
76
|
-
- Respect `ctx.signal` in long-running tools.
|
|
77
|
-
- Use `ctx.progress?.(...)` for incremental updates.
|
|
78
|
-
- Keep modules import-passive; do not register tools or start servers at import time.
|
|
79
|
-
- For stateful tools, export a `createTools()` factory instead of a module-level singleton so each host runtime gets isolated state.
|
|
80
|
-
- TypeBox validation happens before `execute`; use a permissive schema plus domain validation if you need custom guidance for structurally invalid input.
|
|
81
|
-
|
|
82
|
-
## pi adapter
|
|
96
|
+
### pi adapter
|
|
83
97
|
|
|
84
98
|
```ts
|
|
85
99
|
import { registerPiTools } from "@feniix/bridgekit/pi";
|
|
@@ -141,7 +155,7 @@ new default `"return"` mode, prefer the result guards over inspecting a
|
|
|
141
155
|
`"domain"`). The guards operate on a `PortableToolResult`; they are not
|
|
142
156
|
designed to be called on the pi adapter's wire object.
|
|
143
157
|
|
|
144
|
-
|
|
158
|
+
#### Per-host metadata via `hostExtras`
|
|
145
159
|
|
|
146
160
|
`PortableTool.hostExtras` is an optional namespace for host-specific fields that should travel with the tool definition rather than a parallel sidecar map. The pi adapter reads `hostExtras.pi`; the MCP adapter reads `hostExtras.mcp`; each adapter ignores keys it does not recognise. Tools that omit `hostExtras` see no behavior change.
|
|
147
161
|
|
|
@@ -174,7 +188,7 @@ export const generateSummaryTool = definePortableTool({
|
|
|
174
188
|
|
|
175
189
|
See `docs/rfc-host-extras.md` for the design rationale (which fields are in scope, why a top-level field beats a sidecar map, the closure rule for future additions). `PortableToolHostExtras` is module-augmentable for custom host adapters; declare your namespace via `declare module "@feniix/bridgekit"`.
|
|
176
190
|
|
|
177
|
-
|
|
191
|
+
### MCP adapter
|
|
178
192
|
|
|
179
193
|
```ts
|
|
180
194
|
import { realpathSync } from "node:fs";
|
|
@@ -217,42 +231,24 @@ Portable validation failures and portable `isError: true` results return `CallTo
|
|
|
217
231
|
|
|
218
232
|
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.
|
|
219
233
|
|
|
220
|
-
##
|
|
221
|
-
|
|
222
|
-
Default portable tools accept the built-in host union:
|
|
223
|
-
|
|
224
|
-
```ts
|
|
225
|
-
type BuiltIn = "pi" | "mcp" | "test";
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
Custom adapters opt in explicitly:
|
|
229
|
-
|
|
230
|
-
```ts
|
|
231
|
-
import { Type } from "typebox";
|
|
232
|
-
import { definePortableTool, type PortableToolHost } from "@feniix/bridgekit";
|
|
233
|
-
|
|
234
|
-
const params = Type.Object({ text: Type.String() });
|
|
235
|
-
|
|
236
|
-
type CustomHost = "custom-runtime";
|
|
234
|
+
## Best practices
|
|
237
235
|
|
|
238
|
-
|
|
239
|
-
name: "custom_echo",
|
|
240
|
-
title: "Custom Echo",
|
|
241
|
-
description: "Echoes text in a custom runtime.",
|
|
242
|
-
parameters: params,
|
|
243
|
-
execute(args, ctx) {
|
|
244
|
-
const host: CustomHost = ctx.host;
|
|
245
|
-
return { text: `${host}: ${args.text}` };
|
|
246
|
-
},
|
|
247
|
-
});
|
|
236
|
+
Tool definition best practices:
|
|
248
237
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
238
|
+
- Keep tool files host-neutral: no pi imports, no MCP SDK imports.
|
|
239
|
+
- Use TypeBox `Type.Object(...)` schemas so MCP can expose input schemas directly.
|
|
240
|
+
- Return `text` for model-visible output and `structuredContent` for machine-readable data.
|
|
241
|
+
- Use `isError: true` for expected/domain failures that should be represented as tool output.
|
|
242
|
+
- Throw only for unexpected programmer, adapter, or runtime failures.
|
|
243
|
+
- Respect `ctx.signal` in long-running tools.
|
|
244
|
+
- Use `ctx.progress?.(...)` for incremental updates.
|
|
245
|
+
- Keep modules import-passive; do not register tools or start servers at import time.
|
|
246
|
+
- For stateful tools, export a `createTools()` factory instead of a module-level singleton so each host runtime gets isolated state.
|
|
247
|
+
- TypeBox validation happens before `execute`; use a permissive schema plus domain validation if you need custom guidance for structurally invalid input.
|
|
252
248
|
|
|
253
|
-
|
|
249
|
+
## Packaging
|
|
254
250
|
|
|
255
|
-
|
|
251
|
+
Package and release checklist:
|
|
256
252
|
|
|
257
253
|
- Publish compiled JavaScript plus generated `.d.ts` declarations for runtime entrypoints.
|
|
258
254
|
- Keep `exports`, `main`, and `types` aligned with built files.
|
|
@@ -267,3 +263,12 @@ Use `PortableToolHost<CustomHost>` for values that may be either a built-in host
|
|
|
267
263
|
- Treat `docs/releasing.md` as the future release handoff; this repository is not configured for automated publish yet.
|
|
268
264
|
|
|
269
265
|
See `examples/README.md` for complete copyable examples.
|
|
266
|
+
|
|
267
|
+
## For coding agents
|
|
268
|
+
|
|
269
|
+
Read these files in order:
|
|
270
|
+
|
|
271
|
+
1. `README.md` — public API, contracts, and best practices.
|
|
272
|
+
2. `llms.txt` — compact agent-facing usage rules and anti-patterns.
|
|
273
|
+
3. `examples/README.md` — copyable layouts for shared tools, pi extensions, MCP stdio servers, and per-host metadata via `hostExtras`.
|
|
274
|
+
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.
|
|
@@ -37,9 +37,8 @@ export interface PortableValidationError {
|
|
|
37
37
|
message: string;
|
|
38
38
|
}
|
|
39
39
|
export type PortableToolBuiltInHost = "pi" | "mcp" | "test";
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
host: THost;
|
|
40
|
+
export interface PortableToolContext {
|
|
41
|
+
host: PortableToolBuiltInHost;
|
|
43
42
|
signal?: AbortSignal;
|
|
44
43
|
progress?: (update: PortableToolResult) => void;
|
|
45
44
|
}
|
|
@@ -139,12 +138,12 @@ export interface PortableToolHostExtras {
|
|
|
139
138
|
pi?: PiHostExtras;
|
|
140
139
|
mcp?: McpHostExtras;
|
|
141
140
|
}
|
|
142
|
-
export interface PortableTool<TParams extends TSchema = TSchema
|
|
141
|
+
export interface PortableTool<TParams extends TSchema = TSchema> {
|
|
143
142
|
name: string;
|
|
144
143
|
title: string;
|
|
145
144
|
description: string;
|
|
146
145
|
parameters: TParams;
|
|
147
|
-
execute: (args: Static<TParams>, ctx: PortableToolContext
|
|
146
|
+
execute: (args: Static<TParams>, ctx: PortableToolContext) => PortableToolResult | Promise<PortableToolResult>;
|
|
148
147
|
/**
|
|
149
148
|
* Optional per-host metadata. Adapters consume the keys they recognise;
|
|
150
149
|
* unknown host namespaces are ignored. Absent → no behavior change.
|
|
@@ -156,4 +155,4 @@ export interface PortableTool<TParams extends TSchema = TSchema, THost extends s
|
|
|
156
155
|
*/
|
|
157
156
|
hostExtras?: PortableToolHostExtras;
|
|
158
157
|
}
|
|
159
|
-
export declare function definePortableTool<TParams extends TSchema
|
|
158
|
+
export declare function definePortableTool<TParams extends TSchema>(tool: PortableTool<TParams>): PortableTool<TParams>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { TSchema } from "typebox";
|
|
2
|
-
import type { PortableTool,
|
|
3
|
-
export declare function validatePortableToolArgs
|
|
2
|
+
import type { PortableTool, PortableToolContext, PortableToolResult, PortableValidationError } from "./define-tool.js";
|
|
3
|
+
export declare function validatePortableToolArgs(tool: PortableTool<TSchema>, args: unknown): {
|
|
4
4
|
ok: true;
|
|
5
5
|
} | {
|
|
6
6
|
ok: false;
|
|
7
7
|
errors: PortableValidationError[];
|
|
8
8
|
};
|
|
9
|
-
export declare function executePortableTool
|
|
9
|
+
export declare function executePortableTool(tool: PortableTool<TSchema>, args: unknown, ctx: PortableToolContext): Promise<PortableToolResult>;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { definePortableTool, type McpHostExtras, type PiHostExtras, type PortableTool, type PortableToolBuiltInHost, type PortableToolContext, type PortableToolErrorDetails, type
|
|
1
|
+
export { definePortableTool, type McpHostExtras, type PiHostExtras, type PortableTool, type PortableToolBuiltInHost, type PortableToolContext, type PortableToolErrorDetails, type PortableToolHostExtras, type PortableToolResult, type PortableValidationError, } from "./core/define-tool.js";
|
|
2
2
|
export { executePortableTool, validatePortableToolArgs } from "./core/execute-tool.js";
|
|
3
3
|
export { isDomainFailure, isValidationFailure, type PortableDomainFailure, type PortableValidationFailure, } from "./core/result-guards.js";
|
package/examples/README.md
CHANGED
|
@@ -283,53 +283,7 @@ MCP behavior:
|
|
|
283
283
|
|
|
284
284
|
---
|
|
285
285
|
|
|
286
|
-
## 4.
|
|
287
|
-
|
|
288
|
-
Default portable tools accept only built-in hosts: `"pi" | "mcp" | "test"`.
|
|
289
|
-
|
|
290
|
-
If you are writing a custom adapter, opt in explicitly so the handler can safely narrow `ctx.host`:
|
|
291
|
-
|
|
292
|
-
```ts
|
|
293
|
-
import { Type } from "typebox";
|
|
294
|
-
import {
|
|
295
|
-
definePortableTool,
|
|
296
|
-
executePortableTool,
|
|
297
|
-
type PortableTool,
|
|
298
|
-
type PortableToolContext,
|
|
299
|
-
type PortableToolHost,
|
|
300
|
-
} from "@feniix/bridgekit";
|
|
301
|
-
|
|
302
|
-
const params = Type.Object({ text: Type.String() });
|
|
303
|
-
|
|
304
|
-
type CustomHost = "custom-runtime";
|
|
305
|
-
type CustomTool = PortableTool<typeof params, CustomHost>;
|
|
306
|
-
|
|
307
|
-
const customTool = definePortableTool<typeof params, CustomHost>({
|
|
308
|
-
name: "custom_echo",
|
|
309
|
-
title: "Custom Echo",
|
|
310
|
-
description: "Echoes text in a custom runtime.",
|
|
311
|
-
parameters: params,
|
|
312
|
-
execute(args, ctx) {
|
|
313
|
-
const host: CustomHost = ctx.host;
|
|
314
|
-
return { text: `${host}: ${args.text}` };
|
|
315
|
-
},
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
async function runCustomTool(tool: CustomTool, text: string) {
|
|
319
|
-
const ctx: PortableToolContext<CustomHost> = { host: "custom-runtime" };
|
|
320
|
-
return executePortableTool(tool, { text }, ctx);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const hostValue: PortableToolHost<CustomHost> = "custom-runtime";
|
|
324
|
-
void hostValue;
|
|
325
|
-
void customTool;
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
Use `PortableToolHost<CustomHost>` for values that can be either a built-in host or your custom extension. Use `PortableToolContext<CustomHost>` or `PortableTool<Schema, CustomHost>` when a tool is custom-host-only.
|
|
329
|
-
|
|
330
|
-
---
|
|
331
|
-
|
|
332
|
-
## 5. Per-host metadata via `hostExtras`
|
|
286
|
+
## 4. Per-host metadata via `hostExtras`
|
|
333
287
|
|
|
334
288
|
When a tool needs host-specific metadata — pi's `pendingMessage` for a "Processing..." signal, MCP's annotations as advisory hints to clients — the canonical place is `PortableTool.hostExtras`. Each host has its own namespace; adapters read the keys they recognise and ignore the rest. Tools that omit `hostExtras` see no behavior change.
|
|
335
289
|
|
|
@@ -366,7 +320,7 @@ Best practices for `hostExtras`:
|
|
|
366
320
|
|
|
367
321
|
- Keep tool *behavior* host-neutral. `hostExtras` carries *data* the adapter reads on the tool's behalf; do not embed callbacks or runtime logic.
|
|
368
322
|
- Set only the fields the adapter recognises; unrecognised keys are silently ignored, but they add noise to the definition.
|
|
369
|
-
- For
|
|
323
|
+
- If you ship an adapter for a host outside `"pi" | "mcp"`, cast `ctx.host` at the adapter boundary (the host union is fixed since 0.10.0). For type-safe per-host metadata in your adapter's namespace, extend `PortableToolHostExtras` via `declare module "@feniix/bridgekit"` so consumers of your adapter get type safety on the new namespace.
|
|
370
324
|
|
|
371
325
|
See `docs/rfc-host-extras.md` for the full design rationale (which fields qualify, why a top-level field beats a sidecar map, the closure rule for future additions).
|
|
372
326
|
|
|
@@ -446,7 +400,7 @@ per-consumer migration deltas.
|
|
|
446
400
|
|
|
447
401
|
---
|
|
448
402
|
|
|
449
|
-
##
|
|
403
|
+
## 5. Package checklist
|
|
450
404
|
|
|
451
405
|
For publishable tool packages:
|
|
452
406
|
|
package/llms.txt
CHANGED
|
@@ -6,7 +6,7 @@ Use this package when you need to define a tool once and expose it through both
|
|
|
6
6
|
|
|
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
|
-
3. `examples/README.md` — copyable end-to-end layouts for shared tools, pi extension wiring, MCP stdio server wiring, and
|
|
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
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.
|
|
11
11
|
|
|
12
12
|
## Import map
|
|
@@ -96,23 +96,6 @@ if (result.isError) {
|
|
|
96
96
|
}
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
## Custom host typing
|
|
100
|
-
|
|
101
|
-
Default tools accept only built-in hosts: `"pi" | "mcp" | "test"`.
|
|
102
|
-
For a custom adapter, opt in explicitly:
|
|
103
|
-
|
|
104
|
-
```ts
|
|
105
|
-
const customTool = definePortableTool<typeof params, "custom-host">({
|
|
106
|
-
// ...
|
|
107
|
-
execute(args, ctx) {
|
|
108
|
-
const host: "custom-host" = ctx.host;
|
|
109
|
-
return { text: host };
|
|
110
|
-
},
|
|
111
|
-
});
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Use `PortableToolHost<"custom-host">` when a value may be either a built-in host or that extension.
|
|
115
|
-
|
|
116
99
|
## Mixed source-loaded hosts and compiled MCP bins
|
|
117
100
|
|
|
118
101
|
Some hosts, such as pi in source-extension packages, may intentionally load TypeScript source while MCP clients launched from npm need compiled JavaScript. In that case:
|