stitchkit 0.103.12 → 0.104.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 +112 -0
- package/darwin-native.cjs +12 -0
- package/darwin-native.d.cts +2 -0
- package/dist/agent-runtime/store-conformance-lifecycle.d.ts +10 -10
- 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 +8 -6
- package/dist/entrypoints/agent-runtime/harness-tools.js +8 -8
- package/dist/entrypoints/agent-runtime/harness.js +12 -11
- package/dist/entrypoints/agent-runtime/realtime.js +3 -3
- package/dist/entrypoints/agent-runtime/sandbox.js +8 -6
- package/dist/entrypoints/agent-runtime.js +13 -13
- package/dist/entrypoints/application/diagnostic-journal.js +3 -2
- 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.js +11 -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/process.js +2 -1
- 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 +20 -14
- 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/read.d.ts +2 -2
- package/dist/files/read.d.ts.map +1 -1
- package/dist/index-1a6jtnd9.js +88 -0
- package/dist/{index-fyphpknh.js → index-22rhg58f.js} +1 -1
- 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-nybn2err.js → index-5csmzesf.js} +1 -1
- package/dist/{index-qapzv4p5.js → index-5z6jn897.js} +1 -1
- package/dist/{index-ahvsksw5.js → index-6d9xaxw1.js} +1 -1
- package/dist/{index-ahtnte39.js → index-6drst9sg.js} +46 -35
- 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-ej331hah.js → index-gxm9rc97.js} +1 -1
- package/dist/{index-r5c4fedv.js → index-h2fhjqy7.js} +2 -1
- package/dist/{index-sybedc8b.js → index-hbd32c6a.js} +23 -94
- 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-806d5phm.js → index-ptn0g0gj.js} +7 -7
- 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-v5ee8ath.js +88 -0
- 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-xvdd2rbb.js → index-za6j7nwy.js} +19 -5
- package/dist/internal/bounded-file-read.d.ts +41 -0
- package/dist/internal/bounded-file-read.d.ts.map +1 -0
- package/dist/internal/darwin-binding-error.d.ts +24 -0
- package/dist/internal/darwin-binding-error.d.ts.map +1 -0
- package/dist/internal/darwin-binding.d.ts.map +1 -1
- 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/args-fields.d.ts +2 -0
- package/dist/tools/cli/args-fields.d.ts.map +1 -1
- package/dist/tools/cli/args.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 +133 -104
- package/llms/contract.txt +1 -1
- package/llms/process.txt +34 -5
- 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 +5 -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.79.0.txt} +171 -140
- package/llms/{upgrading-0.75.0-0.103.0.txt → upgrading-0.80.0-0.104.0.txt} +120 -171
- package/llms/upgrading.txt +4 -4
- package/llms-full.txt +677 -64
- package/llms.txt +13 -12
- package/package.json +10 -1
- package/dist/index-d4pa2bgs.js +0 -42
- 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/cli.2.txt
CHANGED
|
@@ -5,7 +5,146 @@
|
|
|
5
5
|
|
|
6
6
|
Parts of this slice:
|
|
7
7
|
- `llms/cli.txt`: Guide: CLI (docs/guide/cli.md)
|
|
8
|
-
- `llms/cli.2.txt`: API reference: `stitchkit/cli` (docs/api/reference.md)
|
|
8
|
+
- `llms/cli.2.txt`: Guide: CLI (docs/guide/cli.md) · API reference: `stitchkit/cli` (docs/api/reference.md)
|
|
9
|
+
|
|
10
|
+
==============================================================================
|
|
11
|
+
# Guide: CLI (docs/guide/cli.md) (continued)
|
|
12
|
+
==============================================================================
|
|
13
|
+
|
|
14
|
+
## Commands discovered from a running server
|
|
15
|
+
|
|
16
|
+
A CLI compiled from contracts carries the surface of the build it was compiled
|
|
17
|
+
from. One built from discovery carries the surface the server has *right now* —
|
|
18
|
+
which matters, because a long-lived MCP client freezes schemas at connect time
|
|
19
|
+
and then refuses the server's own newer fields:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const discovered = await mountConnections([
|
|
23
|
+
defineMcpClientConnection({
|
|
24
|
+
name: 'api',
|
|
25
|
+
transport: { url },
|
|
26
|
+
token: () => key,
|
|
27
|
+
transports: ['CLI'], // the opt-in: this server's tools are commands
|
|
28
|
+
limits: {
|
|
29
|
+
discovery: { timeoutMs: 30_000, maxResponseBytes: 4 * 1024 * 1024 },
|
|
30
|
+
call: { timeoutMs: 120_000 },
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
])
|
|
34
|
+
await createCli({ name: 'myapp', version, runtimeTools: discovered, commands: [...] })
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`transports` is where the opt-in belongs: a whole server becomes a set of
|
|
38
|
+
commands, and a connection without it still contributes nothing to the CLI —
|
|
39
|
+
exposure stays explicit, as it is everywhere else in the framework.
|
|
40
|
+
|
|
41
|
+
One unconvertible schema no longer takes the connection down with it. The tool
|
|
42
|
+
is skipped and **named** (`onSkippedTool`, or a stderr line by default), so a
|
|
43
|
+
surface of two hundred tools is not lost to one.
|
|
44
|
+
|
|
45
|
+
MCP connection limits follow the operation phase. `initialize`, the initialized
|
|
46
|
+
notification, `tools/list` and legacy endpoint discovery use `limits.discovery`;
|
|
47
|
+
`tools/call` uses `limits.call`. A mounted call's handshake still uses discovery
|
|
48
|
+
limits. Each logical operation has one deadline, including initial transport
|
|
49
|
+
negotiation and response-body reading. Legacy endpoint readiness has a discovery
|
|
50
|
+
deadline; the lifetime of an established SSE stream does not.
|
|
51
|
+
|
|
52
|
+
Omitted phase fields inherit the existing connection-level `timeoutMs` and
|
|
53
|
+
`maxResponseBytes`, whose defaults are 30 seconds and 1 MiB. Values must be positive
|
|
54
|
+
safe integers; `timeoutMs` must also fit the runtime timer range. The byte ceiling
|
|
55
|
+
counts raw UTF-8 body bytes, including SSE framing, regardless of `Content-Length`.
|
|
56
|
+
Pending legacy calls also count comments and wrong-id frames. `budget.maxTools`
|
|
57
|
+
and `budget.maxSchemaBytes` remain separate mount limits.
|
|
58
|
+
|
|
59
|
+
Only the initial `initialize` can negotiate HTTP-to-legacy fallback on 400, 404
|
|
60
|
+
or 405. A failed `tools/call` is not replayed. Caller cancellation preserves its
|
|
61
|
+
original reason for in-process observers.
|
|
62
|
+
|
|
63
|
+
Expected local failures produce safe tool errors: `CONNECTION_TIMEOUT` (exit 7),
|
|
64
|
+
`CONNECTION_RESPONSE_TOO_LARGE` (exit 1), `UNAUTHORIZED` (exit 2), `FORBIDDEN`
|
|
65
|
+
(exit 3) or `CONNECTION_REQUEST_FAILED` (exit 1). Deadline and response-limit
|
|
66
|
+
failures include fixed `operation`/`phase`, the applicable bound and measured
|
|
67
|
+
`observedReadBytes`. The public `ConnectionTimeoutError` and
|
|
68
|
+
`ConnectionResponseTooLargeError` classes carry the same diagnostics. Raw URL,
|
|
69
|
+
credential, body, identity and stack stay with the original in-process cause in
|
|
70
|
+
`onToolError` / `afterToolCall`; tool errors produce no process console dump.
|
|
71
|
+
Unknown throws remain `INTERNAL_SERVER_ERROR`. A timeout is not proof that a
|
|
72
|
+
write did not happen: verify the remote outcome before repeating an operation.
|
|
73
|
+
|
|
74
|
+
**A remote refusal keeps its code.** A failed `tools/call` used to become a
|
|
75
|
+
one-sentence `Error` with the result discarded, which cost three things at once:
|
|
76
|
+
the code (so `exitCodes` had nothing to map and every remote failure exited `1`),
|
|
77
|
+
the message the operator needed, and the error's own class — a plain `Error` is
|
|
78
|
+
an *unexpected* error to the runner, so it printed a code frame of the framework
|
|
79
|
+
bundle before the JSON failure and was then scrubbed to `INTERNAL_SERVER_ERROR`.
|
|
80
|
+
A structured `{ error, details }` body is now relayed as the contract error it
|
|
81
|
+
is, on every transport; anything else fails as `UPSTREAM_TOOL_ERROR` carrying
|
|
82
|
+
what the server did send. Not `INTERNAL_SERVER_ERROR`, because nothing of ours
|
|
83
|
+
broke.
|
|
84
|
+
|
|
85
|
+
**On the CLI a discovered command prints the answer, not the envelope.**
|
|
86
|
+
`tools/call` returns `{ content: [...], structuredContent? }`, and an agent mount
|
|
87
|
+
needs exactly that — the parts are what a model is shown. The CLI is different in
|
|
88
|
+
kind, because the handler's value is what gets printed, piped and aggregated:
|
|
89
|
+
handed the envelope, `--count-by status` groups the *content parts* and answers
|
|
90
|
+
`no record carries the field "status" — available: text, type`. So the CLI
|
|
91
|
+
transport unwraps, and only it: `structuredContent` when the server sent one, a
|
|
92
|
+
lone text part when it parses as JSON, its text when it does not, and `null` when
|
|
93
|
+
there are no parts at all — a tool without an output contract answers that way,
|
|
94
|
+
and the `_meta` beside an empty `content` is protocol metadata, never the answer.
|
|
95
|
+
Several parts, an image or audio pass through whole — picking one of many would
|
|
96
|
+
be inventing an answer.
|
|
97
|
+
|
|
98
|
+
## Auth parity
|
|
99
|
+
|
|
100
|
+
A scoped command is guarded by the same `createAuthHook` your HTTP server uses —
|
|
101
|
+
pass it as `lifecycle`, and inject the identity through `context` so
|
|
102
|
+
`resolveFromContext` can read it:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
const authHook = createAuthHook({ /* resolve, resolveFromContext, rules */ })
|
|
106
|
+
|
|
107
|
+
await createCli({
|
|
108
|
+
name: 'myapp',
|
|
109
|
+
version: '1.0.0',
|
|
110
|
+
resolveAuth: () => resolveIdentityFromToken(process.env.MYAPP_TOKEN),
|
|
111
|
+
context: (identity) => ({ user: identity }), // resolveFromContext reads this
|
|
112
|
+
lifecycle: { beforeHandle: authHook }, // same policy; HTTP wires it as authorize
|
|
113
|
+
services,
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Without `lifecycle`, a scoped command runs **unguarded** — the scope check lives
|
|
118
|
+
entirely inside the `createAuthHook` result, so with no hook wired in there is
|
|
119
|
+
nothing to enforce a method's `scope`. This matches the MCP / agent surfaces
|
|
120
|
+
exactly ([ADR 0014](../decisions/0014-tool-http-parity.md)): on every tool
|
|
121
|
+
transport the auth gate is opt-in, so a contract with scoped methods **must** be
|
|
122
|
+
given a `lifecycle` (and `context` identity) to be protected. The gate only
|
|
123
|
+
*fails closed* once the hook **is** present but `resolveFromContext` is missing —
|
|
124
|
+
then a scoped call has no identity and is rejected.
|
|
125
|
+
|
|
126
|
+
## Typed context
|
|
127
|
+
|
|
128
|
+
Use `createToolkit<AppContext>()` to type the injected `context` against your
|
|
129
|
+
app's context shape — the tool-side mirror of `createImplement`
|
|
130
|
+
([ADR 0017](../decisions/0017-typed-tool-context.md)):
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
const tools = createToolkit<{ user: User }>()
|
|
134
|
+
await tools.createCli({
|
|
135
|
+
name: 'myapp',
|
|
136
|
+
version: '1.0.0',
|
|
137
|
+
services,
|
|
138
|
+
context: (identity) => ({ user: identity }), // checked against { user: User }
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Remaining boundary
|
|
143
|
+
|
|
144
|
+
File-upload (`multipart`) contract endpoints remain CLI-invisible, the same as
|
|
145
|
+
on MCP/Agent: their wire body is not a JSON tool form. Model file-oriented
|
|
146
|
+
application behavior as a managed pathless command, or binary-only behavior as
|
|
147
|
+
a native command. Streaming (SSE) output is not yet piped to stdout.
|
|
9
148
|
|
|
10
149
|
==============================================================================
|
|
11
150
|
# API reference: `stitchkit/cli` (docs/api/reference.md)
|
|
@@ -33,6 +172,7 @@ SDK nor the `ai` peer.
|
|
|
33
172
|
| `checkCliUpdate` | function | bounded, interval-limited, never-throwing check for a newer published build |
|
|
34
173
|
| `applyCliUpdate` | function | download, verify the decompressed digest and replace the binary by rename |
|
|
35
174
|
| `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 |
|
|
175
|
+
| `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 |
|
|
36
176
|
| `rollbackCliUpdate` / `CliRollbackConfig` / `RolledBackCliUpdate` | function / _types_ | put the kept previous build back, digest-checked first and written by the same atomic rename the update uses |
|
|
37
177
|
| `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 |
|
|
38
178
|
| `cliSignatureAccepted` / `CliSignatureVerdict` | function / _type_ | `valid` \| `unenforced` \| `missing` \| `unknown-key` \| `invalid`; `unenforced` keeps an unpinned build updating while making the absence of a check visible |
|
|
@@ -64,6 +204,9 @@ SDK nor the `ai` peer.
|
|
|
64
204
|
| `CliConfig` | _type_ | config for `createCli`; `defaultCommand`, `globalOptions`, `optionAliases` and `positionals` define the shared command presentation policy |
|
|
65
205
|
| `CliPresentationPolicyConfig` | _type_ | shared command presentation-policy subset of `CliConfig` |
|
|
66
206
|
| `CliSurfaceSource` | _type_ | static service/runtime array or identity-dependent factory |
|
|
207
|
+
| `RuntimeToolExecution` | _type_ | neutral heterogeneous runtime-tool registration; handlers execute through the schema-validating managed runner |
|
|
208
|
+
| `RuntimeToolExecutionWithOutput` | _type_ | strict neutral managed definition with schema-derived handler input/output; construct before adding to CLI `runtimeTools` |
|
|
209
|
+
| `RuntimeToolDefinitionWithoutOutput` | _type_ | strict neutral managed void definition without an output contract or transport presenters |
|
|
67
210
|
| `CliCommandDefinition` | _type_ | native command definition union |
|
|
68
211
|
| `CliCommandDefinitionBase` | _type_ | native command name, description and input schema |
|
|
69
212
|
| `CliCommandDefinitionWithOutput` | _type_ | native command with validated declared output and typed optional `present` / successful `exitCode` callbacks |
|
package/llms/cli.txt
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Parts of this slice:
|
|
8
8
|
- `llms/cli.txt`: Guide: CLI (docs/guide/cli.md)
|
|
9
|
-
- `llms/cli.2.txt`: API reference: `stitchkit/cli` (docs/api/reference.md)
|
|
9
|
+
- `llms/cli.2.txt`: Guide: CLI (docs/guide/cli.md) · API reference: `stitchkit/cli` (docs/api/reference.md)
|
|
10
10
|
|
|
11
11
|
==============================================================================
|
|
12
12
|
# Guide: CLI (docs/guide/cli.md)
|
|
@@ -26,6 +26,46 @@ It exists for what the other three surfaces cannot do: a generation kicked off
|
|
|
26
26
|
with `Bash(run_in_background)` that notifies on exit, a `SKILL.md` that shells
|
|
27
27
|
out in one line, a pipeable terminal command.
|
|
28
28
|
|
|
29
|
+
## Installation and types
|
|
30
|
+
|
|
31
|
+
Install `stitchkit` and `zod` for a CLI. The public `stitchkit/cli` runtime and
|
|
32
|
+
declarations do not require `ai`, the MCP SDK or Bun globals. Node consumers can
|
|
33
|
+
use strict `NodeNext` resolution with `skipLibCheck: false` and ordinary Node
|
|
34
|
+
types; the package keeps its required dependencies separate from optional SDKs.
|
|
35
|
+
|
|
36
|
+
CLI runtime tools use the shared executable contract: identity, input and output
|
|
37
|
+
schemas, handler, and explicit CLI exposure. SDK presenters belong to the MCP/AI
|
|
38
|
+
definitions in `stitchkit/tools`, which require the corresponding peers. A typed
|
|
39
|
+
definition returned by `defineRuntimeTool` or `createRuntimeToolFactory` can be
|
|
40
|
+
passed directly to both CLI and SDK mounts.
|
|
41
|
+
|
|
42
|
+
Keep transport-specific `present` on that typed SDK definition, rather than on
|
|
43
|
+
an inline object in `CliConfig.runtimeTools`. CLI never executes those presenters;
|
|
44
|
+
its neutral configuration does not validate SDK presentation. Native CLI command
|
|
45
|
+
presentation remains on `defineCliCommand({ present })` and retains its inferred
|
|
46
|
+
output type.
|
|
47
|
+
|
|
48
|
+
For a CLI-only managed tool, use the neutral generic construction contract to
|
|
49
|
+
infer the handler from its schemas:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import type { RuntimeToolExecutionWithOutput } from 'stitchkit/cli'
|
|
53
|
+
import { z } from 'zod'
|
|
54
|
+
|
|
55
|
+
const input = z.object({ text: z.string() })
|
|
56
|
+
const output = z.object({ size: z.number() })
|
|
57
|
+
const measure = {
|
|
58
|
+
name: 'measure', description: 'Measure text',
|
|
59
|
+
identity: { serviceName: 'text', action: 'measure', method: 'POST' },
|
|
60
|
+
transports: ['CLI'], input, output,
|
|
61
|
+
handler: ({ input }) => ({ size: input.text.length }),
|
|
62
|
+
} satisfies RuntimeToolExecutionWithOutput<typeof input, typeof output>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Pass `measure` to `runtimeTools`. The heterogeneous registration type preserves
|
|
66
|
+
the definition without inventing a common handler input; execute it through
|
|
67
|
+
`createCli` or `createCliInvoker` so validation remains on the canonical path.
|
|
68
|
+
|
|
29
69
|
## Exposure is opt-in
|
|
30
70
|
|
|
31
71
|
Unlike MCP and agent — where an endpoint with no `expose` is a tool by default —
|
|
@@ -206,6 +246,16 @@ there stays a positional, and `--` makes a literal `false` one too. The same
|
|
|
206
246
|
holds for a short alias, a framework flag such as `--json false` and an
|
|
207
247
|
application option.
|
|
208
248
|
|
|
249
|
+
Every declared non-array option is single-use, including framework and
|
|
250
|
+
application globals. Bare, separate-value, inline, negative and short-alias
|
|
251
|
+
forms of a command option count as the same name: `--active=false --active`,
|
|
252
|
+
`--active false --no-active` and `-f --active` are argument errors even when
|
|
253
|
+
the values agree. Duplicates are refused before command execution. Array
|
|
254
|
+
options accumulate across long and short forms; unknown non-dotted passthrough
|
|
255
|
+
options retain their raw-list grammar. Tokens after `--` are literal data.
|
|
256
|
+
Command `--help` and `-h` keep their diagnostic precedence over malformed
|
|
257
|
+
operation arguments; application globals are validated before routing.
|
|
258
|
+
|
|
209
259
|
Without presentation configuration, positional arguments fill non-boolean
|
|
210
260
|
fields in declaration order, so `myapp generate "a fox"` is
|
|
211
261
|
`--prompt "a fox"`. A piped value fills the first required unset field:
|
|
@@ -656,6 +706,88 @@ manifest URL is configuration you wrote, while an asset URL arrives inside a
|
|
|
656
706
|
document the endpoint served, and a document is exactly what an SSRF boundary
|
|
657
707
|
exists to distrust.
|
|
658
708
|
|
|
709
|
+
### Publishing a complete version
|
|
710
|
+
|
|
711
|
+
`publishCli` is an opt-in publisher for a local application-owned distribution
|
|
712
|
+
directory. It commits every target and its version manifest before atomically
|
|
713
|
+
replacing the public `manifest.json`. Your application selects the CLI source
|
|
714
|
+
identity and admits that snapshot at each phase:
|
|
715
|
+
|
|
716
|
+
```ts
|
|
717
|
+
import { publishCli } from 'stitchkit/cli'
|
|
718
|
+
|
|
719
|
+
const result = await publishCli({
|
|
720
|
+
storageRoot: '/srv/myapp/cli',
|
|
721
|
+
name: 'myapp', version: cliVersion, commit: selectedCliCommit,
|
|
722
|
+
baseUrl: 'https://downloads.example.com/cli/',
|
|
723
|
+
targets: [{ platform: 'linux', arch: 'x64' }],
|
|
724
|
+
signal,
|
|
725
|
+
admit: ({ phase, identity, signal }) => assertSelectedSource({ phase, identity, signal }),
|
|
726
|
+
build: ({ target, stamp, signal }) => compileSelectedSource({ target, stamp, signal }),
|
|
727
|
+
})
|
|
728
|
+
// result.outcome: 'published' | 'existing'; result.manifest is ready to serve.
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
The builder returns `Uint8Array` or `ReadableStream<Uint8Array>` containing the
|
|
732
|
+
executable. Every target receives the same immutable `{ version, commit,
|
|
733
|
+
builtAt }` stamp; carry it inside the binary. The publisher owns staging,
|
|
734
|
+
gzip assets, paths and manifests. Callbacks receive the cancellation signal and
|
|
735
|
+
run under the publication lock. Admission phases are `prepare`, each target's
|
|
736
|
+
`build`, `commit`, and `promote`; validate the selected source through commit
|
|
737
|
+
and promotion. A backend release can explicitly select an unchanged older CLI
|
|
738
|
+
identity. The helper never substitutes a different commit or rebuilds an
|
|
739
|
+
existing version under a new identity.
|
|
740
|
+
|
|
741
|
+
Assets live at `<version>/<name>-<platform>-<arch>.gz`, with an immutable
|
|
742
|
+
`<version>/manifest.json` and a public `manifest.json`. A verified repeat keeps
|
|
743
|
+
the exact bytes and `builtAt`, requires the same target set and base URL, and
|
|
744
|
+
returns `existing` without invoking the builder. A version committed before a
|
|
745
|
+
failed promotion is recovered and promoted without rebuilding. Conflicting
|
|
746
|
+
same-version commits, downgrades, unsafe components, corrupt manifests and
|
|
747
|
+
assets are refused. Version/name/target components are validated before any
|
|
748
|
+
build; `storageRoot` is absolute and its existing parent must be trusted.
|
|
749
|
+
|
|
750
|
+
All limits are finite positive safe integers; `limits` overrides these defaults:
|
|
751
|
+
|
|
752
|
+
| Field | Default | Enforced boundary |
|
|
753
|
+
| --- | --- | --- |
|
|
754
|
+
| `maxTargets` | 16 | Requested and verified target count |
|
|
755
|
+
| `maxManifestBytes` | 256 KiB | Read and written manifest bytes |
|
|
756
|
+
| `maxAssetBytes` | 256 MiB | Builder and decompressed executable bytes |
|
|
757
|
+
| `maxCompressedBytes` | 256 MiB | Archived asset bytes |
|
|
758
|
+
| `maxDirectoryEntries` | 128 | Version layout, root scan and commit space |
|
|
759
|
+
| `maxStoredVersions` | 16 | Verified publisher-owned history |
|
|
760
|
+
| `lockTimeoutMs` | 10,000 | Wait to acquire the lock |
|
|
761
|
+
| `timeoutMs` | 600,000 | Whole publication deadline |
|
|
762
|
+
|
|
763
|
+
`retention` defaults to 2 and keeps the current and previous published versions.
|
|
764
|
+
It must be at least 2 and less than `maxStoredVersions` (at least 3), leaving a
|
|
765
|
+
recovery slot. Older versions are pruned only after their own identity, exact
|
|
766
|
+
layout, raw size and digest are verified. Runtime folders and foreign semver
|
|
767
|
+
directories remain untouched. A full or unverifiable store refuses further
|
|
768
|
+
publication; repeated completed candidates stay inside the owned history cap.
|
|
769
|
+
Cancelled or failed incomplete staging is removed only while its root and
|
|
770
|
+
directory generations still match. The shared asynchronous gzip decoder also
|
|
771
|
+
bounds updater expansion by the declared raw size and configured byte cap.
|
|
772
|
+
|
|
773
|
+
The publisher rejects symlink roots/versions/assets, non-regular files and
|
|
774
|
+
multiply linked files, and checks held-lock, root and prior-pointer generations
|
|
775
|
+
before commit and promotion. This is cooperative publication under a trusted
|
|
776
|
+
parent directory. Portable path checks do not provide an atomic comparison with
|
|
777
|
+
a hostile process replacing ancestors between syscalls. Durability uses file
|
|
778
|
+
and directory sync on POSIX; Windows publication is refused. A deadline stops
|
|
779
|
+
callback/stream waits and blocks late promotion; trusted callbacks remain
|
|
780
|
+
responsible for cancelling their own subprocesses and external effects.
|
|
781
|
+
|
|
782
|
+
A failure after an immutable commit reports that the publication outcome must
|
|
783
|
+
be checked. A failure after public-pointer rename may already have published;
|
|
784
|
+
`AtomicFilePublicationError.published` remains available when the atomic writer
|
|
785
|
+
reports that boundary. Read the durable manifest and retry the admitted same
|
|
786
|
+
identity to recover; an error does not promise rollback. Optional `signing` and
|
|
787
|
+
`trust` reuse the Ed25519 contract below. The generated shell installer checks
|
|
788
|
+
raw digest and size; the updater checks manifest authorship when given a trust
|
|
789
|
+
root.
|
|
790
|
+
|
|
659
791
|
### Proving who built it — signing the manifest
|
|
660
792
|
|
|
661
793
|
The asset digest proves the bytes that arrived are the bytes the manifest named.
|
|
@@ -879,106 +1011,3 @@ asked.
|
|
|
879
1011
|
What stays yours: what makes a repeat safe (an idempotency key derived from the
|
|
880
1012
|
line id), which operations a batch may contain, and how much of it runs at once.
|
|
881
1013
|
That is product knowledge, and the framework has no business guessing it.
|
|
882
|
-
|
|
883
|
-
## Commands discovered from a running server
|
|
884
|
-
|
|
885
|
-
A CLI compiled from contracts carries the surface of the build it was compiled
|
|
886
|
-
from. One built from discovery carries the surface the server has *right now* —
|
|
887
|
-
which matters, because a long-lived MCP client freezes schemas at connect time
|
|
888
|
-
and then refuses the server's own newer fields:
|
|
889
|
-
|
|
890
|
-
```ts
|
|
891
|
-
const discovered = await mountConnections([
|
|
892
|
-
defineMcpClientConnection({
|
|
893
|
-
name: 'api',
|
|
894
|
-
transport: { url },
|
|
895
|
-
token: () => key,
|
|
896
|
-
transports: ['CLI'], // the opt-in: this server's tools are commands
|
|
897
|
-
}),
|
|
898
|
-
])
|
|
899
|
-
await createCli({ name: 'myapp', version, runtimeTools: discovered, commands: [...] })
|
|
900
|
-
```
|
|
901
|
-
|
|
902
|
-
`transports` is where the opt-in belongs: a whole server becomes a set of
|
|
903
|
-
commands, and a connection without it still contributes nothing to the CLI —
|
|
904
|
-
exposure stays explicit, as it is everywhere else in the framework.
|
|
905
|
-
|
|
906
|
-
One unconvertible schema no longer takes the connection down with it. The tool
|
|
907
|
-
is skipped and **named** (`onSkippedTool`, or a stderr line by default), so a
|
|
908
|
-
surface of two hundred tools is not lost to one.
|
|
909
|
-
|
|
910
|
-
**A remote refusal keeps its code.** A failed `tools/call` used to become a
|
|
911
|
-
one-sentence `Error` with the result discarded, which cost three things at once:
|
|
912
|
-
the code (so `exitCodes` had nothing to map and every remote failure exited `1`),
|
|
913
|
-
the message the operator needed, and the error's own class — a plain `Error` is
|
|
914
|
-
an *unexpected* error to the runner, so it printed a code frame of the framework
|
|
915
|
-
bundle before the JSON failure and was then scrubbed to `INTERNAL_SERVER_ERROR`.
|
|
916
|
-
A structured `{ error, details }` body is now relayed as the contract error it
|
|
917
|
-
is, on every transport; anything else fails as `UPSTREAM_TOOL_ERROR` carrying
|
|
918
|
-
what the server did send. Not `INTERNAL_SERVER_ERROR`, because nothing of ours
|
|
919
|
-
broke.
|
|
920
|
-
|
|
921
|
-
**On the CLI a discovered command prints the answer, not the envelope.**
|
|
922
|
-
`tools/call` returns `{ content: [...], structuredContent? }`, and an agent mount
|
|
923
|
-
needs exactly that — the parts are what a model is shown. The CLI is different in
|
|
924
|
-
kind, because the handler's value is what gets printed, piped and aggregated:
|
|
925
|
-
handed the envelope, `--count-by status` groups the *content parts* and answers
|
|
926
|
-
`no record carries the field "status" — available: text, type`. So the CLI
|
|
927
|
-
transport unwraps, and only it: `structuredContent` when the server sent one, a
|
|
928
|
-
lone text part when it parses as JSON, its text when it does not, and `null` when
|
|
929
|
-
there are no parts at all — a tool without an output contract answers that way,
|
|
930
|
-
and the `_meta` beside an empty `content` is protocol metadata, never the answer.
|
|
931
|
-
Several parts, an image or audio pass through whole — picking one of many would
|
|
932
|
-
be inventing an answer.
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
## Auth parity
|
|
936
|
-
|
|
937
|
-
A scoped command is guarded by the same `createAuthHook` your HTTP server uses —
|
|
938
|
-
pass it as `lifecycle`, and inject the identity through `context` so
|
|
939
|
-
`resolveFromContext` can read it:
|
|
940
|
-
|
|
941
|
-
```ts
|
|
942
|
-
const authHook = createAuthHook({ /* resolve, resolveFromContext, rules */ })
|
|
943
|
-
|
|
944
|
-
await createCli({
|
|
945
|
-
name: 'myapp',
|
|
946
|
-
version: '1.0.0',
|
|
947
|
-
resolveAuth: () => resolveIdentityFromToken(process.env.MYAPP_TOKEN),
|
|
948
|
-
context: (identity) => ({ user: identity }), // resolveFromContext reads this
|
|
949
|
-
lifecycle: { beforeHandle: authHook }, // same policy; HTTP wires it as authorize
|
|
950
|
-
services,
|
|
951
|
-
})
|
|
952
|
-
```
|
|
953
|
-
|
|
954
|
-
Without `lifecycle`, a scoped command runs **unguarded** — the scope check lives
|
|
955
|
-
entirely inside the `createAuthHook` result, so with no hook wired in there is
|
|
956
|
-
nothing to enforce a method's `scope`. This matches the MCP / agent surfaces
|
|
957
|
-
exactly ([ADR 0014](../decisions/0014-tool-http-parity.md)): on every tool
|
|
958
|
-
transport the auth gate is opt-in, so a contract with scoped methods **must** be
|
|
959
|
-
given a `lifecycle` (and `context` identity) to be protected. The gate only
|
|
960
|
-
*fails closed* once the hook **is** present but `resolveFromContext` is missing —
|
|
961
|
-
then a scoped call has no identity and is rejected.
|
|
962
|
-
|
|
963
|
-
## Typed context
|
|
964
|
-
|
|
965
|
-
Use `createToolkit<AppContext>()` to type the injected `context` against your
|
|
966
|
-
app's context shape — the tool-side mirror of `createImplement`
|
|
967
|
-
([ADR 0017](../decisions/0017-typed-tool-context.md)):
|
|
968
|
-
|
|
969
|
-
```ts
|
|
970
|
-
const tools = createToolkit<{ user: User }>()
|
|
971
|
-
await tools.createCli({
|
|
972
|
-
name: 'myapp',
|
|
973
|
-
version: '1.0.0',
|
|
974
|
-
services,
|
|
975
|
-
context: (identity) => ({ user: identity }), // checked against { user: User }
|
|
976
|
-
})
|
|
977
|
-
```
|
|
978
|
-
|
|
979
|
-
## Remaining boundary
|
|
980
|
-
|
|
981
|
-
File-upload (`multipart`) contract endpoints remain CLI-invisible, the same as
|
|
982
|
-
on MCP/Agent: their wire body is not a JSON tool form. Model file-oriented
|
|
983
|
-
application behavior as a managed pathless command, or binary-only behavior as
|
|
984
|
-
a native command. Streaming (SSE) output is not yet piped to stdout.
|
package/llms/contract.txt
CHANGED
|
@@ -570,7 +570,7 @@ from the root `stitchkit`.
|
|
|
570
570
|
| Export | Kind | Summary |
|
|
571
571
|
|--------|------|---------|
|
|
572
572
|
| `AppError` | class | the framework error — `code` / `status` / `details` / `hint` |
|
|
573
|
-
| `ErrorEnvelope` | _type_ | the JSON shape of an error response |
|
|
573
|
+
| `ErrorEnvelope` | _type_ | the JSON shape of an error response, preserving optional declared boolean `error.retryable` without changing HTTP retry policy |
|
|
574
574
|
| `notFound` | function | throw `404 NOT_FOUND` — [guide](../guide/auth-and-errors.md#throwing-errors) |
|
|
575
575
|
| `badRequest` | function | throw `400 BAD_REQUEST` |
|
|
576
576
|
| `unauthorized` | function | throw `401 UNAUTHORIZED` |
|
package/llms/process.txt
CHANGED
|
@@ -15,7 +15,7 @@ description: Native IO для Bun и Node, с явно выбранной durabi
|
|
|
15
15
|
type: guide
|
|
16
16
|
status: active
|
|
17
17
|
created: 2026-10-01 20:44 +07:00
|
|
18
|
-
updated: 2026-10-
|
|
18
|
+
updated: 2026-10-04 09:40 +07:00
|
|
19
19
|
participants:
|
|
20
20
|
- role: authored
|
|
21
21
|
harness: Codex
|
|
@@ -29,6 +29,10 @@ participants:
|
|
|
29
29
|
harness: Codex
|
|
30
30
|
model: GPT-6
|
|
31
31
|
at: 2026-10-03 13:36 +07:00
|
|
32
|
+
- role: implemented
|
|
33
|
+
harness: Codex
|
|
34
|
+
model: GPT-6
|
|
35
|
+
at: 2026-10-04 09:21 +07:00
|
|
32
36
|
---
|
|
33
37
|
|
|
34
38
|
# Native IO
|
|
@@ -256,10 +260,35 @@ version: carry their reachable relative `.d.ts` closure, rather than emitting re
|
|
|
256
260
|
instead emit declarations for only that DTO contract. Keep the library's manifest at runtime
|
|
257
261
|
`dependencies: {}` and `peerDependencies: { zod: ... }` when that is its declared promise.
|
|
258
262
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
+
The packaged Darwin loader has static references to both architecture addons. Bun compilation
|
|
264
|
+
embeds the matching `.node` asset; ordinary Bun bundling emits native assets alongside its JS
|
|
265
|
+
output. Publish **every output returned by `Bun.build`**, preserving relative paths. Copying only
|
|
266
|
+
the JS file drops its native dependency. No runtime Stitchkit installation or manually chosen
|
|
267
|
+
native path is required for these bundled artifacts.
|
|
268
|
+
|
|
269
|
+
```sh
|
|
270
|
+
bun build src/native.ts --target=bun --minify --outdir=dist
|
|
271
|
+
bun build src/native.ts --compile --bytecode --format=esm --outfile=dist/native
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
For a JS build that previously used `--outfile=dist/native.js`, use
|
|
275
|
+
`--outdir=dist --entry-naming=native.js` instead: the output can now include native assets.
|
|
276
|
+
The standalone executable still uses `--outfile` because those assets are embedded inside it.
|
|
277
|
+
|
|
278
|
+
Qualify the complete output outside its build tree and installed dependency graph. Test process
|
|
279
|
+
identity, live-owner refusal, dead-owner recovery and contained file operations in the resulting
|
|
280
|
+
JS bundle and standalone executable. Bun and Node package imports retain the same lazy loader;
|
|
281
|
+
importing a portable leaf does not load a Darwin addon on another OS. Test declarations too,
|
|
282
|
+
and check that importing an unbundled Stitchkit leaf fails in a deliberately isolated library
|
|
283
|
+
distribution. A separate schema-only entry must not import the native entry.
|
|
284
|
+
|
|
285
|
+
If the Darwin backend cannot load, `observeProcessInstance` still returns `unavailable`.
|
|
286
|
+
Its backend `Error` preserves the original `cause`; JSON serialization carries only the stable
|
|
287
|
+
`DARWIN_BACKEND_UNAVAILABLE` code, architecture, safe message and failure stage
|
|
288
|
+
(`architecture`, `resolve`, `load` or `surface`), plus a recognized native error code when present.
|
|
289
|
+
It excludes stack, paths and nested cause. This backend diagnosis does not reclassify kernel
|
|
290
|
+
failures or turn unavailable identity into proof that an owner is dead. If a runtime provides
|
|
291
|
+
no recognized native error code, the stage stays `load`; the loader never infers errno from text.
|
|
263
292
|
|
|
264
293
|
This delivery removes a runtime kernel installation; it does not remove the build-time
|
|
265
294
|
Stitchkit installation or create an independent lightweight npm package.
|
package/llms/server.4.txt
CHANGED
|
@@ -547,12 +547,15 @@ error round-trips without adding correlation data to the response body.
|
|
|
547
547
|
A `code` is a free string — your app codes (`BOT_NOT_FOUND`, …) are yours and the
|
|
548
548
|
core never models them (ADR 0002). But stitchkit itself emits a set of its own:
|
|
549
549
|
`BAD_REQUEST`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `METHOD_NOT_ALLOWED`,
|
|
550
|
-
`CONFLICT`, `RATE_LIMITED`, `
|
|
550
|
+
`CONFLICT`, `RATE_LIMITED`, `REQUEST_ABORTED`, `REQUEST_TIMEOUT`,
|
|
551
|
+
`VALIDATION_ERROR`, `FILE_INVALID_PATH`,
|
|
551
552
|
`FILE_OUTSIDE_ROOT`, `FILE_NOT_FOUND`, `FILE_NOT_REGULAR`,
|
|
552
553
|
`FILE_INSPECTION_REJECTED`, `FILE_TOO_LARGE`, `FILE_EXISTS`,
|
|
553
554
|
`REALTIME_CONTRACT_VIOLATION`, `APPLICATION_NOT_ACCEPTING`, `NOT_IMPLEMENTED`,
|
|
554
555
|
`WAIT_TIMEOUT`,
|
|
555
556
|
`WAIT_FAILED`, `DOWNLOAD_NOT_FOUND`, `VIEW_HTTP_ERROR`,
|
|
557
|
+
`CONNECTION_TIMEOUT`, `CONNECTION_RESPONSE_TOO_LARGE`,
|
|
558
|
+
`CONNECTION_REQUEST_FAILED`, `UPSTREAM_TOOL_ERROR`,
|
|
556
559
|
`OPERATION_NOT_SUCCEEDED`, `STREAM_ITEM_INVALID`, `STREAM_FRAME_TOO_LARGE`,
|
|
557
560
|
`STREAM_TERMINAL_MISSING`, `STREAM_LIFETIME_EXCEEDED`,
|
|
558
561
|
`GRAMMY_WEBHOOK_NOT_ACCEPTING`, `SANDBOX_UNAVAILABLE`, `SANDBOX_INSUFFICIENT`,
|
package/llms/server.5.txt
CHANGED
|
@@ -57,6 +57,7 @@ Also re-exports the error helpers from `stitchkit/contract`.
|
|
|
57
57
|
| `respondJson` | function | a raw route's JSON response (`204` for null/undefined) |
|
|
58
58
|
| `errorResponse` | function | any thrown value → the framework error envelope + `x-request-id` |
|
|
59
59
|
| `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` |
|
|
60
|
+
| `NormalizeErrorOptions` | _type_ | `logUnexpected` defaults to logging the raw server-side cause; tool adapters disable process dumps while their existing observers retain that cause |
|
|
60
61
|
| `errorCode` | function | the stable error code for a thrown value (side-effect-free — for log attribution) |
|
|
61
62
|
| `formatZodError` | function | a `ZodError` → a readable, field-summarised string |
|
|
62
63
|
| `zodIssues` | function | a `ZodError` → structured `{ path, code, message }[]` — the machine-readable sibling of `formatZodError` |
|
package/llms/stitchkit.2.txt
CHANGED
|
@@ -710,6 +710,13 @@ URLs.
|
|
|
710
710
|
|
|
711
711
|
## `ApiError`
|
|
712
712
|
|
|
713
|
+
On native Bun, both client paths disable Bun's separate socket idle timer while preserving
|
|
714
|
+
the framework deadline and caller signal. A long declared deadline therefore remains the
|
|
715
|
+
request policy. Explicit or patched fetch implementations, including Next, keep their own
|
|
716
|
+
transport behavior; Node and browsers receive no Bun-specific fetch options. Raw responses
|
|
717
|
+
and contract streams retain their existing header timeout and caller-owned body lifetime.
|
|
718
|
+
See [Bun's idle timeout contract](https://bun.sh/reference/globals/BunFetchRequestInit/timeout).
|
|
719
|
+
|
|
713
720
|
A non-2xx response is thrown as an `ApiError`:
|
|
714
721
|
|
|
715
722
|
```ts
|
|
@@ -724,6 +731,7 @@ try {
|
|
|
724
731
|
err.message // 'Note not found'
|
|
725
732
|
err.details // structured details, if any
|
|
726
733
|
err.hint // optional hint
|
|
734
|
+
err.retryable // optional explicit recommendation, true or false
|
|
727
735
|
err.traceId // x-request-id — correlate this failure with backend logs
|
|
728
736
|
err.cause // concrete injected transport failure, when delivery failed
|
|
729
737
|
}
|
|
@@ -737,6 +745,12 @@ browser code can read it through Stitchkit's default CORS expose list; a custom
|
|
|
737
745
|
|
|
738
746
|
The error model is shared with the server — see [Auth & errors](./auth-and-errors.md).
|
|
739
747
|
|
|
748
|
+
`retryable` preserves an explicit boolean in the server error envelope; an absent declaration
|
|
749
|
+
remains absent. This metadata does not change the HTTP transport retry policy. The existing
|
|
750
|
+
seventh constructor argument remains `ErrorOptions`, including `cause`; the optional
|
|
751
|
+
retryability argument is eighth. Closed error/frame schemas must accept the new optional
|
|
752
|
+
field before their producer declares it.
|
|
753
|
+
|
|
740
754
|
## Auth events
|
|
741
755
|
|
|
742
756
|
The HTTP client emits events your app can react to globally:
|
package/llms/stitchkit.txt
CHANGED
|
@@ -63,10 +63,11 @@ own, recorded as an ADR.
|
|
|
63
63
|
| `stitchkit/server` | server (Bun) | stable | `createServer`, `implement`, hooks, auth, Socket.IO server, server primitives |
|
|
64
64
|
| `stitchkit/node` | server (Node ≥ 22) | stable | `serveNode` + the runtime-agnostic core — the Node mirror of `/server` |
|
|
65
65
|
| `stitchkit/tools` | server | stable | `createMcpHandler`, `mountMcp`, `mountAgent`, the OAuth provider, native tools |
|
|
66
|
+
| `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 |
|
|
66
67
|
| `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 |
|
|
67
68
|
| `stitchkit/tools/invoker` | server | stable | peer-free `createToolInvoker` over the canonical contract tool runner |
|
|
68
69
|
| `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 |
|
|
69
|
-
| `stitchkit/cli` | server | stable | `createCli` —
|
|
70
|
+
| `stitchkit/cli` | server | stable | `createCli` / `createCliInvoker` — runtime and strict NodeNext declarations without MCP SDK / `ai` |
|
|
70
71
|
| `stitchkit/remote` | browser **and** server | stable | peer-free `implementRemote` for thin HTTP proxy processes |
|
|
71
72
|
| `stitchkit/process` | server (Bun or Node, POSIX) | evolving | finite native commands, byte sinks, bounded capture and process-group cancellation |
|
|
72
73
|
| `stitchkit/files` | server (Bun or Node) | stable | peer-free managed local-file boundary |
|
|
@@ -80,12 +81,12 @@ own, recorded as an ADR.
|
|
|
80
81
|
| `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
|
|
81
82
|
| `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
|
|
82
83
|
| `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
|
|
83
|
-
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the
|
|
84
|
+
| `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 |
|
|
84
85
|
| `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, plus the managed-resource conformance kit |
|
|
85
86
|
| `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
|
|
86
87
|
| `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
|
|
87
88
|
| `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) |
|
|
88
|
-
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 22 of the
|
|
89
|
+
| `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 |
|
|
89
90
|
| `stitchkit/agent-runtime/sandbox` | server | evolving | optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see [sandbox guide](sandbox.md) |
|
|
90
91
|
| `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 |
|
|
91
92
|
| `stitchkit/agent-runtime/harness` | server | evolving | resource-aware process-local facade over the canonical Agent runtime; supervision stays outside |
|
|
@@ -98,7 +99,7 @@ own, recorded as an ADR.
|
|
|
98
99
|
| `stitchkit/agent-runtime/sqlite/bun` | server (Bun) | evolving | durable built-in SQLite store for the agent runtime |
|
|
99
100
|
| `stitchkit/agent-runtime/sqlite/node` | server (Node ≥ 22.5) | evolving | durable built-in SQLite store for the agent runtime |
|
|
100
101
|
| `stitchkit-tui` | terminal (Bun) | evolving | optional official OpenTUI host over a caller-composed headless runtime |
|
|
101
|
-
| `stitchkit/application` | browser + server | evolving<br>_redefined in
|
|
102
|
+
| `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 |
|
|
102
103
|
| `stitchkit/application/grammy` | server | evolving | a grammY bot as application resources — configuration, then polling with updates admitted by batch — and the webhook adapter |
|
|
103
104
|
| `stitchkit/application/opentelemetry` | server | evolving | maps application snapshots onto an injected OpenTelemetry `Meter` |
|
|
104
105
|
| `stitchkit/application/schemas` | browser + server | evolving | the application's snapshot, health and shutdown schemas alone, without the kernel |
|