stitchkit 0.103.13 → 0.104.1
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 +120 -0
- package/darwin-native.cjs +1 -3
- package/dist/agent-runtime/store-conformance-lifecycle.d.ts +10 -10
- package/dist/agent-runtime/store-conformance-support.d.ts +5 -5
- package/dist/application/directory-inbox-accept.d.ts +13 -0
- package/dist/application/directory-inbox-accept.d.ts.map +1 -0
- package/dist/application/directory-inbox-contract.d.ts +42 -5
- package/dist/application/directory-inbox-contract.d.ts.map +1 -1
- package/dist/application/directory-inbox-delivery.d.ts +14 -0
- package/dist/application/directory-inbox-delivery.d.ts.map +1 -0
- package/dist/application/directory-inbox-files.d.ts +28 -0
- package/dist/application/directory-inbox-files.d.ts.map +1 -0
- package/dist/application/directory-inbox-state.d.ts +14 -0
- package/dist/application/directory-inbox-state.d.ts.map +1 -0
- package/dist/application/directory-inbox.d.ts +2 -1
- package/dist/application/directory-inbox.d.ts.map +1 -1
- package/dist/application/file-state-store.d.ts +2 -8
- package/dist/application/file-state-store.d.ts.map +1 -1
- package/dist/application/state-store.d.ts +6 -1
- package/dist/application/state-store.d.ts.map +1 -1
- package/dist/browser/client-arguments.d.ts +4 -0
- package/dist/browser/client-arguments.d.ts.map +1 -0
- package/dist/browser/client-executors.d.ts.map +1 -1
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/contract-stream.d.ts.map +1 -1
- package/dist/browser/http.d.ts +2 -1
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/browser/native-fetch.d.ts +8 -0
- package/dist/browser/native-fetch.d.ts.map +1 -0
- package/dist/contract/errors.d.ts +16 -12
- package/dist/contract/errors.d.ts.map +1 -1
- package/dist/contract/normalize.d.ts +5 -1
- package/dist/contract/normalize.d.ts.map +1 -1
- package/dist/contract/stream.d.ts +1 -0
- package/dist/contract/stream.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/browser.js +3 -3
- package/dist/entrypoints/agent-runtime/coding-tools.js +6 -6
- package/dist/entrypoints/agent-runtime/harness-tools.js +8 -8
- package/dist/entrypoints/agent-runtime/harness.js +11 -11
- package/dist/entrypoints/agent-runtime/realtime.js +3 -3
- package/dist/entrypoints/agent-runtime/sandbox.js +6 -6
- package/dist/entrypoints/agent-runtime.js +13 -13
- package/dist/entrypoints/application/diagnostic-journal.js +1 -1
- package/dist/entrypoints/application/directory-inbox.js +424 -119
- package/dist/entrypoints/application/grammy.js +1 -1
- package/dist/entrypoints/application.d.ts +2 -2
- package/dist/entrypoints/application.d.ts.map +1 -1
- package/dist/entrypoints/application.js +7 -3
- package/dist/entrypoints/cli.d.ts +2 -0
- package/dist/entrypoints/cli.d.ts.map +1 -1
- package/dist/entrypoints/cli.js +757 -136
- package/dist/entrypoints/contract.js +3 -3
- package/dist/entrypoints/files/packaging.d.ts +3 -0
- package/dist/entrypoints/files/packaging.d.ts.map +1 -0
- package/dist/entrypoints/files/packaging.js +133 -0
- package/dist/entrypoints/files.js +10 -107
- package/dist/entrypoints/index.js +7 -7
- package/dist/entrypoints/node.js +8 -8
- package/dist/entrypoints/observability.js +2 -2
- package/dist/entrypoints/react.js +1 -1
- package/dist/entrypoints/remote.js +19 -6
- package/dist/entrypoints/server.d.ts +1 -1
- package/dist/entrypoints/server.d.ts.map +1 -1
- package/dist/entrypoints/server.js +23 -17
- package/dist/entrypoints/telegram.d.ts +1 -0
- package/dist/entrypoints/telegram.d.ts.map +1 -1
- package/dist/entrypoints/telegram.js +214 -98
- package/dist/entrypoints/testing.js +7 -7
- package/dist/entrypoints/tools/connections.d.ts +2 -2
- package/dist/entrypoints/tools/connections.d.ts.map +1 -1
- package/dist/entrypoints/tools/connections.js +427 -294
- package/dist/entrypoints/tools/invoker.js +6 -6
- package/dist/entrypoints/tools/mcp.d.ts +12 -0
- package/dist/entrypoints/tools/mcp.d.ts.map +1 -0
- package/dist/entrypoints/tools/mcp.js +45 -0
- package/dist/entrypoints/tools.d.ts +1 -0
- package/dist/entrypoints/tools.d.ts.map +1 -1
- package/dist/entrypoints/tools.js +82 -1147
- package/dist/entrypoints/tracking.js +1 -1
- package/dist/files/boundary.d.ts +2 -8
- package/dist/files/boundary.d.ts.map +1 -1
- package/dist/files/file-io.d.ts +0 -5
- package/dist/files/file-io.d.ts.map +1 -1
- package/dist/files/native-packaging-layout.d.ts +12 -0
- package/dist/files/native-packaging-layout.d.ts.map +1 -0
- package/dist/files/native-packaging.d.ts +72 -0
- package/dist/files/native-packaging.d.ts.map +1 -0
- package/dist/files/read.d.ts +2 -2
- package/dist/files/read.d.ts.map +1 -1
- package/dist/index-1a6jtnd9.js +88 -0
- package/dist/index-269zqj8m.js +77 -0
- package/dist/{index-r34mvse1.js → index-27a2pj09.js} +1 -1
- package/dist/{index-r956rndn.js → index-2hyavjjj.js} +3 -3
- package/dist/{index-m2xqkv55.js → index-2vnh05w4.js} +83 -14
- package/dist/{index-pw99k9h5.js → index-43p08g7t.js} +1 -1
- package/dist/{index-xwq9j1sf.js → index-4e0ah203.js} +9 -7
- package/dist/{index-qapzv4p5.js → index-5z6jn897.js} +1 -1
- package/dist/{index-ahvsksw5.js → index-6d9xaxw1.js} +1 -1
- package/dist/{index-8zfsgar0.js → index-6drst9sg.js} +11 -5
- package/dist/{index-x87j7csh.js → index-77nxk6ay.js} +2 -2
- package/dist/{index-dnn9z96q.js → index-a0zzh8ak.js} +3 -3
- package/dist/{index-kmpzj1cq.js → index-a3wma1hk.js} +1 -1
- package/dist/{index-j8aw2c0e.js → index-bakgedh8.js} +35 -7
- package/dist/index-bhb950qs.js +1145 -0
- package/dist/{index-tgzhq07n.js → index-cvda079a.js} +1 -1
- package/dist/{index-n2gre124.js → index-fa4wg312.js} +4 -4
- package/dist/{index-zp4jpkp0.js → index-fk18k56k.js} +2 -2
- package/dist/{index-afjvjyck.js → index-g2j7pnak.js} +2 -134
- package/dist/index-g95fk660.js +116 -0
- package/dist/{index-r5c4fedv.js → index-h2fhjqy7.js} +2 -1
- package/dist/{index-sybedc8b.js → index-hbd32c6a.js} +23 -94
- package/dist/{index-fyphpknh.js → index-hp9d77wk.js} +1 -1
- package/dist/index-jd470k6q.js +109 -0
- package/dist/{index-b2bz0kdm.js → index-kb8styz3.js} +4 -3
- package/dist/{index-0c419yx7.js → index-kemm0ej5.js} +12 -9
- package/dist/{index-db2spkv1.js → index-ptn0g0gj.js} +3 -3
- package/dist/{index-w575evhq.js → index-r4r70zmh.js} +1 -1
- package/dist/{index-12m2v2a9.js → index-s4evrmp5.js} +1 -1
- package/dist/{index-1khy8y7n.js → index-t1sr4aks.js} +3 -3
- package/dist/{index-45tdvqa3.js → index-wh0ecvyk.js} +1 -1
- package/dist/{index-n53mswt3.js → index-x928baz2.js} +8 -1
- package/dist/index-yk4g8805.js +133 -0
- package/dist/{index-ygkka6zn.js → index-ywppsaby.js} +28 -5
- package/dist/{index-9853ymwb.js → index-za6j7nwy.js} +18 -4
- package/dist/internal/bounded-file-read.d.ts +41 -0
- package/dist/internal/bounded-file-read.d.ts.map +1 -0
- package/dist/internal/exclusive-lock.d.ts +2 -0
- package/dist/internal/exclusive-lock.d.ts.map +1 -1
- package/dist/internal/with-exclusive-lock.d.ts +4 -2
- package/dist/internal/with-exclusive-lock.d.ts.map +1 -1
- package/dist/telegram/broadcast-delivery.d.ts +23 -0
- package/dist/telegram/broadcast-delivery.d.ts.map +1 -0
- package/dist/telegram/broadcast-failure.d.ts +22 -0
- package/dist/telegram/broadcast-failure.d.ts.map +1 -0
- package/dist/telegram/broadcast-state.d.ts +6 -3
- package/dist/telegram/broadcast-state.d.ts.map +1 -1
- package/dist/telegram/broadcast.d.ts +10 -5
- package/dist/telegram/broadcast.d.ts.map +1 -1
- package/dist/tools/cli/format.d.ts.map +1 -1
- package/dist/tools/cli/invoke.d.ts +2 -2
- package/dist/tools/cli/invoke.d.ts.map +1 -1
- package/dist/tools/cli/publication-assets.d.ts +10 -0
- package/dist/tools/cli/publication-assets.d.ts.map +1 -0
- package/dist/tools/cli/publication-contract.d.ts +75 -0
- package/dist/tools/cli/publication-contract.d.ts.map +1 -0
- package/dist/tools/cli/publication-control.d.ts +4 -0
- package/dist/tools/cli/publication-control.d.ts.map +1 -0
- package/dist/tools/cli/publication-storage.d.ts +32 -0
- package/dist/tools/cli/publication-storage.d.ts.map +1 -0
- package/dist/tools/cli/publication.d.ts +35 -0
- package/dist/tools/cli/publication.d.ts.map +1 -0
- package/dist/tools/cli/update.d.ts.map +1 -1
- package/dist/tools/connections/define.d.ts.map +1 -1
- package/dist/tools/connections/error-projection.d.ts +4 -0
- package/dist/tools/connections/error-projection.d.ts.map +1 -0
- package/dist/tools/connections/errors.d.ts +24 -8
- package/dist/tools/connections/errors.d.ts.map +1 -1
- package/dist/tools/connections/limits.d.ts +11 -31
- package/dist/tools/connections/limits.d.ts.map +1 -1
- package/dist/tools/connections/mcp-client.d.ts +6 -4
- package/dist/tools/connections/mcp-client.d.ts.map +1 -1
- package/dist/tools/connections/mcp.d.ts.map +1 -1
- package/dist/tools/connections/openapi.d.ts.map +1 -1
- package/dist/tools/connections/operation-limits.d.ts +25 -0
- package/dist/tools/connections/operation-limits.d.ts.map +1 -0
- package/dist/tools/connections/sse-frames.d.ts +11 -2
- package/dist/tools/connections/sse-frames.d.ts.map +1 -1
- package/dist/tools/connections/sse-session.d.ts +15 -2
- package/dist/tools/connections/sse-session.d.ts.map +1 -1
- package/dist/tools/connections/types.d.ts +19 -1
- package/dist/tools/connections/types.d.ts.map +1 -1
- package/dist/tools/execute-result.d.ts.map +1 -1
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/internal/observe-hook.d.ts +3 -0
- package/dist/tools/internal/observe-hook.d.ts.map +1 -0
- package/dist/tools/internal/surface-projector.d.ts +2 -1
- package/dist/tools/internal/surface-projector.d.ts.map +1 -1
- package/dist/tools/mcp/mount.d.ts +2 -2
- package/dist/tools/mcp/mount.d.ts.map +1 -1
- package/dist/tools/mcp/prepare.d.ts +4 -5
- package/dist/tools/mcp/prepare.d.ts.map +1 -1
- package/dist/tools/mcp/register.d.ts +4 -1
- package/dist/tools/mcp/register.d.ts.map +1 -1
- package/dist/tools/mcp/runtime-tools.d.ts.map +1 -1
- package/dist/tools/remote.d.ts.map +1 -1
- package/dist/tools/runtime-tool-execution.d.ts +65 -0
- package/dist/tools/runtime-tool-execution.d.ts.map +1 -0
- package/dist/tools/runtime-tool-mcp.d.ts +27 -0
- package/dist/tools/runtime-tool-mcp.d.ts.map +1 -0
- package/dist/tools/runtime-tool.d.ts +9 -60
- package/dist/tools/runtime-tool.d.ts.map +1 -1
- package/dist/tools/surface.d.ts +12 -14
- package/dist/tools/surface.d.ts.map +1 -1
- package/llms/application.2.txt +221 -44
- package/llms/application.3.txt +3 -1
- package/llms/application.txt +1 -1
- package/llms/cli.2.txt +144 -1
- package/llms/cli.txt +123 -104
- package/llms/contract.txt +1 -1
- package/llms/files-packaging.txt +27 -0
- package/llms/process.txt +63 -1
- package/llms/server.4.txt +4 -1
- package/llms/server.5.txt +1 -0
- package/llms/stitchkit.2.txt +14 -0
- package/llms/stitchkit.txt +6 -4
- package/llms/telegram.txt +64 -2
- package/llms/tools-connections.txt +3 -0
- package/llms/tools-mcp.txt +29 -0
- package/llms/tools.2.txt +59 -0
- package/llms/tools.3.txt +1 -0
- package/llms/tools.txt +11 -52
- package/llms/upgrading-0.37.0-0.44.0.txt +444 -0
- package/llms/{upgrading-0.44.0-0.60.0.txt → upgrading-0.44.0-0.61.0.txt} +140 -271
- package/llms/{upgrading-0.61.0-0.74.0.txt → upgrading-0.62.0-0.80.0.txt} +217 -140
- package/llms/{upgrading-0.75.0-0.103.0.txt → upgrading-0.81.0-0.104.0.txt} +154 -217
- package/llms/upgrading.txt +4 -4
- package/llms-full.txt +745 -60
- package/llms.txt +14 -12
- package/native-assets.json +8 -0
- package/package.json +12 -3
- package/dist/index-wykebpn9.js +0 -221
- package/llms/upgrading-0.37.0.txt +0 -176
- package/dist/{index-69nvze1q.js → index-pptyv13k.js} +3 -3
package/llms-full.txt
CHANGED
|
@@ -54,12 +54,14 @@ own, recorded as an ADR.
|
|
|
54
54
|
| `stitchkit/server` | server (Bun) | stable | `createServer`, `implement`, hooks, auth, Socket.IO server, server primitives |
|
|
55
55
|
| `stitchkit/node` | server (Node ≥ 22) | stable | `serveNode` + the runtime-agnostic core — the Node mirror of `/server` |
|
|
56
56
|
| `stitchkit/tools` | server | stable | `createMcpHandler`, `mountMcp`, `mountAgent`, the OAuth provider, native tools |
|
|
57
|
+
| `stitchkit/tools/mcp` | server (Bun or Node) | evolving | the canonical MCP HTTP/stdio server, schemas and typed MCP presenters; only Zod and the MCP server SDK peers |
|
|
57
58
|
| `stitchkit/tools/contract` | browser + server | evolving | the shapes a tool surface speaks — async-operation contract, snapshot and cancel schemas, view-file input/output — without the runtime that serves them |
|
|
58
59
|
| `stitchkit/tools/invoker` | server | stable | peer-free `createToolInvoker` over the canonical contract tool runner |
|
|
59
60
|
| `stitchkit/tools/connections` | server (Bun or Node) | evolving | consume external MCP servers and a bounded OpenAPI subset — typed reauthorization, a per-request host fence and per-call credentials |
|
|
60
|
-
| `stitchkit/cli` | server | stable | `createCli` —
|
|
61
|
+
| `stitchkit/cli` | server | stable | `createCli` / `createCliInvoker` — runtime and strict NodeNext declarations without MCP SDK / `ai` |
|
|
61
62
|
| `stitchkit/remote` | browser **and** server | stable | peer-free `implementRemote` for thin HTTP proxy processes |
|
|
62
63
|
| `stitchkit/process` | server (Bun or Node, POSIX) | evolving | finite native commands, byte sinks, bounded capture and process-group cancellation |
|
|
64
|
+
| `stitchkit/files/packaging` | build time (Bun or Node) | evolving | installed native asset graph, integrity and Bun packaging plugin; no runtime install policy |
|
|
63
65
|
| `stitchkit/files` | server (Bun or Node) | stable | peer-free managed local-file boundary |
|
|
64
66
|
| `stitchkit/telegram` | server (Bun or Node) | evolving | peer-free Telegram platform primitives — Mini App `initData` verification, send-failure classification, resumable broadcasts, the operator channel with dedupe, local Bot API files, webhook ownership and durable webhook update intake |
|
|
65
67
|
| `stitchkit/telegram/html` | browser and server | evolving | Telegram's HTML as a tree — clean any markup to what Telegram accepts, cut long text into valid parts by what the reader sees, check markup before it is sent |
|
|
@@ -71,12 +73,12 @@ own, recorded as an ADR.
|
|
|
71
73
|
| `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
|
|
72
74
|
| `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
|
|
73
75
|
| `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
|
|
74
|
-
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the
|
|
76
|
+
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the 49 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
|
|
75
77
|
| `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, plus the managed-resource conformance kit |
|
|
76
78
|
| `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
|
|
77
79
|
| `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
|
|
78
80
|
| `stitchkit/react/keyboard` | browser | evolving | which part of a screen gets a key — ordered layers, one Escape per level, list zones with real focus; see [keyboard guide](keyboard.md) |
|
|
79
|
-
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 22 of the
|
|
81
|
+
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 22 of the 49 minors since 0.56.2, most recently 0.97.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
|
|
80
82
|
| `stitchkit/agent-runtime/sandbox` | server | evolving | optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see [sandbox guide](sandbox.md) |
|
|
81
83
|
| `stitchkit/agent-runtime/testing` | tests on Bun or Node | evolving | credential-free replay, scripted provider faults, deterministic race controls and the agent-store conformance kit |
|
|
82
84
|
| `stitchkit/agent-runtime/harness` | server | evolving | resource-aware process-local facade over the canonical Agent runtime; supervision stays outside |
|
|
@@ -89,7 +91,7 @@ own, recorded as an ADR.
|
|
|
89
91
|
| `stitchkit/agent-runtime/sqlite/bun` | server (Bun) | evolving | durable built-in SQLite store for the agent runtime |
|
|
90
92
|
| `stitchkit/agent-runtime/sqlite/node` | server (Node ≥ 22.5) | evolving | durable built-in SQLite store for the agent runtime |
|
|
91
93
|
| `stitchkit-tui` | terminal (Bun) | evolving | optional official OpenTUI host over a caller-composed headless runtime |
|
|
92
|
-
| `stitchkit/application` | browser + server | evolving<br>_redefined in
|
|
94
|
+
| `stitchkit/application` | browser + server | evolving<br>_redefined in 12 of the 49 minors since 0.56.2, most recently 0.104.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
|
|
93
95
|
| `stitchkit/application/grammy` | server | evolving | a grammY bot as application resources — configuration, then polling with updates admitted by batch — and the webhook adapter |
|
|
94
96
|
| `stitchkit/application/opentelemetry` | server | evolving | maps application snapshots onto an injected OpenTelemetry `Meter` |
|
|
95
97
|
| `stitchkit/application/schemas` | browser + server | evolving | the application's snapshot, health and shutdown schemas alone, without the kernel |
|
|
@@ -3131,6 +3133,13 @@ URLs.
|
|
|
3131
3133
|
|
|
3132
3134
|
## `ApiError`
|
|
3133
3135
|
|
|
3136
|
+
On native Bun, both client paths disable Bun's separate socket idle timer while preserving
|
|
3137
|
+
the framework deadline and caller signal. A long declared deadline therefore remains the
|
|
3138
|
+
request policy. Explicit or patched fetch implementations, including Next, keep their own
|
|
3139
|
+
transport behavior; Node and browsers receive no Bun-specific fetch options. Raw responses
|
|
3140
|
+
and contract streams retain their existing header timeout and caller-owned body lifetime.
|
|
3141
|
+
See [Bun's idle timeout contract](https://bun.sh/reference/globals/BunFetchRequestInit/timeout).
|
|
3142
|
+
|
|
3134
3143
|
A non-2xx response is thrown as an `ApiError`:
|
|
3135
3144
|
|
|
3136
3145
|
```ts
|
|
@@ -3145,6 +3154,7 @@ try {
|
|
|
3145
3154
|
err.message // 'Note not found'
|
|
3146
3155
|
err.details // structured details, if any
|
|
3147
3156
|
err.hint // optional hint
|
|
3157
|
+
err.retryable // optional explicit recommendation, true or false
|
|
3148
3158
|
err.traceId // x-request-id — correlate this failure with backend logs
|
|
3149
3159
|
err.cause // concrete injected transport failure, when delivery failed
|
|
3150
3160
|
}
|
|
@@ -3158,6 +3168,12 @@ browser code can read it through Stitchkit's default CORS expose list; a custom
|
|
|
3158
3168
|
|
|
3159
3169
|
The error model is shared with the server — see [Auth & errors](./auth-and-errors.md).
|
|
3160
3170
|
|
|
3171
|
+
`retryable` preserves an explicit boolean in the server error envelope; an absent declaration
|
|
3172
|
+
remains absent. This metadata does not change the HTTP transport retry policy. The existing
|
|
3173
|
+
seventh constructor argument remains `ErrorOptions`, including `cause`; the optional
|
|
3174
|
+
retryability argument is eighth. Closed error/frame schemas must accept the new optional
|
|
3175
|
+
field before their producer declares it.
|
|
3176
|
+
|
|
3161
3177
|
## Auth events
|
|
3162
3178
|
|
|
3163
3179
|
The HTTP client emits events your app can react to globally:
|
|
@@ -3611,13 +3627,20 @@ get the view's defaults and projected answer, which is what `collectTools` and
|
|
|
3611
3627
|
|
|
3612
3628
|
## MCP — `createMcpHandler`
|
|
3613
3629
|
|
|
3630
|
+
An MCP-only server imports `stitchkit/tools/mcp` and installs
|
|
3631
|
+
`stitchkit`, `zod` and `@modelcontextprotocol/server`. The leaf's runtime and strict
|
|
3632
|
+
NodeNext declarations require no `ai`. It exports the existing HTTP/stdio server,
|
|
3633
|
+
schema policy, catalog and resource helpers; their implementation and security are shared
|
|
3634
|
+
with the full `stitchkit/tools` barrel. Use that full barrel when the application also
|
|
3635
|
+
needs its AI SDK features.
|
|
3636
|
+
|
|
3614
3637
|
`createMcpHandler` builds a complete stateless Streamable-HTTP MCP endpoint on
|
|
3615
3638
|
the official TypeScript SDK v2 server package. It owns server creation,
|
|
3616
3639
|
protocol-era negotiation and shutdown; application code does not import the SDK
|
|
3617
3640
|
to mount a normal endpoint.
|
|
3618
3641
|
|
|
3619
3642
|
```ts
|
|
3620
|
-
import { createMcpHandler, createMcpHttpRoute } from 'stitchkit/tools'
|
|
3643
|
+
import { createMcpHandler, createMcpHttpRoute } from 'stitchkit/tools/mcp'
|
|
3621
3644
|
import { createServer } from 'stitchkit/server'
|
|
3622
3645
|
|
|
3623
3646
|
const mcp = createMcpHandler({
|
|
@@ -3751,7 +3774,7 @@ Every advertised tool and every tool result therefore carries the fingerprint of
|
|
|
3751
3774
|
the catalog it came from:
|
|
3752
3775
|
|
|
3753
3776
|
```ts
|
|
3754
|
-
import { readMcpCatalogStamp } from 'stitchkit/tools';
|
|
3777
|
+
import { readMcpCatalogStamp } from 'stitchkit/tools/mcp';
|
|
3755
3778
|
|
|
3756
3779
|
const listed = await client.listTools();
|
|
3757
3780
|
let known = readMcpCatalogStamp(listed.tools[0]?._meta); // { digest, tools }
|
|
@@ -4256,7 +4279,7 @@ If you already run an `McpServer` from the SDK, `mountMcp` adds contract tools
|
|
|
4256
4279
|
to it instead of owning the lifecycle:
|
|
4257
4280
|
|
|
4258
4281
|
```ts
|
|
4259
|
-
import { mountMcp } from 'stitchkit/tools'
|
|
4282
|
+
import { mountMcp } from 'stitchkit/tools/mcp'
|
|
4260
4283
|
|
|
4261
4284
|
mountMcp(mcpServer, [usersService], { context: { source: 'mcp' } })
|
|
4262
4285
|
```
|
|
@@ -4272,7 +4295,7 @@ client (Claude Desktop, Claude Code, Cursor, Codex), on the user's machine, so
|
|
|
4272
4295
|
it can reach the local filesystem.
|
|
4273
4296
|
|
|
4274
4297
|
```ts
|
|
4275
|
-
import { bindStdioProcessSignals, createStdioMcpServer } from 'stitchkit/tools'
|
|
4298
|
+
import { bindStdioProcessSignals, createStdioMcpServer } from 'stitchkit/tools/mcp'
|
|
4276
4299
|
|
|
4277
4300
|
const stdio = await createStdioMcpServer({
|
|
4278
4301
|
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
@@ -4427,7 +4450,7 @@ through the contract's typed client:
|
|
|
4427
4450
|
```ts
|
|
4428
4451
|
import { createHttpClient } from 'stitchkit'
|
|
4429
4452
|
import { implementRemote } from 'stitchkit/remote'
|
|
4430
|
-
import { createStdioMcpServer } from 'stitchkit/tools'
|
|
4453
|
+
import { createStdioMcpServer } from 'stitchkit/tools/mcp'
|
|
4431
4454
|
|
|
4432
4455
|
const http = createHttpClient({
|
|
4433
4456
|
baseUrl: 'https://api.example.com',
|
|
@@ -4453,6 +4476,17 @@ no duplicated business logic.
|
|
|
4453
4476
|
`transformArgs` hook that rewrites a call's arguments before they are forwarded
|
|
4454
4477
|
— e.g. to upload a local file referenced in the args and swap in its URL.
|
|
4455
4478
|
|
|
4479
|
+
The call's signal reaches the existing typed HTTP client's request options, for endpoints
|
|
4480
|
+
with or without arguments. An already cancelled call, including cancellation while an async
|
|
4481
|
+
argument transform runs, dispatches no request. Bind your process signal to `createCli` or
|
|
4482
|
+
`createCliInvoker`; `REQUEST_ABORTED` is a safe nonretryable failure with CLI exit130.
|
|
4483
|
+
Cooperative origins observe `ctx.signal` and release resources when their work ends. An
|
|
4484
|
+
origin or provider ignoring cancellation may continue after the local wait stops.
|
|
4485
|
+
|
|
4486
|
+
An explicit `AppError.retryable` boolean also survives this remote hop. `false` on502 and
|
|
4487
|
+
`true` on409 remain the application's recommendation through HTTP, CLI, MCP and AI tools.
|
|
4488
|
+
Absent metadata keeps the previous defaults and does not alter HTTP transport retries.
|
|
4489
|
+
|
|
4456
4490
|
## Structured output
|
|
4457
4491
|
|
|
4458
4492
|
When a contract endpoint or runtime tool declares `output`, its MCP tool
|
|
@@ -6809,7 +6843,7 @@ description: Compose process-local resources, schedules, readiness, drain and op
|
|
|
6809
6843
|
type: architecture
|
|
6810
6844
|
status: active
|
|
6811
6845
|
created: 2026-08-23
|
|
6812
|
-
updated: 2026-
|
|
6846
|
+
updated: 2026-10-04 13:28 +07:00
|
|
6813
6847
|
---
|
|
6814
6848
|
|
|
6815
6849
|
# Managed application kernel
|
|
@@ -7792,49 +7826,101 @@ deadline holds `stop()` — and so the resource's `force()` — for that one cal
|
|
|
7792
7826
|
so give the transport a timeout. Superseding a key that is being sent right now
|
|
7793
7827
|
does not recall it: the send completes, and only its receipt is not written.
|
|
7794
7828
|
|
|
7795
|
-
`createDirectoryInbox`
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
`
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7829
|
+
`createDirectoryInbox` receives entries from another program on the same host,
|
|
7830
|
+
or directly from a transport adapter. Import the resource from
|
|
7831
|
+
`stitchkit/application/directory-inbox`; its contracts live in
|
|
7832
|
+
`stitchkit/application`. Its published handle has `accept({ source, key, entry })`,
|
|
7833
|
+
`flush()` and `state()`:
|
|
7834
|
+
|
|
7835
|
+
```ts
|
|
7836
|
+
const inbox = createDirectoryInbox({
|
|
7837
|
+
id: 'updates',
|
|
7838
|
+
directory: env.INBOX_DIRECTORY,
|
|
7839
|
+
schema: UpdateSchema,
|
|
7840
|
+
handle: ({ identity, entry, signal }) => processUpdate(identity, entry, signal),
|
|
7841
|
+
})
|
|
7842
|
+
const ingress = defineManagedResource({
|
|
7843
|
+
id: 'ingress',
|
|
7844
|
+
dependsOn: [inbox],
|
|
7845
|
+
start(context) {
|
|
7846
|
+
const intake = context.use(inbox)
|
|
7847
|
+
return { value: (key: string, entry: Update) =>
|
|
7848
|
+
intake.accept({ source: 'client-updates', key, entry }) }
|
|
7849
|
+
},
|
|
7850
|
+
})
|
|
7851
|
+
```
|
|
7852
|
+
|
|
7853
|
+
`accept` is available after the resource starts, including before activation.
|
|
7854
|
+
It validates the entry and full producer identity, writes a lossless JSON envelope,
|
|
7855
|
+
syncs its file and parent directory, then returns
|
|
7856
|
+
`{ status: 'accepted' | 'duplicate', filename }`. Automatic delivery starts at
|
|
7857
|
+
`activate`; an explicit `flush()` is available before activation. A producer
|
|
7858
|
+
should acknowledge its provider only after acceptance resolves. Failure after
|
|
7859
|
+
publication can mean the entry was accepted but its acknowledgement was lost:
|
|
7860
|
+
retry the same identity, and `duplicate` keeps the original payload.
|
|
7861
|
+
|
|
7862
|
+
The identity is the pair `source` (1–128 characters) and `key` (1–1024 characters).
|
|
7863
|
+
A hash of the pair names the file; the full pair is retained inside its envelope
|
|
7864
|
+
and checked against existing files and records. Two sources may use the same key.
|
|
7865
|
+
The handler's legacy `key` remains the filename; programmatic entries additionally
|
|
7866
|
+
carry `identity`. No Telegram numeric update id or MTProto event shape is invented.
|
|
7867
|
+
|
|
7868
|
+
The default `maxPendingEntries: 1000` refuses new programmatic entries when the
|
|
7869
|
+
pending directory is full, without publishing another file; duplicate acceptance
|
|
7870
|
+
still succeeds. `maxEntryBytes` defaults to 1 MiB and counts the complete UTF-8
|
|
7871
|
+
envelope. A completed identity is deduplicated while its receipt is retained
|
|
7872
|
+
(`retain`, default 1000); a rejected envelope also deduplicates while its file
|
|
7873
|
+
remains in `rejected/`. Choose the retention and rejected-file cleanup policy to
|
|
7874
|
+
match the provider's replay window. Provider cursors, identity extraction and
|
|
7875
|
+
external-effect idempotency remain application responsibilities.
|
|
7876
|
+
|
|
7877
|
+
The original file-producer path also remains: atomically publish
|
|
7878
|
+
`<name>.json`, using a temporary name followed by a rename. Names starting with
|
|
7879
|
+
a dot are ignored; `intake-<64 hex characters>.json` is reserved for programmatic
|
|
7880
|
+
envelopes. Entries are delivered in filename order. The reader refuses unsafe
|
|
7881
|
+
leaf symlinks, multiple links and files changed during reading.
|
|
7882
|
+
`stopAdmission` stops new acceptance and delivery, `drain` waits for accepted
|
|
7883
|
+
storage operations and the handler in flight, and `force` aborts its handler
|
|
7884
|
+
signal. A handler ignoring that signal may still finish an external effect;
|
|
7885
|
+
the inbox leaves its entry unsettled rather than claiming it was cancelled.
|
|
7886
|
+
|
|
7887
|
+
Taken and done are separate durable records. Before `handle`, the entry is
|
|
7888
|
+
claimed with a unique expiring lease (`leaseMs`, default five minutes). A
|
|
7889
|
+
long handler renews that lease; an expired or replaced lease cannot complete,
|
|
7890
|
+
reject, retry or remove the successor's file. Success first commits a receipt,
|
|
7891
|
+
then removes only that file generation under a new protected transaction.
|
|
7892
|
+
A crash after receipt commit is recovered by cleanup without redelivery. A crash
|
|
7893
|
+
before receipt commit may redeliver: the guarantee is at least once, so use the
|
|
7894
|
+
full producer identity as the external idempotency key.
|
|
7895
|
+
|
|
7896
|
+
A throwing handler retries after a backoff from one second to five minutes.
|
|
7897
|
+
Schema failures, oversize files and `maxAttempts` exhaustion (default 20) are
|
|
7898
|
+
recorded before their files move to `rejected/`, with `onRejected` reporting the
|
|
7899
|
+
reason. The state defaults to `<directory>/.inbox-state.json`, or uses the supplied
|
|
7900
|
+
`store`. Manual file producers are responsible for atomic publication and capacity.
|
|
7901
|
+
|
|
7902
|
+
These primitives share the structural `StateStore`. `update` owns one atomic
|
|
7903
|
+
read/modify/write transaction and passes a `StateStoreUpdateContext` as the
|
|
7904
|
+
transition's second argument. Its `await context.assertHeld()` checks that the
|
|
7905
|
+
transaction is still active and its exclusive generation is still owned. A custom
|
|
7906
|
+
store must implement both real serialization/atomic commit and this guard;
|
|
7907
|
+
a no-op guard does not satisfy the contract. Ordinary one-argument transition
|
|
7908
|
+
callbacks remain valid.
|
|
7909
|
+
|
|
7910
|
+
On a server, `createFileStateStore` uses the same process-instance lock as
|
|
7911
|
+
`withExclusiveLock`, unique staging files and atomic directory-durable publication.
|
|
7912
|
+
`lockTimeoutMs` (default 10 s, zero means one attempt) bounds acquisition only.
|
|
7913
|
+
A live or unattributable owner is never replaced by age, including after an event
|
|
7914
|
+
loop stall or `SIGSTOP`; only a provably dead local process instance is reclaimed.
|
|
7915
|
+
Legacy readable pid/token records without a host are unknown owners and need
|
|
7916
|
+
operator recovery after the old writer is verified stopped.
|
|
7917
|
+
|
|
7918
|
+
`staleLockMs` and `retryMs` are removed and are refused at runtime. The current
|
|
7919
|
+
write removes its own staging file; unknown historical temporary files are
|
|
7920
|
+
preserved, without an age sweep. Directory durability requires a filesystem
|
|
7921
|
+
supporting directory sync (Linux and macOS); Windows is refused explicitly.
|
|
7922
|
+
Ledger corruption may be declared reconstructable; an outbox must fail closed
|
|
7923
|
+
rather than discard pending delivery.
|
|
7838
7924
|
|
|
7839
7925
|
## Recovering change subscriptions
|
|
7840
7926
|
|
|
@@ -8045,7 +8131,7 @@ description: Native IO для Bun и Node, с явно выбранной durabi
|
|
|
8045
8131
|
type: guide
|
|
8046
8132
|
status: active
|
|
8047
8133
|
created: 2026-10-01 20:44 +07:00
|
|
8048
|
-
updated: 2026-10-04
|
|
8134
|
+
updated: 2026-10-04 20:04 +07:00
|
|
8049
8135
|
participants:
|
|
8050
8136
|
- role: authored
|
|
8051
8137
|
harness: Codex
|
|
@@ -8323,6 +8409,68 @@ no recognized native error code, the stage stays `load`; the loader never infers
|
|
|
8323
8409
|
This delivery removes a runtime kernel installation; it does not remove the build-time
|
|
8324
8410
|
Stitchkit installation or create an independent lightweight npm package.
|
|
8325
8411
|
|
|
8412
|
+
## Public native packaging
|
|
8413
|
+
|
|
8414
|
+
Custom archives and installers use `stitchkit/files/packaging` at **build time**.
|
|
8415
|
+
`createNativePackaging` resolves the installed version and target addon with its original SHA256;
|
|
8416
|
+
its Bun-compatible plugin integrates that asset with the same lazy native loader.
|
|
8417
|
+
The leaf is evolving. It requires no optional peer or Bun ambient declarations for Node imports.
|
|
8418
|
+
It must run unbundled from its installed package, never from an application's runtime artifact.
|
|
8419
|
+
This contract is available from 0.104.1; versions 0.103.13–0.104.0 use the complete-output recipe
|
|
8420
|
+
in the previous section.
|
|
8421
|
+
|
|
8422
|
+
```ts
|
|
8423
|
+
import { createNativePackaging } from 'stitchkit/files/packaging'
|
|
8424
|
+
import { createHash } from 'node:crypto'
|
|
8425
|
+
import { copyFileSync, mkdirSync, readFileSync } from 'node:fs'
|
|
8426
|
+
import { dirname, join } from 'node:path'
|
|
8427
|
+
|
|
8428
|
+
const native = createNativePackaging({
|
|
8429
|
+
platform: 'darwin', architecture: 'arm64', delivery: 'companion',
|
|
8430
|
+
entryPath: 'app/native.js', assetPath: 'addons/owner.node',
|
|
8431
|
+
})
|
|
8432
|
+
if (native.state !== 'ready') throw new Error(native.code)
|
|
8433
|
+
const result = await Bun.build({
|
|
8434
|
+
entrypoints: ['src/native.ts'], target: 'node', format: 'esm',
|
|
8435
|
+
outdir: 'dist', naming: { entry: 'app/native.js' }, splitting: false,
|
|
8436
|
+
plugins: [native.plugin],
|
|
8437
|
+
})
|
|
8438
|
+
if (!result.success) throw new AggregateError(result.logs, 'Build failed')
|
|
8439
|
+
// Preserve every result.outputs file under dist, then add the selected companion.
|
|
8440
|
+
for (const asset of native.assets) {
|
|
8441
|
+
const bytes = readFileSync(asset.sourcePath)
|
|
8442
|
+
if (createHash('sha256').update(bytes).digest('hex') !== asset.sha256)
|
|
8443
|
+
throw new Error('Native asset changed during build')
|
|
8444
|
+
const destination = join('dist', asset.outputPath)
|
|
8445
|
+
mkdirSync(dirname(destination), { recursive: true })
|
|
8446
|
+
copyFileSync(asset.sourcePath, destination)
|
|
8447
|
+
}
|
|
8448
|
+
```
|
|
8449
|
+
|
|
8450
|
+
`entryPath` and `assetPath` are relative paths inside the application's output root, without
|
|
8451
|
+
absolute paths, traversal or overlapping file/directory paths. `entryPath` is fixed, without
|
|
8452
|
+
Bun naming templates such as `[dir]` or `[name]`. Companion JS builds require one entry, no splitting,
|
|
8453
|
+
and `naming.entry` exactly matching `entryPath`; the plugin rejects a mismatching layout.
|
|
8454
|
+
Choose any application layout; the framework does not prescribe an app directory or installer.
|
|
8455
|
+
Keep every bundler output, then verify copied addon bytes against the original SHA256.
|
|
8456
|
+
Archive the complete output directory with an integrity manifest, unpack to a clean directory,
|
|
8457
|
+
verify the same hashes there, and run offline without the build tree or `node_modules`.
|
|
8458
|
+
A digest provides integrity, not authenticity: signature and trust policy remain application-owned.
|
|
8459
|
+
|
|
8460
|
+
For a standalone executable use `delivery: 'embedded'` and the same plugin in `Bun.build`
|
|
8461
|
+
with `compile: { outfile: ... }`. Bun embeds the selected addon; `assets` identifies its
|
|
8462
|
+
original bytes for qualification, not a companion that must be installed beside the executable.
|
|
8463
|
+
Cross-builds must select the requested architecture explicitly; the artifact must run on that target.
|
|
8464
|
+
The installed package must contain that target's addon. No automatic fallback/downgrade occurs.
|
|
8465
|
+
|
|
8466
|
+
The API returns `unsupported` / `NATIVE_TARGET_UNSUPPORTED` for non-Darwin or unsupported
|
|
8467
|
+
architectures, and `missing` / `NATIVE_ASSET_MISSING` for a missing addon. Portable Linux libraries
|
|
8468
|
+
use their normal build, without a Darwin plugin; merely importing the build leaf loads no addon.
|
|
8469
|
+
Malformed inputs, unsupported metadata versions and other IO errors throw before packaging.
|
|
8470
|
+
Runtime missing/corrupt companions preserve the native `unavailable` result and safe stage/code
|
|
8471
|
+
from the existing observer; they never certify a dead owner. Preserve the raw cause internally.
|
|
8472
|
+
The plugin does not parse consumer JS or establish a second runtime native implementation.
|
|
8473
|
+
|
|
8326
8474
|
## Qualification boundaries
|
|
8327
8475
|
|
|
8328
8476
|
Native command cleanup owns the child before launch subscriptions are installed. Setup
|
|
@@ -8483,7 +8631,7 @@ description: Executable patterns for moving database, poller, queue and operatio
|
|
|
8483
8631
|
type: architecture
|
|
8484
8632
|
status: active
|
|
8485
8633
|
created: 2026-08-24
|
|
8486
|
-
updated: 2026-
|
|
8634
|
+
updated: 2026-10-04 13:28 +07:00
|
|
8487
8635
|
---
|
|
8488
8636
|
|
|
8489
8637
|
# Application migration recipes
|
|
@@ -8517,6 +8665,131 @@ The application still owns the client, ORM configuration, transactions,
|
|
|
8517
8665
|
migrations and reconnect policy. The executable recipe deliberately fails after
|
|
8518
8666
|
allocation and proves one rollback close.
|
|
8519
8667
|
|
|
8668
|
+
## Stateful clients, including MTProto
|
|
8669
|
+
|
|
8670
|
+
An application-owned client is an ordinary managed resource. Keep SDK creation,
|
|
8671
|
+
credentials, authorization and reconnect policy in the application; no Telegram
|
|
8672
|
+
client SDK is required by Stitchkit. Create a fresh client inside each `start`,
|
|
8673
|
+
publish it after connection/readiness succeeds, and share one memoized destroy
|
|
8674
|
+
promise between partial-start cleanup, `close` and `force`:
|
|
8675
|
+
|
|
8676
|
+
```ts
|
|
8677
|
+
let generation: { destroy(): Promise<void> } | undefined
|
|
8678
|
+
|
|
8679
|
+
const client = defineManagedResource({
|
|
8680
|
+
id: 'client',
|
|
8681
|
+
async start({ signal }) {
|
|
8682
|
+
const connection = createClient() // Your SDK and configuration.
|
|
8683
|
+
let destruction: Promise<void> | undefined
|
|
8684
|
+
const destroy = () => destruction ??= Promise.resolve()
|
|
8685
|
+
.then(() => connection.destroy())
|
|
8686
|
+
generation = { destroy }
|
|
8687
|
+
let ready = false
|
|
8688
|
+
let startFailure: unknown
|
|
8689
|
+
let startFailed = false
|
|
8690
|
+
let cleanupFailure: unknown
|
|
8691
|
+
let cleanupFailed = false
|
|
8692
|
+
try {
|
|
8693
|
+
await connection.connect(signal)
|
|
8694
|
+
await connection.assertReady()
|
|
8695
|
+
signal.throwIfAborted()
|
|
8696
|
+
ready = true
|
|
8697
|
+
} catch (error) {
|
|
8698
|
+
startFailure = error
|
|
8699
|
+
startFailed = true
|
|
8700
|
+
} finally {
|
|
8701
|
+
if (!ready) {
|
|
8702
|
+
try { await destroy() }
|
|
8703
|
+
catch (cleanup) {
|
|
8704
|
+
cleanupFailure = cleanup
|
|
8705
|
+
cleanupFailed = true
|
|
8706
|
+
}
|
|
8707
|
+
}
|
|
8708
|
+
}
|
|
8709
|
+
if (startFailed) {
|
|
8710
|
+
if (cleanupFailed) throw new AggregateError([startFailure, cleanupFailure],
|
|
8711
|
+
'Client startup and cleanup failed', { cause: startFailure })
|
|
8712
|
+
throw startFailure
|
|
8713
|
+
}
|
|
8714
|
+
return { value: connection }
|
|
8715
|
+
},
|
|
8716
|
+
close: () => generation?.destroy(),
|
|
8717
|
+
force: () => generation?.destroy(),
|
|
8718
|
+
})
|
|
8719
|
+
|
|
8720
|
+
const api = defineManagedResource({
|
|
8721
|
+
id: 'api',
|
|
8722
|
+
dependsOn: [client],
|
|
8723
|
+
start(context) {
|
|
8724
|
+
const connection = context.use(client)
|
|
8725
|
+
return { value: async () => {
|
|
8726
|
+
const lease = context.admission.acquire()
|
|
8727
|
+
if (!lease) throw new ApplicationAdmissionError()
|
|
8728
|
+
try { return await connection.invoke() }
|
|
8729
|
+
finally { lease.release() }
|
|
8730
|
+
} }
|
|
8731
|
+
},
|
|
8732
|
+
})
|
|
8733
|
+
```
|
|
8734
|
+
|
|
8735
|
+
`createClient` supplies a client whose `destroy` safely cleans partial connection
|
|
8736
|
+
setup; its adapter must honor cancellation or otherwise reconcile late SDK effects.
|
|
8737
|
+
The destroy cache belongs to one generation and is reset by the next `start`.
|
|
8738
|
+
Successful startup keeps the connection alive. Dependants start after readiness,
|
|
8739
|
+
requests acquire admission before invoking the client, and dependent HTTP resources
|
|
8740
|
+
close before the client. A subtree restart builds a new client and new dependants.
|
|
8741
|
+
|
|
8742
|
+
The packed-consumer fixture
|
|
8743
|
+
[`managed-client-composition.mjs`](../../packages/core/scripts/consumer-lane/fixtures/minimal/src/managed-client-composition.mjs)
|
|
8744
|
+
proves readiness/admission, partial startup, close order, forced cleanup and restart
|
|
8745
|
+
with a fake client on Bun and Node. It does not claim a live provider acceptance test.
|
|
8746
|
+
|
|
8747
|
+
## Custom StateStore transaction guards
|
|
8748
|
+
|
|
8749
|
+
Transitions now receive `(current, context)`. Keep ordinary callbacks that only use
|
|
8750
|
+
`current`; update custom store implementations to pass a real protected context.
|
|
8751
|
+
For an in-memory test store, queue transactions and invalidate the context when
|
|
8752
|
+
the transaction finishes:
|
|
8753
|
+
|
|
8754
|
+
```ts
|
|
8755
|
+
function memoryStore<T>(): StateStore<T> {
|
|
8756
|
+
let state: T | null = null
|
|
8757
|
+
let tail: Promise<unknown> = Promise.resolve()
|
|
8758
|
+
return {
|
|
8759
|
+
read: async () => state,
|
|
8760
|
+
update(transition) {
|
|
8761
|
+
const work = tail.then(async () => {
|
|
8762
|
+
let active = true
|
|
8763
|
+
const context: StateStoreUpdateContext = {
|
|
8764
|
+
async assertHeld() {
|
|
8765
|
+
if (!active) throw new Error('Transaction is no longer active')
|
|
8766
|
+
},
|
|
8767
|
+
}
|
|
8768
|
+
try {
|
|
8769
|
+
const next = await transition(state, context)
|
|
8770
|
+
await context.assertHeld()
|
|
8771
|
+
state = next.state
|
|
8772
|
+
return next.result
|
|
8773
|
+
} finally { active = false }
|
|
8774
|
+
})
|
|
8775
|
+
tail = work.catch(() => undefined)
|
|
8776
|
+
return work
|
|
8777
|
+
},
|
|
8778
|
+
}
|
|
8779
|
+
}
|
|
8780
|
+
```
|
|
8781
|
+
|
|
8782
|
+
This recipe is process-local and has no restart durability. A database store must
|
|
8783
|
+
guard its real transaction/generation and commit atomically; an escaped or lost
|
|
8784
|
+
guard must refuse. Filesystem mutations made inside inbox transactions call
|
|
8785
|
+
`assertHeld` immediately before publication or cleanup.
|
|
8786
|
+
|
|
8787
|
+
For `createFileStateStore`, remove `staleLockMs` and `retryMs` from configuration.
|
|
8788
|
+
`lockTimeoutMs` remains the acquisition budget. Timestamp age no longer revokes
|
|
8789
|
+
a live or unknown writer. Stop and verify old writers before recovering a legacy
|
|
8790
|
+
pid-only lock; do not invent owner metadata. Historical temporary files are no
|
|
8791
|
+
longer deleted by age. See the [durable intake contract](application-kernel.md#durable-process-facts-and-owner-notifications).
|
|
8792
|
+
|
|
8520
8793
|
## Long-running poller
|
|
8521
8794
|
|
|
8522
8795
|
Return separate readiness and completion promises. Readiness says dependants may
|
|
@@ -8756,6 +9029,46 @@ It exists for what the other three surfaces cannot do: a generation kicked off
|
|
|
8756
9029
|
with `Bash(run_in_background)` that notifies on exit, a `SKILL.md` that shells
|
|
8757
9030
|
out in one line, a pipeable terminal command.
|
|
8758
9031
|
|
|
9032
|
+
## Installation and types
|
|
9033
|
+
|
|
9034
|
+
Install `stitchkit` and `zod` for a CLI. The public `stitchkit/cli` runtime and
|
|
9035
|
+
declarations do not require `ai`, the MCP SDK or Bun globals. Node consumers can
|
|
9036
|
+
use strict `NodeNext` resolution with `skipLibCheck: false` and ordinary Node
|
|
9037
|
+
types; the package keeps its required dependencies separate from optional SDKs.
|
|
9038
|
+
|
|
9039
|
+
CLI runtime tools use the shared executable contract: identity, input and output
|
|
9040
|
+
schemas, handler, and explicit CLI exposure. SDK presenters belong to the MCP/AI
|
|
9041
|
+
definitions in `stitchkit/tools`, which require the corresponding peers. A typed
|
|
9042
|
+
definition returned by `defineRuntimeTool` or `createRuntimeToolFactory` can be
|
|
9043
|
+
passed directly to both CLI and SDK mounts.
|
|
9044
|
+
|
|
9045
|
+
Keep transport-specific `present` on that typed SDK definition, rather than on
|
|
9046
|
+
an inline object in `CliConfig.runtimeTools`. CLI never executes those presenters;
|
|
9047
|
+
its neutral configuration does not validate SDK presentation. Native CLI command
|
|
9048
|
+
presentation remains on `defineCliCommand({ present })` and retains its inferred
|
|
9049
|
+
output type.
|
|
9050
|
+
|
|
9051
|
+
For a CLI-only managed tool, use the neutral generic construction contract to
|
|
9052
|
+
infer the handler from its schemas:
|
|
9053
|
+
|
|
9054
|
+
```ts
|
|
9055
|
+
import type { RuntimeToolExecutionWithOutput } from 'stitchkit/cli'
|
|
9056
|
+
import { z } from 'zod'
|
|
9057
|
+
|
|
9058
|
+
const input = z.object({ text: z.string() })
|
|
9059
|
+
const output = z.object({ size: z.number() })
|
|
9060
|
+
const measure = {
|
|
9061
|
+
name: 'measure', description: 'Measure text',
|
|
9062
|
+
identity: { serviceName: 'text', action: 'measure', method: 'POST' },
|
|
9063
|
+
transports: ['CLI'], input, output,
|
|
9064
|
+
handler: ({ input }) => ({ size: input.text.length }),
|
|
9065
|
+
} satisfies RuntimeToolExecutionWithOutput<typeof input, typeof output>
|
|
9066
|
+
```
|
|
9067
|
+
|
|
9068
|
+
Pass `measure` to `runtimeTools`. The heterogeneous registration type preserves
|
|
9069
|
+
the definition without inventing a common handler input; execute it through
|
|
9070
|
+
`createCli` or `createCliInvoker` so validation remains on the canonical path.
|
|
9071
|
+
|
|
8759
9072
|
## Exposure is opt-in
|
|
8760
9073
|
|
|
8761
9074
|
Unlike MCP and agent — where an endpoint with no `expose` is a tool by default —
|
|
@@ -9396,6 +9709,88 @@ manifest URL is configuration you wrote, while an asset URL arrives inside a
|
|
|
9396
9709
|
document the endpoint served, and a document is exactly what an SSRF boundary
|
|
9397
9710
|
exists to distrust.
|
|
9398
9711
|
|
|
9712
|
+
### Publishing a complete version
|
|
9713
|
+
|
|
9714
|
+
`publishCli` is an opt-in publisher for a local application-owned distribution
|
|
9715
|
+
directory. It commits every target and its version manifest before atomically
|
|
9716
|
+
replacing the public `manifest.json`. Your application selects the CLI source
|
|
9717
|
+
identity and admits that snapshot at each phase:
|
|
9718
|
+
|
|
9719
|
+
```ts
|
|
9720
|
+
import { publishCli } from 'stitchkit/cli'
|
|
9721
|
+
|
|
9722
|
+
const result = await publishCli({
|
|
9723
|
+
storageRoot: '/srv/myapp/cli',
|
|
9724
|
+
name: 'myapp', version: cliVersion, commit: selectedCliCommit,
|
|
9725
|
+
baseUrl: 'https://downloads.example.com/cli/',
|
|
9726
|
+
targets: [{ platform: 'linux', arch: 'x64' }],
|
|
9727
|
+
signal,
|
|
9728
|
+
admit: ({ phase, identity, signal }) => assertSelectedSource({ phase, identity, signal }),
|
|
9729
|
+
build: ({ target, stamp, signal }) => compileSelectedSource({ target, stamp, signal }),
|
|
9730
|
+
})
|
|
9731
|
+
// result.outcome: 'published' | 'existing'; result.manifest is ready to serve.
|
|
9732
|
+
```
|
|
9733
|
+
|
|
9734
|
+
The builder returns `Uint8Array` or `ReadableStream<Uint8Array>` containing the
|
|
9735
|
+
executable. Every target receives the same immutable `{ version, commit,
|
|
9736
|
+
builtAt }` stamp; carry it inside the binary. The publisher owns staging,
|
|
9737
|
+
gzip assets, paths and manifests. Callbacks receive the cancellation signal and
|
|
9738
|
+
run under the publication lock. Admission phases are `prepare`, each target's
|
|
9739
|
+
`build`, `commit`, and `promote`; validate the selected source through commit
|
|
9740
|
+
and promotion. A backend release can explicitly select an unchanged older CLI
|
|
9741
|
+
identity. The helper never substitutes a different commit or rebuilds an
|
|
9742
|
+
existing version under a new identity.
|
|
9743
|
+
|
|
9744
|
+
Assets live at `<version>/<name>-<platform>-<arch>.gz`, with an immutable
|
|
9745
|
+
`<version>/manifest.json` and a public `manifest.json`. A verified repeat keeps
|
|
9746
|
+
the exact bytes and `builtAt`, requires the same target set and base URL, and
|
|
9747
|
+
returns `existing` without invoking the builder. A version committed before a
|
|
9748
|
+
failed promotion is recovered and promoted without rebuilding. Conflicting
|
|
9749
|
+
same-version commits, downgrades, unsafe components, corrupt manifests and
|
|
9750
|
+
assets are refused. Version/name/target components are validated before any
|
|
9751
|
+
build; `storageRoot` is absolute and its existing parent must be trusted.
|
|
9752
|
+
|
|
9753
|
+
All limits are finite positive safe integers; `limits` overrides these defaults:
|
|
9754
|
+
|
|
9755
|
+
| Field | Default | Enforced boundary |
|
|
9756
|
+
| --- | --- | --- |
|
|
9757
|
+
| `maxTargets` | 16 | Requested and verified target count |
|
|
9758
|
+
| `maxManifestBytes` | 256 KiB | Read and written manifest bytes |
|
|
9759
|
+
| `maxAssetBytes` | 256 MiB | Builder and decompressed executable bytes |
|
|
9760
|
+
| `maxCompressedBytes` | 256 MiB | Archived asset bytes |
|
|
9761
|
+
| `maxDirectoryEntries` | 128 | Version layout, root scan and commit space |
|
|
9762
|
+
| `maxStoredVersions` | 16 | Verified publisher-owned history |
|
|
9763
|
+
| `lockTimeoutMs` | 10,000 | Wait to acquire the lock |
|
|
9764
|
+
| `timeoutMs` | 600,000 | Whole publication deadline |
|
|
9765
|
+
|
|
9766
|
+
`retention` defaults to 2 and keeps the current and previous published versions.
|
|
9767
|
+
It must be at least 2 and less than `maxStoredVersions` (at least 3), leaving a
|
|
9768
|
+
recovery slot. Older versions are pruned only after their own identity, exact
|
|
9769
|
+
layout, raw size and digest are verified. Runtime folders and foreign semver
|
|
9770
|
+
directories remain untouched. A full or unverifiable store refuses further
|
|
9771
|
+
publication; repeated completed candidates stay inside the owned history cap.
|
|
9772
|
+
Cancelled or failed incomplete staging is removed only while its root and
|
|
9773
|
+
directory generations still match. The shared asynchronous gzip decoder also
|
|
9774
|
+
bounds updater expansion by the declared raw size and configured byte cap.
|
|
9775
|
+
|
|
9776
|
+
The publisher rejects symlink roots/versions/assets, non-regular files and
|
|
9777
|
+
multiply linked files, and checks held-lock, root and prior-pointer generations
|
|
9778
|
+
before commit and promotion. This is cooperative publication under a trusted
|
|
9779
|
+
parent directory. Portable path checks do not provide an atomic comparison with
|
|
9780
|
+
a hostile process replacing ancestors between syscalls. Durability uses file
|
|
9781
|
+
and directory sync on POSIX; Windows publication is refused. A deadline stops
|
|
9782
|
+
callback/stream waits and blocks late promotion; trusted callbacks remain
|
|
9783
|
+
responsible for cancelling their own subprocesses and external effects.
|
|
9784
|
+
|
|
9785
|
+
A failure after an immutable commit reports that the publication outcome must
|
|
9786
|
+
be checked. A failure after public-pointer rename may already have published;
|
|
9787
|
+
`AtomicFilePublicationError.published` remains available when the atomic writer
|
|
9788
|
+
reports that boundary. Read the durable manifest and retry the admitted same
|
|
9789
|
+
identity to recover; an error does not promise rollback. Optional `signing` and
|
|
9790
|
+
`trust` reuse the Ed25519 contract below. The generated shell installer checks
|
|
9791
|
+
raw digest and size; the updater checks manifest authorship when given a trust
|
|
9792
|
+
root.
|
|
9793
|
+
|
|
9399
9794
|
### Proving who built it — signing the manifest
|
|
9400
9795
|
|
|
9401
9796
|
The asset digest proves the bytes that arrived are the bytes the manifest named.
|
|
@@ -9634,6 +10029,10 @@ const discovered = await mountConnections([
|
|
|
9634
10029
|
transport: { url },
|
|
9635
10030
|
token: () => key,
|
|
9636
10031
|
transports: ['CLI'], // the opt-in: this server's tools are commands
|
|
10032
|
+
limits: {
|
|
10033
|
+
discovery: { timeoutMs: 30_000, maxResponseBytes: 4 * 1024 * 1024 },
|
|
10034
|
+
call: { timeoutMs: 120_000 },
|
|
10035
|
+
},
|
|
9637
10036
|
}),
|
|
9638
10037
|
])
|
|
9639
10038
|
await createCli({ name: 'myapp', version, runtimeTools: discovered, commands: [...] })
|
|
@@ -9647,6 +10046,35 @@ One unconvertible schema no longer takes the connection down with it. The tool
|
|
|
9647
10046
|
is skipped and **named** (`onSkippedTool`, or a stderr line by default), so a
|
|
9648
10047
|
surface of two hundred tools is not lost to one.
|
|
9649
10048
|
|
|
10049
|
+
MCP connection limits follow the operation phase. `initialize`, the initialized
|
|
10050
|
+
notification, `tools/list` and legacy endpoint discovery use `limits.discovery`;
|
|
10051
|
+
`tools/call` uses `limits.call`. A mounted call's handshake still uses discovery
|
|
10052
|
+
limits. Each logical operation has one deadline, including initial transport
|
|
10053
|
+
negotiation and response-body reading. Legacy endpoint readiness has a discovery
|
|
10054
|
+
deadline; the lifetime of an established SSE stream does not.
|
|
10055
|
+
|
|
10056
|
+
Omitted phase fields inherit the existing connection-level `timeoutMs` and
|
|
10057
|
+
`maxResponseBytes`, whose defaults are 30 seconds and 1 MiB. Values must be positive
|
|
10058
|
+
safe integers; `timeoutMs` must also fit the runtime timer range. The byte ceiling
|
|
10059
|
+
counts raw UTF-8 body bytes, including SSE framing, regardless of `Content-Length`.
|
|
10060
|
+
Pending legacy calls also count comments and wrong-id frames. `budget.maxTools`
|
|
10061
|
+
and `budget.maxSchemaBytes` remain separate mount limits.
|
|
10062
|
+
|
|
10063
|
+
Only the initial `initialize` can negotiate HTTP-to-legacy fallback on 400, 404
|
|
10064
|
+
or 405. A failed `tools/call` is not replayed. Caller cancellation preserves its
|
|
10065
|
+
original reason for in-process observers.
|
|
10066
|
+
|
|
10067
|
+
Expected local failures produce safe tool errors: `CONNECTION_TIMEOUT` (exit 7),
|
|
10068
|
+
`CONNECTION_RESPONSE_TOO_LARGE` (exit 1), `UNAUTHORIZED` (exit 2), `FORBIDDEN`
|
|
10069
|
+
(exit 3) or `CONNECTION_REQUEST_FAILED` (exit 1). Deadline and response-limit
|
|
10070
|
+
failures include fixed `operation`/`phase`, the applicable bound and measured
|
|
10071
|
+
`observedReadBytes`. The public `ConnectionTimeoutError` and
|
|
10072
|
+
`ConnectionResponseTooLargeError` classes carry the same diagnostics. Raw URL,
|
|
10073
|
+
credential, body, identity and stack stay with the original in-process cause in
|
|
10074
|
+
`onToolError` / `afterToolCall`; tool errors produce no process console dump.
|
|
10075
|
+
Unknown throws remain `INTERNAL_SERVER_ERROR`. A timeout is not proof that a
|
|
10076
|
+
write did not happen: verify the remote outcome before repeating an operation.
|
|
10077
|
+
|
|
9650
10078
|
**A remote refusal keeps its code.** A failed `tools/call` used to become a
|
|
9651
10079
|
one-sentence `Error` with the result discarded, which cost three things at once:
|
|
9652
10080
|
the code (so `exitCodes` had nothing to map and every remote failure exited `1`),
|
|
@@ -11764,12 +12192,15 @@ error round-trips without adding correlation data to the response body.
|
|
|
11764
12192
|
A `code` is a free string — your app codes (`BOT_NOT_FOUND`, …) are yours and the
|
|
11765
12193
|
core never models them (ADR 0002). But stitchkit itself emits a set of its own:
|
|
11766
12194
|
`BAD_REQUEST`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `METHOD_NOT_ALLOWED`,
|
|
11767
|
-
`CONFLICT`, `RATE_LIMITED`, `
|
|
12195
|
+
`CONFLICT`, `RATE_LIMITED`, `REQUEST_ABORTED`, `REQUEST_TIMEOUT`,
|
|
12196
|
+
`VALIDATION_ERROR`, `FILE_INVALID_PATH`,
|
|
11768
12197
|
`FILE_OUTSIDE_ROOT`, `FILE_NOT_FOUND`, `FILE_NOT_REGULAR`,
|
|
11769
12198
|
`FILE_INSPECTION_REJECTED`, `FILE_TOO_LARGE`, `FILE_EXISTS`,
|
|
11770
12199
|
`REALTIME_CONTRACT_VIOLATION`, `APPLICATION_NOT_ACCEPTING`, `NOT_IMPLEMENTED`,
|
|
11771
12200
|
`WAIT_TIMEOUT`,
|
|
11772
12201
|
`WAIT_FAILED`, `DOWNLOAD_NOT_FOUND`, `VIEW_HTTP_ERROR`,
|
|
12202
|
+
`CONNECTION_TIMEOUT`, `CONNECTION_RESPONSE_TOO_LARGE`,
|
|
12203
|
+
`CONNECTION_REQUEST_FAILED`, `UPSTREAM_TOOL_ERROR`,
|
|
11773
12204
|
`OPERATION_NOT_SUCCEEDED`, `STREAM_ITEM_INVALID`, `STREAM_FRAME_TOO_LARGE`,
|
|
11774
12205
|
`STREAM_TERMINAL_MISSING`, `STREAM_LIFETIME_EXCEEDED`,
|
|
11775
12206
|
`GRAMMY_WEBHOOK_NOT_ACCEPTING`, `SANDBOX_UNAVAILABLE`, `SANDBOX_INSUFFICIENT`,
|
|
@@ -14222,7 +14653,8 @@ const report = await runTelegramBroadcast({
|
|
|
14222
14653
|
`retry_after` and sends the same recipient again; a server error is retried
|
|
14223
14654
|
with backoff up to `maxAttempts`, then `failed`. A message Telegram cannot
|
|
14224
14655
|
parse is not the recipient's fault: the run **halts** with them still pending,
|
|
14225
|
-
so the run after the fix reaches them.
|
|
14656
|
+
so the run after the fix reaches them. An unknown transport outcome becomes
|
|
14657
|
+
`uncertain` immediately and halts the run; resume never sends to that recipient again.
|
|
14226
14658
|
- **Pacing** is `ratePerSecond`, 25 by default. `dryRun` counts and writes
|
|
14227
14659
|
nothing. One runner per name: a second concurrent run is refused.
|
|
14228
14660
|
|
|
@@ -14231,6 +14663,66 @@ application (the application's signal, with admission held by the caller).
|
|
|
14231
14663
|
The recipient state contains Telegram ids: keep it in the state directory, out
|
|
14232
14664
|
of git.
|
|
14233
14665
|
|
|
14666
|
+
### Injecting another transport's failure policy
|
|
14667
|
+
|
|
14668
|
+
`classify(error)` returns the public `TelegramBroadcastFailure` union. It lets
|
|
14669
|
+
an application use its own client without adding that SDK to Stitchkit:
|
|
14670
|
+
|
|
14671
|
+
```ts
|
|
14672
|
+
const report = await runTelegramBroadcast({
|
|
14673
|
+
name: 'announcement',
|
|
14674
|
+
directory: env.STATE_DIRECTORY,
|
|
14675
|
+
recipients: () => audience.activeSubscribers(),
|
|
14676
|
+
send: ({ recipient }) => client.sendMessage(recipient, message),
|
|
14677
|
+
classify(error) {
|
|
14678
|
+
if (isFloodWait(error))
|
|
14679
|
+
return { kind: 'retry-after', retryAfterMs: error.seconds * 1000,
|
|
14680
|
+
reason: 'provider-rate-limit' }
|
|
14681
|
+
if (isRecipientGone(error))
|
|
14682
|
+
return { kind: 'permanent', recipientUnreachable: true,
|
|
14683
|
+
reason: 'recipient-gone' }
|
|
14684
|
+
return { kind: 'ambiguous', reason: 'unknown-provider-outcome' }
|
|
14685
|
+
},
|
|
14686
|
+
maxRetryDelayMs: 60_000,
|
|
14687
|
+
signal: stop.signal,
|
|
14688
|
+
})
|
|
14689
|
+
```
|
|
14690
|
+
|
|
14691
|
+
The four variants are `retry-after` (exact `retryAfterMs`), `transient` (bounded
|
|
14692
|
+
backoff), `permanent` (optionally `recipientUnreachable` or `stopBroadcast`), and
|
|
14693
|
+
`ambiguous`. Retry variants certify that the failed attempt had no external
|
|
14694
|
+
effect. Lack of an HTTP status does not establish that fact: a server may have
|
|
14695
|
+
accepted the message before the connection failed. `ambiguous` durably records
|
|
14696
|
+
`uncertain`, then halts; resuming the name skips that recipient.
|
|
14697
|
+
|
|
14698
|
+
`maxRetryDelayMs` defaults to 60 seconds. A provider wait above it halts with the
|
|
14699
|
+
recipient pending; it is never shortened to send early. `maxAttempts` is an
|
|
14700
|
+
integer from 1 to 100, `maxRetryDelayMs` is an integer from 0 to 2,147,483,647,
|
|
14701
|
+
and pacing/progress intervals must fit native timers. The optional
|
|
14702
|
+
`sleep(milliseconds, signal)` receives cancellation; the runner also stops waiting
|
|
14703
|
+
when the signal aborts if a custom sleeper ignores it. A send already in flight
|
|
14704
|
+
finishes and is recorded before stopping.
|
|
14705
|
+
|
|
14706
|
+
Without `classify`, known Bot API 429, unreachable-recipient, malformed-message
|
|
14707
|
+
and server-error behavior remains. Unknown/no-status failures now halt as
|
|
14708
|
+
uncertain, rather than being automatically retried. Existing custom `send`
|
|
14709
|
+
implementations that relied on those retries must supply an explicit classifier
|
|
14710
|
+
for proven pre-effect failures. `report.halt` now carries
|
|
14711
|
+
`TelegramBroadcastFailure`; inspect `halt.kind` instead of the old send-failure
|
|
14712
|
+
`scope`/`retryable` fields.
|
|
14713
|
+
|
|
14714
|
+
The runner uses the shared process-instance lock and checks its generation before
|
|
14715
|
+
sends and journal writes. The audience and initial journal directory entry are
|
|
14716
|
+
synced before sending. Lost ownership cannot write a stale delivered receipt or
|
|
14717
|
+
start another send; the persisted intent becomes uncertain on recovery. Old
|
|
14718
|
+
pid-only broadcast locks have unknown ownership and require recovery after their
|
|
14719
|
+
writers are verified stopped, rather than automatic age-based deletion.
|
|
14720
|
+
|
|
14721
|
+
The installed
|
|
14722
|
+
[`telegram-broadcast-classifier.mjs`](../../packages/core/scripts/consumer-lane/fixtures/minimal/src/telegram-broadcast-classifier.mjs)
|
|
14723
|
+
fixture checks injected rate limits, ambiguity/no resend, wait budgets and abort
|
|
14724
|
+
on Bun and Node without a client SDK.
|
|
14725
|
+
|
|
14234
14726
|
## Message markup
|
|
14235
14727
|
|
|
14236
14728
|
`stitchkit/telegram/html` is Telegram's HTML parse mode as a tree, with no peer
|
|
@@ -14827,6 +15319,157 @@ analytics policy belong to the application.
|
|
|
14827
15319
|
|
|
14828
15320
|
# Upgrading stitchkit
|
|
14829
15321
|
|
|
15322
|
+
## Released migration: 0.104.0
|
|
15323
|
+
|
|
15324
|
+
JS bundles carrying Darwin native capabilities also need the
|
|
15325
|
+
[delivery migration first affected in 0.103.13](#released-migration-010313).
|
|
15326
|
+
Consumers upgrading from 0.103.12 or earlier must apply it even if their TypeScript API is unchanged.
|
|
15327
|
+
|
|
15328
|
+
### CLI runtime-tool construction
|
|
15329
|
+
|
|
15330
|
+
**Who must act:** callers writing a schema-dependent handler or MCP/AI `present` directly
|
|
15331
|
+
inside an annotated `CliConfig.runtimeTools` or `CliInvokerConfig.runtimeTools` object.
|
|
15332
|
+
Native `commands` and values returned by `defineRuntimeTool` / `createRuntimeToolFactory`
|
|
15333
|
+
remain valid. Execution, auth, validation and the invocation result envelope keep their behavior.
|
|
15334
|
+
|
|
15335
|
+
Construct a CLI-only managed definition with the neutral schema-aware type before registration:
|
|
15336
|
+
|
|
15337
|
+
```ts
|
|
15338
|
+
import type { CliInvokerConfig, RuntimeToolExecutionWithOutput } from 'stitchkit/cli'
|
|
15339
|
+
import { z } from 'zod'
|
|
15340
|
+
|
|
15341
|
+
const input = z.object({ text: z.string() })
|
|
15342
|
+
const output = z.object({ size: z.number() })
|
|
15343
|
+
// Before: handler receives the heterogeneous registry context.
|
|
15344
|
+
const config: CliInvokerConfig = {
|
|
15345
|
+
name: 'app',
|
|
15346
|
+
runtimeTools: [{
|
|
15347
|
+
name: 'measure', description: 'Measure text',
|
|
15348
|
+
identity: { serviceName: 'text', action: 'measure', method: 'POST' },
|
|
15349
|
+
transports: ['CLI'], input, output,
|
|
15350
|
+
handler: ({ input }) => ({ size: String(input.text).length }),
|
|
15351
|
+
}],
|
|
15352
|
+
}
|
|
15353
|
+
// After: handler input and output derive from the construction schemas.
|
|
15354
|
+
const measure = {
|
|
15355
|
+
name: 'measure', description: 'Measure text',
|
|
15356
|
+
identity: { serviceName: 'text', action: 'measure', method: 'POST' },
|
|
15357
|
+
transports: ['CLI'], input, output,
|
|
15358
|
+
handler: ({ input }) => ({ size: input.text.length }),
|
|
15359
|
+
} satisfies RuntimeToolExecutionWithOutput<typeof input, typeof output>
|
|
15360
|
+
const nextConfig: CliInvokerConfig = { name: 'app', runtimeTools: [measure] }
|
|
15361
|
+
```
|
|
15362
|
+
|
|
15363
|
+
For a shared MCP/AI tool, construct the definition with `defineRuntimeTool` from
|
|
15364
|
+
`stitchkit/tools`, including its typed SDK `present` callbacks, then pass the returned value
|
|
15365
|
+
to `runtimeTools`. Install the corresponding SDK peers for that integration. A CLI-only
|
|
15366
|
+
consumer needs `stitchkit`, `zod` and its ordinary Node type tooling.
|
|
15367
|
+
|
|
15368
|
+
`RuntimeToolExecution` names the heterogeneous registration contract. Call a registered
|
|
15369
|
+
operation through `createCli` or `createCliInvoker`; its erased handler input is `never`
|
|
15370
|
+
because the managed runner owns schema validation before execution. For a managed void
|
|
15371
|
+
definition, use `RuntimeToolDefinitionWithoutOutput<typeof input>`.
|
|
15372
|
+
|
|
15373
|
+
### MCP construction, state stores and delivery
|
|
15374
|
+
|
|
15375
|
+
**Who must act:** schema-dependent runtime tool literals written directly inside MCP mount
|
|
15376
|
+
configuration, MCP presenters returning malformed content or metadata, custom `StateStore`
|
|
15377
|
+
implementations, file-store consumers using retired lock
|
|
15378
|
+
options, broadcast consumers reading `halt` or retrying unknown send outcomes, and consumers
|
|
15379
|
+
that validate HTTP error envelopes with a closed schema. Applications collecting raw tool
|
|
15380
|
+
causes from `console.error` must configure an internal tool hook sink.
|
|
15381
|
+
|
|
15382
|
+
MCP-only code can import the existing server factories from `stitchkit/tools/mcp` and
|
|
15383
|
+
construct its schema-aware tool before heterogeneous registration:
|
|
15384
|
+
|
|
15385
|
+
```ts
|
|
15386
|
+
import { buildMcpServer, type RuntimeMcpToolDefinitionWithOutput } from 'stitchkit/tools/mcp'
|
|
15387
|
+
import { z } from 'zod'
|
|
15388
|
+
const input = z.object({ value: z.number() })
|
|
15389
|
+
const output = z.object({ doubled: z.number() })
|
|
15390
|
+
// Before: runtimeTools: [{ input, output, handler, present }]
|
|
15391
|
+
const double = {
|
|
15392
|
+
name: 'double', description: 'Double a number',
|
|
15393
|
+
identity: { serviceName: 'numbers', action: 'double', method: 'POST' },
|
|
15394
|
+
input, output,
|
|
15395
|
+
handler: ({ input }) => ({ doubled: input.value * 2 }),
|
|
15396
|
+
present: { mcp: ({ doubled }) => ({ content: [{ type: 'text', text: String(doubled) }] }) },
|
|
15397
|
+
} satisfies RuntimeMcpToolDefinitionWithOutput<typeof input, typeof output>
|
|
15398
|
+
const server = buildMcpServer({ serverInfo: { name: 'numbers', version: '1' }, services: [], runtimeTools: [double] })
|
|
15399
|
+
```
|
|
15400
|
+
|
|
15401
|
+
Full MCP/AI integrations keep `defineRuntimeTool` from `stitchkit/tools`; those typed values
|
|
15402
|
+
remain accepted by the MCP leaf and CLI. The leaf requires the MCP SDK and Zod, with no AI peer.
|
|
15403
|
+
|
|
15404
|
+
`RuntimeMcpPresentation` preserves the official SDK's required `content` and typed `_meta`
|
|
15405
|
+
fields. A presenter returning `{}` must return `{ content: [] }`; text blocks require string
|
|
15406
|
+
text, and metadata must be an object. `structuredContent` and `isError` remain framework-owned.
|
|
15407
|
+
This restores SDK checks that an indexed mapped type previously erased.
|
|
15408
|
+
|
|
15409
|
+
Unexpected tool causes remain in `hooks.onToolError` and the `error` field of
|
|
15410
|
+
`hooks.afterToolCall`. Protocol stderr carries safe errors. MCP resolver failures use those
|
|
15411
|
+
same observers without executing the handler or its lifecycle again. HTTP's default
|
|
15412
|
+
unexpected-error logging retains its behavior.
|
|
15413
|
+
|
|
15414
|
+
A custom state adapter's `update` must invoke `transition(current, context)` while it still
|
|
15415
|
+
owns the serialized transaction. `context.assertHeld()` checks the actual transaction or lock
|
|
15416
|
+
generation and refuses after completion, rollback or ownership loss. A no-op guard cannot
|
|
15417
|
+
satisfy this contract. Existing transition callbacks may keep one parameter. For the owning
|
|
15418
|
+
file adapter, replace `{ staleLockMs, retryMs, lockTimeoutMs }` with `{ lockTimeoutMs }`:
|
|
15419
|
+
the remaining budget controls acquisition waiting, never expiry of a live transaction.
|
|
15420
|
+
Unknown legacy PID locks and historical temporary files are preserved; recover them only
|
|
15421
|
+
after independently proving their owner is gone.
|
|
15422
|
+
|
|
15423
|
+
Broadcast consumers change `report.halt.reason` checks to the closed `halt.kind` union:
|
|
15424
|
+
`retry-after`, `transient`, `permanent` or `ambiguous`. A custom MTProto adapter can classify
|
|
15425
|
+
an acknowledged flood refusal as `{ kind: 'retry-after', retryAfterMs: wait }`; the exact
|
|
15426
|
+
provider wait is respected. A wait over `maxRetryDelayMs` halts with the recipient pending.
|
|
15427
|
+
Unknown write outcome becomes `uncertain`; restarting the same broadcast does not send it
|
|
15428
|
+
again. A retry classification must certify that the attempt did not apply the external effect.
|
|
15429
|
+
|
|
15430
|
+
HTTP errors gain optional boolean `error.retryable`; framed contract streams use the same
|
|
15431
|
+
field. Update closed consumer schemas before producers declaring it. `false` on 502 and
|
|
15432
|
+
`true` on 409 remain explicit recommendations through the remote tool path. An absent field
|
|
15433
|
+
retains prior status-derived defaults; the field does not change the HTTP client's retry policy.
|
|
15434
|
+
The existing seventh `ApiError` constructor argument remains `ErrorOptions`; retryability is
|
|
15435
|
+
the new eighth argument.
|
|
15436
|
+
|
|
15437
|
+
Caller cancellation now reaches `implementRemote`'s existing HTTP call. Applications bind
|
|
15438
|
+
signals to `createCli` / `createCliInvoker` and cooperative handlers observe `ctx.signal`.
|
|
15439
|
+
`REQUEST_ABORTED` is nonretryable and exits 130. A disconnected caller does not prove that
|
|
15440
|
+
an origin ignoring cancellation or an external provider stopped; keep resource leases until
|
|
15441
|
+
that work actually completes.
|
|
15442
|
+
|
|
15443
|
+
## Released migration: 0.103.13
|
|
15444
|
+
|
|
15445
|
+
### Darwin native assets in JS distributions
|
|
15446
|
+
|
|
15447
|
+
**Who must act:** Bun JS builds using `--outfile`, copying only `outputs[0]`, custom
|
|
15448
|
+
single-file/archive packagers and installers delivering native process/files capabilities.
|
|
15449
|
+
First affected publication: **0.103.13**. It shipped as a patch; its changed delivery graph
|
|
15450
|
+
requires this migration despite unchanged API signatures.
|
|
15451
|
+
|
|
15452
|
+
```sh
|
|
15453
|
+
# Before: one JS file was assumed to be the entire distribution.
|
|
15454
|
+
bun build src/native.ts --target=bun --outfile=dist/native.js
|
|
15455
|
+
# After: retain every output, with its relative path.
|
|
15456
|
+
bun build src/native.ts --target=bun --outdir=dist --entry-naming=native.js
|
|
15457
|
+
```
|
|
15458
|
+
|
|
15459
|
+
For `Bun.build`, copy **all** `result.outputs`, not just the JS entry or `outputs[0]`.
|
|
15460
|
+
A single-file JS distribution cannot embed a native `.node` addon automatically.
|
|
15461
|
+
An archive may contain JS plus companion assets, materialized together before execution.
|
|
15462
|
+
Custom output layout uses the evolving build-only packaging contract in the
|
|
15463
|
+
[native IO guide](native-io.md#public-native-packaging).
|
|
15464
|
+
|
|
15465
|
+
Three deliveries have different rules: an ordinary npm install retains the package's
|
|
15466
|
+
native assets; a JS distribution must ship its complete output graph; a Bun compiled
|
|
15467
|
+
executable embeds the matching addon and may still use `--outfile`.
|
|
15468
|
+
The [native IO guide](native-io.md#libraries-with-a-zod-only-runtime) is the canonical recipe.
|
|
15469
|
+
Check the resulting artifact offline outside the build tree and `node_modules`, including
|
|
15470
|
+
process identity, live-owner lock refusal, dead-owner recovery and contained IO.
|
|
15471
|
+
A missing or corrupt addon remains `unavailable`, never evidence that an owner died.
|
|
15472
|
+
|
|
14830
15473
|
## Released migration: 0.103.0
|
|
14831
15474
|
|
|
14832
15475
|
### Diagnostic journal startup preserves torn evidence and inspects archives
|
|
@@ -19064,7 +19707,7 @@ from the root `stitchkit`.
|
|
|
19064
19707
|
| Export | Kind | Summary |
|
|
19065
19708
|
|--------|------|---------|
|
|
19066
19709
|
| `AppError` | class | the framework error — `code` / `status` / `details` / `hint` |
|
|
19067
|
-
| `ErrorEnvelope` | _type_ | the JSON shape of an error response |
|
|
19710
|
+
| `ErrorEnvelope` | _type_ | the JSON shape of an error response, preserving optional declared boolean `error.retryable` without changing HTTP retry policy |
|
|
19068
19711
|
| `notFound` | function | throw `404 NOT_FOUND` — [guide](../guide/auth-and-errors.md#throwing-errors) |
|
|
19069
19712
|
| `badRequest` | function | throw `400 BAD_REQUEST` |
|
|
19070
19713
|
| `unauthorized` | function | throw `401 UNAUTHORIZED` |
|
|
@@ -19227,6 +19870,7 @@ Also re-exports the error helpers from `stitchkit/contract`.
|
|
|
19227
19870
|
| `respondJson` | function | a raw route's JSON response (`204` for null/undefined) |
|
|
19228
19871
|
| `errorResponse` | function | any thrown value → the framework error envelope + `x-request-id` |
|
|
19229
19872
|
| `normalizeError` | function | any thrown value → an `AppError` (`ZodError` → `VALIDATION_ERROR` 400 with structured `details.issues`, else generic 500) — the framework's canonical classification, for a bespoke `onError` |
|
|
19873
|
+
| `NormalizeErrorOptions` | _type_ | `logUnexpected` defaults to logging the raw server-side cause; tool adapters disable process dumps while their existing observers retain that cause |
|
|
19230
19874
|
| `errorCode` | function | the stable error code for a thrown value (side-effect-free — for log attribution) |
|
|
19231
19875
|
| `formatZodError` | function | a `ZodError` → a readable, field-summarised string |
|
|
19232
19876
|
| `zodIssues` | function | a `ZodError` → structured `{ path, code, message }[]` — the machine-readable sibling of `formatZodError` |
|
|
@@ -19443,7 +20087,9 @@ cutovers are covered by the executable
|
|
|
19443
20087
|
| `NotificationOutboxItem` / `NotificationOutboxReceipt` / `NotificationOutboxState` / `NotificationSend` / `NotificationFailureClassification` / `DroppedNotification` / `EnqueueNotification` | _type_ | versioned queue records, stable send identity and delivery decisions |
|
|
19444
20088
|
| `notificationOutboxStateSchema` | function | strict persisted-state schema over an application payload schema |
|
|
19445
20089
|
| `notificationOutboxResource` / `NotificationOutboxResource` / `NotificationOutboxResourceConfig` | function / _type_ | thin managed-resource scheduler over an outbox handle |
|
|
19446
|
-
| `createDirectoryInbox` (from `stitchkit/application/directory-inbox`) / `DirectoryInbox` / `DirectoryInboxConfig` / `DirectoryInboxDelivery` / `DirectoryInboxResource` | function / _type_ | managed
|
|
20090
|
+
| `createDirectoryInbox` (from `stitchkit/application/directory-inbox`) / `DirectoryInbox` / `DirectoryInboxConfig` / `DirectoryInboxDelivery` / `DirectoryInboxResource` | function / _type_ | one managed directory inbox for files or durable `accept({ source, key, entry })`; first payload wins, bounded capacity/bytes/receipts and renewable fenced leases; delivery begins after readiness and effects remain at least once |
|
|
20091
|
+
| `DirectoryInboxIdentitySchema` / `DirectoryInboxIdentity` / `DirectoryInboxAccept` / `DirectoryInboxAcceptResultSchema` / `DirectoryInboxAcceptResult` | schema / _type_ | validated source/key, typed entry and durable accepted/duplicate result with filename; duplicates do not replace the first payload |
|
|
20092
|
+
| `StateStoreUpdateContext` | _type_ | real active protected transaction: `assertHeld()` refuses after ownership loss or completion; custom adapters supply this context to their transition |
|
|
19447
20093
|
| `DirectoryInboxStateSchema` / `DirectoryInboxState` / `DirectoryInboxRejection` / `DirectoryInboxRejectionReasonSchema` / `DirectoryInboxRejectionReason` | schema / _type_ | the inbox's claims, receipts and rejections (`invalid`, `too-large`, `attempt-limit`) |
|
|
19448
20094
|
| `ApplicationHandle.restart` | method | replace one resource and everything that depends on it, leaving the rest of the graph running and the process epoch unchanged |
|
|
19449
20095
|
| `ApplicationRestartInputSchema` / `ApplicationRestartInput` | schema / _type_ | the resource to replace, by id, and optionally `gracePeriodMs` / `forceTimeoutMs` for this restart — the application's own shutdown budget otherwise |
|
|
@@ -20628,6 +21274,7 @@ Advanced building blocks — the shared machinery the mounts are built on.
|
|
|
20628
21274
|
| `TransportSummary` | _type_ | `{ contractServices, runtimeTools, totals, sources }` from `summarizeTransports` |
|
|
20629
21275
|
| `TransportCounts` | _type_ | per-transport counts (`{ HTTP, MCP, AGENT, CLI }`) |
|
|
20630
21276
|
| `ToolSurfaceDefinition` | _type_ | shared object-shaped `{ services?, runtimeTools? }` introspection surface |
|
|
21277
|
+
| `ToolSurfaceProjection` | _type_ | one readonly services/runtime container shared by full and MCP-only surfaces; executable mounts specialize the runtime definition without pulling in another adapter's peers |
|
|
20631
21278
|
| `ToolManifestConfig` | _type_ | mixed surface plus required model-facing `transport` and presentation options |
|
|
20632
21279
|
| `coerceJsonArgs` | function | coerce JSON-stringified array/object tool arguments |
|
|
20633
21280
|
| `flattenToolJsonSchema` | function | project structurally identifiable discriminated unions into conservative object joins; scalar collisions retain provable types, object/array collisions retain structural alternatives, and field descriptions retain discriminator labels plus availability/requiredness hints; the projection never executes validation |
|
|
@@ -20637,6 +21284,22 @@ Advanced building blocks — the shared machinery the mounts are built on.
|
|
|
20637
21284
|
|
|
20638
21285
|
---
|
|
20639
21286
|
|
|
21287
|
+
## `stitchkit/tools/mcp`
|
|
21288
|
+
|
|
21289
|
+
A server-only leaf over the same MCP owner as `stitchkit/tools`. Its runtime and strict
|
|
21290
|
+
NodeNext declarations require Zod and `@modelcontextprotocol/server`, with no AI SDK peer.
|
|
21291
|
+
HTTP/stdio factories, mounts, schema policy, catalog and resource helpers keep their canonical
|
|
21292
|
+
behavior and names. See [MCP guide](../guide/mcp-and-agents.md#mcp--createmcphandler).
|
|
21293
|
+
|
|
21294
|
+
| Export | Kind | Purpose |
|
|
21295
|
+
|--------|------|---------|
|
|
21296
|
+
| `createMcpHandler` / `createMcpHttpRoute` / `buildMcpServer` / `mountMcp` | function | the shared authenticated HTTP handler, raw-route adapter, SDK server and contract mount |
|
|
21297
|
+
| `createStdioMcpServer` / `bindStdioProcessSignals` | function | the shared stdio server and bounded process cleanup |
|
|
21298
|
+
| `RuntimeMcpToolDefinitionWithOutput` | _type_ | schema-aware MCP-only construction with concrete handler output and presenter input |
|
|
21299
|
+
| `RuntimeMcpToolDefinition` | _type_ | heterogeneous MCP registration; the canonical runner validates input/output before invocation |
|
|
21300
|
+
| `RuntimeMcpToolPresenters` / `RuntimeMcpPresentation` | _type_ | official SDK content without framework-owned `structuredContent` or `isError`; one presenter owner shared with the full SDK surface |
|
|
21301
|
+
| `RuntimeToolDefinitionWithoutOutput` | _type_ | the shared neutral void definition |
|
|
21302
|
+
|
|
20640
21303
|
## `stitchkit/tools/connections`
|
|
20641
21304
|
|
|
20642
21305
|
Server-only subexport that consumes external MCP servers and OpenAPI specifications
|
|
@@ -20648,6 +21311,9 @@ and approval path.
|
|
|
20648
21311
|
| Export | Kind | Summary |
|
|
20649
21312
|
|--------|------|---------|
|
|
20650
21313
|
| `defineMcpClientConnection` | function | declare one external MCP server connection over Streamable HTTP with an optional SSE fallback |
|
|
21314
|
+
| `ConnectionOperationLimits` / `McpConnectionLimits` | _type_ | positive finite deadline/raw byte ceilings with independent discovery/call overrides; omitted fields inherit the shared bounds |
|
|
21315
|
+
| `ConnectionPhase` / `ConnectionOperation` / `ConnectionFailureContext` | _type_ | closed operation/phase vocabulary and measured read context for existing typed connection errors |
|
|
21316
|
+
| `ConnectionTimeoutError` / `ConnectionResponseTooLargeError` | class | bounded operation refusal, with phase, operation and finite observed bytes; safe tool projection retains the raw cause locally |
|
|
20651
21317
|
| `defineOpenApiConnection` | function | declare one OpenAPI document (object, JSON text or JSON URL) as a tool surface |
|
|
20652
21318
|
| `mountConnections` | function | discover every connection and return readonly `RuntimeToolDefinition`s for `mountAgent` |
|
|
20653
21319
|
| `ConnectionAuthorizationRequiredError` | class | typed reauthorization signal raised on `401` with credentials resolved again on the next call |
|
|
@@ -20787,8 +21453,9 @@ injected grammY bot. → ADR 0143, ADR 0201 — [guide](../guide/telegram.md)
|
|
|
20787
21453
|
| `classifyTelegramSendFailure` | function | name a refused Bot API send and separate "retry this send" from "stop addressing this recipient" |
|
|
20788
21454
|
| `TelegramSendFailure` | _type_ | reason, `status`, Telegram-stated `retryAfterSeconds`, `retryable`, `recipientUnreachable` and which evidence produced the answer |
|
|
20789
21455
|
| `TelegramSendFailureReason` / `TELEGRAM_SEND_FAILURE_REASONS` | _type_ / constant | `blocked-by-user` / `user-deactivated` / `chat-not-found` / `not-started` / `rate-limited` / `message-invalid` / `server-error` / `unknown`, and the same as a list; a `Record<TelegramSendFailureReason, …>` over them fails to compile when a reason is added |
|
|
20790
|
-
| `runTelegramBroadcast` | function | a resumable broadcast by `name` under a state `directory`: audience
|
|
21456
|
+
| `runTelegramBroadcast` | function | a resumable broadcast by `name` under a state `directory`: audience and journal durably recorded, pacing at `ratePerSecond` (25), exact retry delays within the finite declared budget, injected classifier, uncertain send outcomes never replayed, `dryRun`, one fenced runner per name |
|
|
20791
21457
|
| `TelegramBroadcastConfig` / `TelegramBroadcastSend` / `TelegramBroadcastReport` / `TelegramBroadcastRunOutcome` / `TelegramBroadcastOutcome` / `TelegramBroadcastRecipient` | _type_ | `name`, `directory`, `recipients()`, `send({ recipient, attempt })`, `maxAttempts`, `signal`, `onProgress`; counts `delivered` / `unreachable` / `failed` / `uncertain` / `pending` and `finished` / `stopped` / `halted` / `dry-run` |
|
|
21458
|
+
| `TelegramBroadcastFailureSchema` / `TelegramBroadcastFailure` | schema / _type_ | injected `classify` answers retry-after/transient/permanent/ambiguous; exact provider delay is bounded by `maxRetryDelayMs` without shortening, unknown outcome remains uncertain and is never replayed |
|
|
20792
21459
|
| `telegramBroadcastSender` / `TelegramBroadcastSenderConfig` / `TelegramBroadcastMessage` | function / _type_ | the standard `send`: `sendMessage` with a text or `copyMessage` of a prepared message, through the Bot API |
|
|
20793
21460
|
| `createTelegramOperatorChannel` | function | the operator chat, apart from the journal: `post(text, topic?)` returns at once and never throws; paced sends into forum topics, 429 honoured, oldest dropped on overflow, `drain(signal)` and `close()` for the way down |
|
|
20794
21461
|
| `TelegramOperatorChannelConfig` / `TelegramOperatorChannel` / `TelegramOperatorMessage` / `TelegramOperatorDrop` / `TelegramChatId` | _type_ | `chatId`, `topics`, `send`, `maxQueued`, `minIntervalMs`, `maxAttempts`, `onDropped`, `sensitivePatterns` and `sensitiveValues` (a bot token is always masked), `dedupe`; a drop is `overflow` / `refused` / `attempts` / `closed` / `repeated` / `over-budget` with its classification |
|
|
@@ -21131,6 +21798,7 @@ SDK nor the `ai` peer.
|
|
|
21131
21798
|
| `checkCliUpdate` | function | bounded, interval-limited, never-throwing check for a newer published build |
|
|
21132
21799
|
| `applyCliUpdate` | function | download, verify the decompressed digest and replace the binary by rename |
|
|
21133
21800
|
| `assertCliPublishable` | function | refuse republishing one version from a different commit — takes one manifest or every manifest already published, because the promise a version makes does not stop at a channel boundary |
|
|
21801
|
+
| `publishCli` / `CliPublicationOptions` / `CliPublicationPhase` / `CliPublicationResult` | function / _type_ | optional bounded builder/admission over one immutable name/version/commit stamp; commit verified assets before the manifest pointer, recover exact completed versions, retain verified history; existing signatures/installer/updater own the wire contract |
|
|
21134
21802
|
| `rollbackCliUpdate` / `CliRollbackConfig` / `RolledBackCliUpdate` | function / _types_ | put the kept previous build back, digest-checked first and written by the same atomic rename the update uses |
|
|
21135
21803
|
| `signCliManifest` / `verifyCliManifest` / `cliManifestSigningPayload` | function | Ed25519 over `{name, version, commit, builtAt, assets[]}` — every asset's digest included, so the chain closes on the file that executes |
|
|
21136
21804
|
| `cliSignatureAccepted` / `CliSignatureVerdict` | function / _type_ | `valid` \| `unenforced` \| `missing` \| `unknown-key` \| `invalid`; `unenforced` keeps an unpinned build updating while making the absence of a check visible |
|
|
@@ -21162,6 +21830,9 @@ SDK nor the `ai` peer.
|
|
|
21162
21830
|
| `CliConfig` | _type_ | config for `createCli`; `defaultCommand`, `globalOptions`, `optionAliases` and `positionals` define the shared command presentation policy |
|
|
21163
21831
|
| `CliPresentationPolicyConfig` | _type_ | shared command presentation-policy subset of `CliConfig` |
|
|
21164
21832
|
| `CliSurfaceSource` | _type_ | static service/runtime array or identity-dependent factory |
|
|
21833
|
+
| `RuntimeToolExecution` | _type_ | neutral heterogeneous runtime-tool registration; handlers execute through the schema-validating managed runner |
|
|
21834
|
+
| `RuntimeToolExecutionWithOutput` | _type_ | strict neutral managed definition with schema-derived handler input/output; construct before adding to CLI `runtimeTools` |
|
|
21835
|
+
| `RuntimeToolDefinitionWithoutOutput` | _type_ | strict neutral managed void definition without an output contract or transport presenters |
|
|
21165
21836
|
| `CliCommandDefinition` | _type_ | native command definition union |
|
|
21166
21837
|
| `CliCommandDefinitionBase` | _type_ | native command name, description and input schema |
|
|
21167
21838
|
| `CliCommandDefinitionWithOutput` | _type_ | native command with validated declared output and typed optional `present` / successful `exitCode` callbacks |
|
|
@@ -21313,3 +21984,17 @@ Native POSIX Bun/Node one-shot command execution. See [native IO](../guide/nativ
|
|
|
21313
21984
|
| `observeProcessInstance` / `ProcessInstanceObservation` | function / type | Linux/Darwin lifetime observation; observed identity or unavailable with its original cause, never guessed absence |
|
|
21314
21985
|
| `ProcessInstanceSchema` / `ProcessInstance` | schema / type | platform, boot ID, namespace and process start identity from the shared native reader |
|
|
21315
21986
|
| `probeProcessOwner` / `ProcessOwnerEvidence` | function / type | compare lifetimes on one caller-established machine; matched, boot change, reused PID, gone, legacy or unavailable with cause |
|
|
21987
|
+
|
|
21988
|
+
## `stitchkit/files/packaging`
|
|
21989
|
+
|
|
21990
|
+
`stitchkit/files/packaging` owns `createNativePackaging` and the types
|
|
21991
|
+
`NativePackagingOptions`, `NativePackagingAsset`, `NativePackagingPlugin`, `NativePackagingResult`.
|
|
21992
|
+
It resolves the installed package's target/version and original addon SHA256.
|
|
21993
|
+
`platform`, `architecture`, `delivery`, `entryPath` and `assetPath` are explicit public inputs.
|
|
21994
|
+
The result is `ready` with assets and a structural Bun plugin, or `unsupported`/`missing` with a safe code.
|
|
21995
|
+
Malformed options/metadata and other filesystem errors fail rather than masquerade as missing.
|
|
21996
|
+
Companion mode places an external addon relative to the emitted entry; embedded mode lets
|
|
21997
|
+
Bun compile retain the matching addon. Keep JS builds without splitting, preserve every output,
|
|
21998
|
+
and copy each original asset to its `outputPath` after verifying `sha256`.
|
|
21999
|
+
This evolving entrypoint is a build dependency; runtime imports do not reach it.
|
|
22000
|
+
The detailed recipe is in [native IO](../guide/native-io.md#public-native-packaging).
|