stitchkit 0.114.2 → 0.116.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 +54 -0
- package/dist/agent-runtime/coding-tool-files.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-listing.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-paths.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-refusals.d.ts +6 -0
- package/dist/agent-runtime/coding-tool-refusals.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-search-patch.d.ts.map +1 -1
- package/dist/agent-runtime/contained-scan.d.ts +1 -1
- package/dist/agent-runtime/contained-scan.d.ts.map +1 -1
- package/dist/agent-runtime/sandbox-broker.d.ts.map +1 -1
- package/dist/agent-runtime/sandbox-bubblewrap-storage.d.ts.map +1 -1
- package/dist/application/directory-inbox-files.d.ts.map +1 -1
- package/dist/application/file-state-store.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/coding-tools.js +6 -4
- package/dist/entrypoints/agent-runtime/harness.js +2 -1
- package/dist/entrypoints/agent-runtime/sandbox.js +13 -8
- package/dist/entrypoints/agent-runtime/sqlite/bun.js +8 -6
- package/dist/entrypoints/agent-runtime/sqlite/node.js +8 -6
- package/dist/entrypoints/agent-runtime/testing.js +8 -6
- package/dist/entrypoints/agent-runtime.js +8 -6
- package/dist/entrypoints/application/diagnostic-journal.js +2 -2
- package/dist/entrypoints/application/directory-inbox.js +10 -7
- package/dist/entrypoints/cli/publish.js +11 -8
- package/dist/entrypoints/cli.js +6 -3
- package/dist/entrypoints/files.js +10 -7
- package/dist/entrypoints/process/owner-loss.js +1 -1
- package/dist/entrypoints/process.js +3 -3
- package/dist/entrypoints/react/keyboard/testing.js +1 -1
- package/dist/entrypoints/react/keyboard.js +11 -11
- package/dist/entrypoints/server.js +4 -4
- package/dist/entrypoints/telegram/grammy.js +2 -2
- package/dist/entrypoints/telegram.d.ts +1 -1
- package/dist/entrypoints/telegram.d.ts.map +1 -1
- package/dist/entrypoints/telegram.js +30 -14
- package/dist/entrypoints/tools.js +5 -2
- package/dist/files/chunk-spool.d.ts.map +1 -1
- package/dist/{index-2f9r0jgr.js → index-364k2zwa.js} +4 -4
- package/dist/{index-dc9ere5p.js → index-4g6qmgdx.js} +1 -1
- package/dist/index-6f49krb5.js +107 -0
- package/dist/{index-912sza5h.js → index-90p34rts.js} +1 -1
- package/dist/{index-07dcf2yn.js → index-ac6vvm30.js} +5 -2
- package/dist/{index-zrtrjkbf.js → index-arjmb6de.js} +183 -172
- package/dist/{index-7r4knwf8.js → index-dr3t5n1v.js} +14 -4
- package/dist/{index-84bf5spd.js → index-f6m4c545.js} +5 -2
- package/dist/{index-qj1sy4ep.js → index-fa435yq2.js} +1 -1
- package/dist/{index-hy802jnr.js → index-fdk4r4r6.js} +6 -3
- package/dist/index-jj9228tt.js +6 -0
- package/dist/{index-a3462dqf.js → index-jq2ky8fw.js} +1 -1
- package/dist/{index-s47ac8zt.js → index-n5sv4z0w.js} +142 -156
- package/dist/{index-bh2ht9y5.js → index-n8z3rvzw.js} +4 -1
- package/dist/index-q968hy6y.js +100 -0
- package/dist/{index-j4zh647a.js → index-tt30h7mr.js} +4 -1
- package/dist/{index-tnxsq7cw.js → index-w7jq3fz9.js} +113 -38
- package/dist/{index-p02zgk8x.js → index-y4rxnvgp.js} +6 -0
- package/dist/{index-5v5a9k2n.js → index-z3d6smer.js} +1 -1
- package/dist/{index-6b3pcq5z.js → index-zqkz4af9.js} +1 -1
- package/dist/internal/atomic-file.d.ts.map +1 -1
- package/dist/internal/atomic-staging.d.ts.map +1 -1
- package/dist/internal/contained-directory.d.ts +20 -0
- package/dist/internal/contained-directory.d.ts.map +1 -0
- package/dist/{agent-runtime → internal}/contained-files.d.ts +24 -13
- package/dist/internal/contained-files.d.ts.map +1 -0
- package/dist/internal/contained-handle.d.ts +30 -0
- package/dist/internal/contained-handle.d.ts.map +1 -0
- package/dist/internal/contained-write.d.ts +12 -0
- package/dist/internal/contained-write.d.ts.map +1 -0
- package/dist/internal/darwin-binding.d.ts +1 -1
- package/dist/internal/darwin-binding.d.ts.map +1 -1
- package/dist/internal/errno.d.ts +3 -0
- package/dist/internal/errno.d.ts.map +1 -0
- package/dist/internal/process-instance.d.ts.map +1 -1
- package/dist/internal/write-download.d.ts +5 -14
- package/dist/internal/write-download.d.ts.map +1 -1
- package/dist/process/group-diagnostics.d.ts +1 -0
- package/dist/process/group-diagnostics.d.ts.map +1 -1
- package/dist/process/group-settlement.d.ts +2 -0
- package/dist/process/group-settlement.d.ts.map +1 -1
- package/dist/process/group.d.ts.map +1 -1
- package/dist/process/owner-loss-control.d.ts.map +1 -1
- package/dist/react/keyboard/hooks.d.ts +2 -2
- package/dist/react/keyboard/hooks.d.ts.map +1 -1
- package/dist/react/keyboard/layers.d.ts +2 -0
- package/dist/react/keyboard/layers.d.ts.map +1 -1
- package/dist/telegram/broadcast-state.d.ts.map +1 -1
- package/dist/telegram/budget-transformer.d.ts +5 -2
- package/dist/telegram/budget-transformer.d.ts.map +1 -1
- package/dist/telegram/outbound-budget.d.ts +26 -11
- package/dist/telegram/outbound-budget.d.ts.map +1 -1
- package/dist/tools/cli/download.d.ts.map +1 -1
- package/dist/tools/cli/publication-storage.d.ts.map +1 -1
- package/dist/tools/cli/publication.d.ts.map +1 -1
- package/dist/tools/cli/view.d.ts +7 -1
- package/dist/tools/cli/view.d.ts.map +1 -1
- package/llms/agent-runtime.txt +16 -6
- package/llms/cli.txt +37 -3
- package/llms/process.txt +2 -2
- package/llms/react-keyboard.txt +18 -2
- package/llms/stitchkit.txt +3 -3
- package/llms/telegram.txt +10 -3
- package/llms/{upgrading-0.104.0-0.114.0.txt → upgrading-0.105.0-0.116.0.txt} +85 -124
- package/llms/{upgrading-0.44.0-0.61.0.txt → upgrading-0.44.0-0.62.0.txt} +120 -3
- package/llms/{upgrading-0.62.0-0.78.0.txt → upgrading-0.63.0-0.83.0.txt} +181 -120
- package/llms/{upgrading-0.79.0-0.103.13.txt → upgrading-0.84.0-0.104.0.txt} +124 -181
- package/llms/upgrading.txt +4 -4
- package/llms-full.txt +168 -19
- package/llms.txt +9 -9
- package/native/darwin-arm64.node +0 -0
- package/native/darwin-x64.node +0 -0
- package/native-assets.json +4 -4
- package/package.json +1 -1
- package/dist/agent-runtime/contained-darwin.d.ts +0 -21
- package/dist/agent-runtime/contained-darwin.d.ts.map +0 -1
- package/dist/agent-runtime/contained-files.d.ts.map +0 -1
- package/dist/agent-runtime/contained-write.d.ts +0 -9
- package/dist/agent-runtime/contained-write.d.ts.map +0 -1
|
@@ -1,14 +1,135 @@
|
|
|
1
|
-
# Upgrading 0.
|
|
1
|
+
# Upgrading 0.84.0 → 0.104.0 — stitchkit docs slice
|
|
2
2
|
|
|
3
3
|
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
4
|
> `llms.txt` in this package.
|
|
5
5
|
|
|
6
|
-
Contains: Guide: Upgrading, 0.
|
|
6
|
+
Contains: Guide: Upgrading, 0.84.0 → 0.104.0 (docs/guide/upgrading.md)
|
|
7
7
|
|
|
8
8
|
==============================================================================
|
|
9
|
-
# Guide: Upgrading, 0.
|
|
9
|
+
# Guide: Upgrading, 0.84.0 → 0.104.0 (docs/guide/upgrading.md)
|
|
10
10
|
==============================================================================
|
|
11
11
|
|
|
12
|
+
## Released migration: 0.104.0
|
|
13
|
+
|
|
14
|
+
JS bundles carrying Darwin native capabilities also need the
|
|
15
|
+
[delivery migration first affected in 0.103.13](#released-migration-010313).
|
|
16
|
+
Consumers upgrading from 0.103.12 or earlier must apply it even if their TypeScript API is unchanged.
|
|
17
|
+
|
|
18
|
+
### CLI runtime-tool construction
|
|
19
|
+
|
|
20
|
+
**Who must act:** callers writing a schema-dependent handler or MCP/AI `present` directly
|
|
21
|
+
inside an annotated `CliConfig.runtimeTools` or `CliInvokerConfig.runtimeTools` object.
|
|
22
|
+
Native `commands` and values returned by `defineRuntimeTool` / `createRuntimeToolFactory`
|
|
23
|
+
remain valid. Execution, auth, validation and the invocation result envelope keep their behavior.
|
|
24
|
+
|
|
25
|
+
Construct a CLI-only managed definition with the neutral schema-aware type before registration:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import type { CliInvokerConfig, RuntimeToolExecutionWithOutput } from 'stitchkit/cli'
|
|
29
|
+
import { z } from 'zod'
|
|
30
|
+
|
|
31
|
+
const input = z.object({ text: z.string() })
|
|
32
|
+
const output = z.object({ size: z.number() })
|
|
33
|
+
// Before: handler receives the heterogeneous registry context.
|
|
34
|
+
const config: CliInvokerConfig = {
|
|
35
|
+
name: 'app',
|
|
36
|
+
runtimeTools: [{
|
|
37
|
+
name: 'measure', description: 'Measure text',
|
|
38
|
+
identity: { serviceName: 'text', action: 'measure', method: 'POST' },
|
|
39
|
+
transports: ['CLI'], input, output,
|
|
40
|
+
handler: ({ input }) => ({ size: String(input.text).length }),
|
|
41
|
+
}],
|
|
42
|
+
}
|
|
43
|
+
// After: handler input and output derive from the construction schemas.
|
|
44
|
+
const measure = {
|
|
45
|
+
name: 'measure', description: 'Measure text',
|
|
46
|
+
identity: { serviceName: 'text', action: 'measure', method: 'POST' },
|
|
47
|
+
transports: ['CLI'], input, output,
|
|
48
|
+
handler: ({ input }) => ({ size: input.text.length }),
|
|
49
|
+
} satisfies RuntimeToolExecutionWithOutput<typeof input, typeof output>
|
|
50
|
+
const nextConfig: CliInvokerConfig = { name: 'app', runtimeTools: [measure] }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For a shared MCP/AI tool, construct the definition with `defineRuntimeTool` from
|
|
54
|
+
`stitchkit/tools`, including its typed SDK `present` callbacks, then pass the returned value
|
|
55
|
+
to `runtimeTools`. Install the corresponding SDK peers for that integration. A CLI-only
|
|
56
|
+
consumer needs `stitchkit`, `zod` and its ordinary Node type tooling.
|
|
57
|
+
|
|
58
|
+
`RuntimeToolExecution` names the heterogeneous registration contract. Call a registered
|
|
59
|
+
operation through `createCli` or `createCliInvoker`; its erased handler input is `never`
|
|
60
|
+
because the managed runner owns schema validation before execution. For a managed void
|
|
61
|
+
definition, use `RuntimeToolDefinitionWithoutOutput<typeof input>`.
|
|
62
|
+
|
|
63
|
+
### MCP construction, state stores and delivery
|
|
64
|
+
|
|
65
|
+
**Who must act:** schema-dependent runtime tool literals written directly inside MCP mount
|
|
66
|
+
configuration, MCP presenters returning malformed content or metadata, custom `StateStore`
|
|
67
|
+
implementations, file-store consumers using retired lock
|
|
68
|
+
options, broadcast consumers reading `halt` or retrying unknown send outcomes, and consumers
|
|
69
|
+
that validate HTTP error envelopes with a closed schema. Applications collecting raw tool
|
|
70
|
+
causes from `console.error` must configure an internal tool hook sink.
|
|
71
|
+
|
|
72
|
+
MCP-only code can import the existing server factories from `stitchkit/tools/mcp` and
|
|
73
|
+
construct its schema-aware tool before heterogeneous registration:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { buildMcpServer, type RuntimeMcpToolDefinitionWithOutput } from 'stitchkit/tools/mcp'
|
|
77
|
+
import { z } from 'zod'
|
|
78
|
+
const input = z.object({ value: z.number() })
|
|
79
|
+
const output = z.object({ doubled: z.number() })
|
|
80
|
+
// Before: runtimeTools: [{ input, output, handler, present }]
|
|
81
|
+
const double = {
|
|
82
|
+
name: 'double', description: 'Double a number',
|
|
83
|
+
identity: { serviceName: 'numbers', action: 'double', method: 'POST' },
|
|
84
|
+
input, output,
|
|
85
|
+
handler: ({ input }) => ({ doubled: input.value * 2 }),
|
|
86
|
+
present: { mcp: ({ doubled }) => ({ content: [{ type: 'text', text: String(doubled) }] }) },
|
|
87
|
+
} satisfies RuntimeMcpToolDefinitionWithOutput<typeof input, typeof output>
|
|
88
|
+
const server = buildMcpServer({ serverInfo: { name: 'numbers', version: '1' }, services: [], runtimeTools: [double] })
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Full MCP/AI integrations keep `defineRuntimeTool` from `stitchkit/tools`; those typed values
|
|
92
|
+
remain accepted by the MCP leaf and CLI. The leaf requires the MCP SDK and Zod, with no AI peer.
|
|
93
|
+
|
|
94
|
+
`RuntimeMcpPresentation` preserves the official SDK's required `content` and typed `_meta`
|
|
95
|
+
fields. A presenter returning `{}` must return `{ content: [] }`; text blocks require string
|
|
96
|
+
text, and metadata must be an object. `structuredContent` and `isError` remain framework-owned.
|
|
97
|
+
This restores SDK checks that an indexed mapped type previously erased.
|
|
98
|
+
|
|
99
|
+
Unexpected tool causes remain in `hooks.onToolError` and the `error` field of
|
|
100
|
+
`hooks.afterToolCall`. Protocol stderr carries safe errors. MCP resolver failures use those
|
|
101
|
+
same observers without executing the handler or its lifecycle again. HTTP's default
|
|
102
|
+
unexpected-error logging retains its behavior.
|
|
103
|
+
|
|
104
|
+
A custom state adapter's `update` must invoke `transition(current, context)` while it still
|
|
105
|
+
owns the serialized transaction. `context.assertHeld()` checks the actual transaction or lock
|
|
106
|
+
generation and refuses after completion, rollback or ownership loss. A no-op guard cannot
|
|
107
|
+
satisfy this contract. Existing transition callbacks may keep one parameter. For the owning
|
|
108
|
+
file adapter, replace `{ staleLockMs, retryMs, lockTimeoutMs }` with `{ lockTimeoutMs }`:
|
|
109
|
+
the remaining budget controls acquisition waiting, never expiry of a live transaction.
|
|
110
|
+
Unknown legacy PID locks and historical temporary files are preserved; recover them only
|
|
111
|
+
after independently proving their owner is gone.
|
|
112
|
+
|
|
113
|
+
Broadcast consumers change `report.halt.reason` checks to the closed `halt.kind` union:
|
|
114
|
+
`retry-after`, `transient`, `permanent` or `ambiguous`. A custom MTProto adapter can classify
|
|
115
|
+
an acknowledged flood refusal as `{ kind: 'retry-after', retryAfterMs: wait }`; the exact
|
|
116
|
+
provider wait is respected. A wait over `maxRetryDelayMs` halts with the recipient pending.
|
|
117
|
+
Unknown write outcome becomes `uncertain`; restarting the same broadcast does not send it
|
|
118
|
+
again. A retry classification must certify that the attempt did not apply the external effect.
|
|
119
|
+
|
|
120
|
+
HTTP errors gain optional boolean `error.retryable`; framed contract streams use the same
|
|
121
|
+
field. Update closed consumer schemas before producers declaring it. `false` on 502 and
|
|
122
|
+
`true` on 409 remain explicit recommendations through the remote tool path. An absent field
|
|
123
|
+
retains prior status-derived defaults; the field does not change the HTTP client's retry policy.
|
|
124
|
+
The existing seventh `ApiError` constructor argument remains `ErrorOptions`; retryability is
|
|
125
|
+
the new eighth argument.
|
|
126
|
+
|
|
127
|
+
Caller cancellation now reaches `implementRemote`'s existing HTTP call. Applications bind
|
|
128
|
+
signals to `createCli` / `createCliInvoker` and cooperative handlers observe `ctx.signal`.
|
|
129
|
+
`REQUEST_ABORTED` is nonretryable and exits 130. A disconnected caller does not prove that
|
|
130
|
+
an origin ignoring cancellation or an external provider stopped; keep resource leases until
|
|
131
|
+
that work actually completes.
|
|
132
|
+
|
|
12
133
|
## Released migration: 0.103.13
|
|
13
134
|
|
|
14
135
|
### Darwin native assets in JS distributions
|
|
@@ -884,181 +1005,3 @@ The workspace root is not asked about — it is the boundary the tools already o
|
|
|
884
1005
|
**3. The policy is called more often.** A path of depth N costs N+1 calls (`.`, then each ancestor,
|
|
885
1006
|
then the leaf), outermost first, stopping at the first refusal. A policy that logs or meters will
|
|
886
1007
|
see a different sequence, and will no longer see the leaf once an ancestor has refused.
|
|
887
|
-
|
|
888
|
-
## Released migration: 0.83.0
|
|
889
|
-
|
|
890
|
-
Two things, both mechanical, and only if you touch an observability sink.
|
|
891
|
-
|
|
892
|
-
```bash
|
|
893
|
-
rg -n "createObservability|createApplicationEventSink|createApplicationSnapshotSink|createAgentRuntimeEventSink|createAgentObservability"
|
|
894
|
-
```
|
|
895
|
-
|
|
896
|
-
**1. `flush()` returns `Promise<boolean>`.** `await sink.flush()` needs no
|
|
897
|
-
change. Only a declared type does:
|
|
898
|
-
|
|
899
|
-
```ts
|
|
900
|
-
// before
|
|
901
|
-
const flushAudit: () => Promise<void> = observability.flush
|
|
902
|
-
// after
|
|
903
|
-
const flushAudit: () => Promise<boolean> = observability.flush
|
|
904
|
-
```
|
|
905
|
-
|
|
906
|
-
**2. `ObservabilityDrainReport` carries `drained`.** The framework builds it, so
|
|
907
|
-
reading code is unchanged. A hand-built report — a test double, or one persisted
|
|
908
|
-
and re-parsed through `ObservabilityDrainReportSchema` — needs the field:
|
|
909
|
-
|
|
910
|
-
```ts
|
|
911
|
-
// before
|
|
912
|
-
{ request, tools, total, durationMs }
|
|
913
|
-
// after
|
|
914
|
-
{ request, tools, total, durationMs, drained: true }
|
|
915
|
-
```
|
|
916
|
-
|
|
917
|
-
Then take the thing this release exists for. Every drain now accepts
|
|
918
|
-
`{ timeoutMs?, signal? }`, so a shutdown can give the audit drain the same
|
|
919
|
-
deadline it gives every other step:
|
|
920
|
-
|
|
921
|
-
```ts
|
|
922
|
-
const report = await observability.close({ timeoutMs: 5_000 })
|
|
923
|
-
if (!report.drained) {
|
|
924
|
-
logger.warn('audit drain incomplete', {
|
|
925
|
-
unwritten: report.total.received - report.total.filtered - report.total.completed,
|
|
926
|
-
})
|
|
927
|
-
}
|
|
928
|
-
```
|
|
929
|
-
|
|
930
|
-
The bound ends the **waiting**, not the writes: a sink's `write` is handed no
|
|
931
|
-
cancellation, so an outstanding one keeps running against whatever you close
|
|
932
|
-
next. Racing `close()` against your own timer looks equivalent and is not — it
|
|
933
|
-
discards the report along with the wait.
|
|
934
|
-
|
|
935
|
-
## Released migration: 0.82.0
|
|
936
|
-
|
|
937
|
-
One thing, and only if you mount MCP or agent tools from a `createTrackingContract` contract.
|
|
938
|
-
|
|
939
|
-
```bash
|
|
940
|
-
rg -n "createTrackingContract"
|
|
941
|
-
```
|
|
942
|
-
|
|
943
|
-
The event ingest (`track`, `POST /events`) is now `expose: ['HTTP']`, which is
|
|
944
|
-
what its sibling `bootstrap` always declared. Before, it declared nothing — and
|
|
945
|
-
an endpoint with no `expose` is a tool on MCP and AGENT by default, so the
|
|
946
|
-
mounted surface carried a `track_<prefix>` tool. Since this contract is built
|
|
947
|
-
inside the framework, an application that had made every tool opt-in for the
|
|
948
|
-
endpoints *it* authors could not have opted this one out.
|
|
949
|
-
|
|
950
|
-
**If you pin a tool-surface digest or count**, it moves by one; re-record it.
|
|
951
|
-
**If you assert on tool names**, `track_<prefix>` is gone. **If nothing in your
|
|
952
|
-
project mounts tools from this contract**, there is nothing to do — the HTTP
|
|
953
|
-
routes, the client and the schemas are unchanged.
|
|
954
|
-
|
|
955
|
-
Un-declaring the tool was never the intent, so there is no option to keep it. If
|
|
956
|
-
an agent in your system genuinely needs to record something, give it your own
|
|
957
|
-
endpoint with your own schema: the browser ingest trusts a client-minted event
|
|
958
|
-
id and a visit lease, and an agent holds neither.
|
|
959
|
-
|
|
960
|
-
## Released migration: 0.81.0
|
|
961
|
-
|
|
962
|
-
**Path literals own string params.**
|
|
963
|
-
|
|
964
|
-
An endpoint whose path contains `:id` or a terminal `*rest` no longer needs a
|
|
965
|
-
duplicate `params: z.object({ …string() })` declaration. Remove schemas that do
|
|
966
|
-
nothing beyond repeating path names:
|
|
967
|
-
|
|
968
|
-
```ts
|
|
969
|
-
// before
|
|
970
|
-
{ path: '/projects/:projectId/*filePath',
|
|
971
|
-
params: z.object({ projectId: z.string(), filePath: z.string() }) }
|
|
972
|
-
|
|
973
|
-
// after
|
|
974
|
-
{ path: '/projects/:projectId/*filePath' }
|
|
975
|
-
```
|
|
976
|
-
|
|
977
|
-
Keep an explicit schema when it validates or coerces. It must cover every name
|
|
978
|
-
in the path — an explicit schema that misses one now fails at `defineContract`
|
|
979
|
-
with the path and the missing field named. Client calls and handler contexts
|
|
980
|
-
infer the string fields from the literal, so a call that omitted one becomes a
|
|
981
|
-
compile error instead of building a URL with an unresolved segment. Measured
|
|
982
|
-
across three consuming applications before release (373 endpoints with path
|
|
983
|
-
segments), no explicit schema missed a field: the migration is deleting
|
|
984
|
-
schemas that only repeated the path, or nothing.
|
|
985
|
-
|
|
986
|
-
## Released migration: 0.80.0
|
|
987
|
-
|
|
988
|
-
One thing, and only if you parse an async-operation snapshot.
|
|
989
|
-
|
|
990
|
-
```bash
|
|
991
|
-
rg -n "createAsyncOperationSnapshotSchema"
|
|
992
|
-
```
|
|
993
|
-
|
|
994
|
-
`progress` on a parsed snapshot used to be `unknown`. The factory built its
|
|
995
|
-
object shapes with a conditional spread, and the narrowing inside it widened
|
|
996
|
-
your schema back to a bare `ZodType`, so the emitted declaration threw the type
|
|
997
|
-
argument away. It is now the output of the schema you configured.
|
|
998
|
-
|
|
999
|
-
```ts
|
|
1000
|
-
const schema = createAsyncOperationSnapshotSchema({
|
|
1001
|
-
progress: z.object({ done: z.number(), total: z.number() }),
|
|
1002
|
-
failure: z.object({ code: z.string() }),
|
|
1003
|
-
})
|
|
1004
|
-
const snap = schema.parse(body)
|
|
1005
|
-
if (snap.phase === 'running') {
|
|
1006
|
-
// before: `snap.progress` was `unknown` — this needed a cast or a narrow
|
|
1007
|
-
// after: it is `{ done: number; total: number } | undefined`
|
|
1008
|
-
console.log(snap.progress?.done)
|
|
1009
|
-
}
|
|
1010
|
-
```
|
|
1011
|
-
|
|
1012
|
-
**If you cast it**, delete the cast — it was working around the erased type.
|
|
1013
|
-
**If you assigned something else to it**, the compiler now refuses, and it was
|
|
1014
|
-
already a value the schema rejected at run time.
|
|
1015
|
-
|
|
1016
|
-
**If you pass explicit type arguments**, the no-progress form takes one now, not
|
|
1017
|
-
two: the factory is two overloads. Pass none.
|
|
1018
|
-
|
|
1019
|
-
```ts
|
|
1020
|
-
// before: createAsyncOperationSnapshotSchema<undefined, typeof Failure>({ failure: Failure })
|
|
1021
|
-
// after: createAsyncOperationSnapshotSchema({ failure: Failure })
|
|
1022
|
-
```
|
|
1023
|
-
|
|
1024
|
-
Nothing about parsing moves. A snapshot configured without `progress` still
|
|
1025
|
-
strips an unexpected `progress` rather than refusing it — that behaviour is why
|
|
1026
|
-
this is overloads and not one normalised key.
|
|
1027
|
-
|
|
1028
|
-
**If you compile with `skipLibCheck: false`**, this is also the release that
|
|
1029
|
-
makes `stitchkit/tools/contract` compile at all: it carried five `TS2344`
|
|
1030
|
-
errors, one per phase, from the same conditional spread.
|
|
1031
|
-
|
|
1032
|
-
## Released migration: 0.79.0
|
|
1033
|
-
|
|
1034
|
-
One thing, and only if you assert on the whole snapshot.
|
|
1035
|
-
|
|
1036
|
-
```bash
|
|
1037
|
-
rg -n "getSnapshot\(\)|projectApplicationStatus|status\(\)" --glob '*.test.ts' --glob '*.spec.ts'
|
|
1038
|
-
```
|
|
1039
|
-
|
|
1040
|
-
`ApplicationSnapshot` and `ApplicationStatusProjection` each gained a
|
|
1041
|
-
`restarting` field — ids in the snapshot, a count in the projection. A reader
|
|
1042
|
-
that names the fields it wants is unaffected. A test that compares the whole
|
|
1043
|
-
object with `toEqual` fails until it adds the field:
|
|
1044
|
-
|
|
1045
|
-
```ts
|
|
1046
|
-
// before
|
|
1047
|
-
expect(body).toEqual({ id, lifecycle: 'ready', /* … */ resources: { total: 1, ready: 1, degraded: 0, failed: 0 } })
|
|
1048
|
-
// after
|
|
1049
|
-
expect(body).toEqual({ id, lifecycle: 'ready', /* … */ resources: { total: 1, ready: 1, degraded: 0, failed: 0 }, restarting: 0 })
|
|
1050
|
-
```
|
|
1051
|
-
|
|
1052
|
-
It is zero except while a restart is running, and then it names the subtree being
|
|
1053
|
-
replaced. That is the point: a snapshot taken mid-restart used to be
|
|
1054
|
-
indistinguishable from a resource that had failed on its own, so a dashboard read
|
|
1055
|
-
a planned replacement as an outage.
|
|
1056
|
-
|
|
1057
|
-
**If you watch a hub across a restart**, nothing to change, but the behaviour is
|
|
1058
|
-
different and better: closing a hub now tells its subscribers `unavailable` /
|
|
1059
|
-
`source-unavailable` instead of dropping them, so a page stops showing a value
|
|
1060
|
-
that will never update again.
|
|
1061
|
-
|
|
1062
|
-
**If you need a tool contract in a browser**, `stitchkit/tools/contract` now
|
|
1063
|
-
carries the async-operation helpers, its schemas and the view-file input/output
|
|
1064
|
-
without the runtime. `stitchkit/tools` still exports all of them.
|
package/llms/upgrading.txt
CHANGED
|
@@ -11,10 +11,10 @@ Contains: Guide: Upgrading, general (docs/guide/upgrading.md)
|
|
|
11
11
|
|
|
12
12
|
Load this slice, then every range slice between your installed version and the target:
|
|
13
13
|
|
|
14
|
-
- 0.
|
|
15
|
-
- 0.
|
|
16
|
-
- 0.
|
|
17
|
-
- 0.44.0 → 0.
|
|
14
|
+
- 0.105.0 → 0.116.0: `llms/upgrading-0.105.0-0.116.0.txt`
|
|
15
|
+
- 0.84.0 → 0.104.0: `llms/upgrading-0.84.0-0.104.0.txt`
|
|
16
|
+
- 0.63.0 → 0.83.0: `llms/upgrading-0.63.0-0.83.0.txt`
|
|
17
|
+
- 0.44.0 → 0.62.0: `llms/upgrading-0.44.0-0.62.0.txt`
|
|
18
18
|
- 0.37.0 → 0.44.0: `llms/upgrading-0.37.0-0.44.0.txt`
|
|
19
19
|
|
|
20
20
|
# Upgrading stitchkit
|
package/llms-full.txt
CHANGED
|
@@ -78,13 +78,13 @@ own, recorded as an ADR.
|
|
|
78
78
|
| `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
|
|
79
79
|
| `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
|
|
80
80
|
| `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
|
|
81
|
-
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the
|
|
81
|
+
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the 61 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
|
|
82
82
|
| `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, the managed-resource conformance kit and manual time for schedules and retries |
|
|
83
83
|
| `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
|
|
84
84
|
| `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
|
|
85
85
|
| `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) |
|
|
86
86
|
| `stitchkit/react/keyboard/testing` | server (Bun or Node) | evolving | the keyboard layers and zones without a DOM — fakes for the window, elements and key events beside the two engines, to test the order of layers, `scope`/`inert` and the edges of a zone in milliseconds |
|
|
87
|
-
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in
|
|
87
|
+
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 25 of the 61 minors since 0.56.2, most recently 0.115.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
|
|
88
88
|
| `stitchkit/agent-runtime/sandbox` | server | evolving | optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see [sandbox guide](sandbox.md) |
|
|
89
89
|
| `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 |
|
|
90
90
|
| `stitchkit/agent-runtime/harness` | server | evolving | resource-aware process-local facade over the canonical Agent runtime; supervision stays outside |
|
|
@@ -96,7 +96,7 @@ own, recorded as an ADR.
|
|
|
96
96
|
| `stitchkit/agent-runtime/sqlite/bun` | server (Bun) | evolving | durable built-in SQLite store for the agent runtime |
|
|
97
97
|
| `stitchkit/agent-runtime/sqlite/node` | server (Node ≥ 22.5) | evolving | durable built-in SQLite store for the agent runtime |
|
|
98
98
|
| `stitchkit-tui` | terminal (Bun) | evolving | optional official OpenTUI host over a caller-composed headless runtime |
|
|
99
|
-
| `stitchkit/application` | browser + server | evolving<br>_redefined in 14 of the
|
|
99
|
+
| `stitchkit/application` | browser + server | evolving<br>_redefined in 14 of the 61 minors since 0.56.2, most recently 0.110.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
|
|
100
100
|
| `stitchkit/application/grammy` | server | evolving | a grammY bot as application resources — configuration, then polling with updates admitted by batch — and the webhook adapter |
|
|
101
101
|
| `stitchkit/application/opentelemetry` | server | evolving | maps application snapshots onto an injected OpenTelemetry `Meter` |
|
|
102
102
|
| `stitchkit/application/schemas` | browser + server | evolving | the application's snapshot, health and shutdown schemas alone, without the kernel |
|
|
@@ -5658,17 +5658,27 @@ approval input fails the run with a private diagnostic rather than starting a fr
|
|
|
5658
5658
|
`read_output`. Every call passes a required host authorization callback. An optional async/sync
|
|
5659
5659
|
`authorizePath({ path })` is the one operation-independent policy for direct file access and
|
|
5660
5660
|
discovery: direct read/write/edit refuses a denied path, while listing, glob and search omit it.
|
|
5661
|
-
Denial is recursive on every surface — direct access
|
|
5662
|
-
|
|
5661
|
+
Denial is recursive on every surface — direct access asks about each named ancestor and the file,
|
|
5662
|
+
outermost first, stopping at the first refusal; discovery rooted at `.` also asks about `.`.
|
|
5663
|
+
Thus denying `credentials` denies everything
|
|
5663
5664
|
under it. The comparison is segment-wise, so it does not deny `credentials-backup`, and a path of
|
|
5664
|
-
depth N costs N
|
|
5665
|
+
depth N costs N questions for direct access. Directory decisions happen before descent; file decisions and
|
|
5665
5666
|
`search_files.include` happen before opening content. Requested paths use `/`: a backslash is
|
|
5666
5667
|
refused rather than normalised, because the workspace walk reads it as a separator and every
|
|
5667
5668
|
authorization callback would otherwise be asked about a different decomposition than the one opened. File paths are relative, bounded and contained after
|
|
5668
|
-
descriptor-relative resolution: each ancestor is opened without following symlinks and
|
|
5669
|
-
pinned through authorization
|
|
5669
|
+
descriptor-relative resolution: each ancestor is opened without following symlinks. Reads and edits
|
|
5670
|
+
stay pinned through authorization; `write_file` plans before it and opens the parent after, because
|
|
5671
|
+
the parent it creates does not exist yet. Reads revalidate the pinned file identity;
|
|
5670
5672
|
writes and patches revalidate the pinned parent identity; search and resource discovery descend
|
|
5671
|
-
only through opened directories.
|
|
5673
|
+
only through opened directories. A path that changed during authorization refuses with `CONFLICT`.
|
|
5674
|
+
A path spelled differently from the name stored on disk refuses before any policy reads it, so on a
|
|
5675
|
+
case-insensitive volume a rule on `credentials` cannot be passed by asking for `CREDENTIALS`.
|
|
5676
|
+
NUL bytes are refused before either host policy sees a path.
|
|
5677
|
+
Reads and edits open file candidates without blocking on special files, then require a regular
|
|
5678
|
+
file. A writerless FIFO therefore refuses instead of occupying a filesystem worker. `write_file`
|
|
5679
|
+
supplies the exact missing-directory plan as `createsDirectories` to host authorization; the
|
|
5680
|
+
descriptor walk may create only those entries. An ancestor that disappears after approval refuses
|
|
5681
|
+
with `CONFLICT`, without expanding that plan. Linux traverses `/proc/self/fd`; macOS uses the package's
|
|
5672
5682
|
architecture-specific Node-API `openat` backend. Unsupported platforms, including FreeBSD until a
|
|
5673
5683
|
real backend is qualified, fail closed. The package needs no install-time compiler or script.
|
|
5674
5684
|
Other platforms fail these filesystem operations closed because Node exposes no equivalent
|
|
@@ -9072,8 +9082,8 @@ a static loader enters a bundle.
|
|
|
9072
9082
|
|
|
9073
9083
|
Only these calls load the addon, and only on macOS: process identity (`observeProcessInstance`
|
|
9074
9084
|
and `probeProcessOwner`), every exclusive lock (`withExclusiveLock` and what is built on it, such
|
|
9075
|
-
as the file state store and the diagnostic journal)
|
|
9076
|
-
coding tools
|
|
9085
|
+
as the file state store and the diagnostic journal), the contained file operations of the Agent
|
|
9086
|
+
coding tools and `--output-dir` downloads of `stitchkit/cli`. Without the addon a download refuses, and a lock still works, but it cannot record or check its owner's
|
|
9077
9087
|
identity, so a lock held by a crashed owner is not reclaimed. The managed file boundary
|
|
9078
9088
|
(`createManagedFileBoundary` and the transfer tools built on it), atomic writes and the chunk
|
|
9079
9089
|
spool never load it, on any operating system. The package is free of import side effects
|
|
@@ -10415,6 +10425,29 @@ myapp generate "a fox" --wait --output-dir ./out
|
|
|
10415
10425
|
myapp generate "a fox" --wait --json > result.json &
|
|
10416
10426
|
```
|
|
10417
10427
|
|
|
10428
|
+
### Download filesystem boundary
|
|
10429
|
+
|
|
10430
|
+
`--output-dir` resolves the explicitly configured root once before fetching and pins that
|
|
10431
|
+
one directory for the whole batch. An initial root alias (including a symbolic link) selects
|
|
10432
|
+
its canonical directory; missing components are created through pinned parents. The root
|
|
10433
|
+
capability continues to name the same directory if another actor renames it or replaces its
|
|
10434
|
+
pathname. The original spelling printed in `saved` is a display path, not a re-open of the root.
|
|
10435
|
+
|
|
10436
|
+
Each media name becomes a direct child. Downloads atomically replace an existing file,
|
|
10437
|
+
symbolic link (including a dangling link), or hard link without changing the inode a link
|
|
10438
|
+
points to. An existing directory refuses replacement. Ordinary files retain their permission
|
|
10439
|
+
bits; new files use `0666 & ~umask`. Replacing writes a new file beside the old one, so it needs
|
|
10440
|
+
write permission on the directory, gives the file to the process user, replaces a read-only
|
|
10441
|
+
file, and refuses a bind-mounted one. Symlinks inside a contained parent path are never followed.
|
|
10442
|
+
The successful operation's JSON remains on stdout when a download fails; per-file diagnostics
|
|
10443
|
+
go to stderr and any failed file makes the exit non-zero. Already saved files remain saved.
|
|
10444
|
+
|
|
10445
|
+
This filesystem protection supports Linux and macOS. On Linux it uses directory descriptors;
|
|
10446
|
+
on macOS it uses the packaged native backend. A bundled or compiled macOS CLI must use
|
|
10447
|
+
[`createNativePackaging`](./native-io.md) from `stitchkit/files/packaging` at build
|
|
10448
|
+
time. Missing native support and unsupported platforms, including Windows, refuse the download;
|
|
10449
|
+
CLI commands without downloads continue to work. There is no weaker path-based fallback.
|
|
10450
|
+
|
|
10418
10451
|
## Aggregate views
|
|
10419
10452
|
|
|
10420
10453
|
The CLI's audience is agents, scripts and `jq`, so output is JSON. That settles
|
|
@@ -10450,16 +10483,27 @@ myapp item_list --sort messages --top 5 --json # the same five, a
|
|
|
10450
10483
|
myapp item_list --sort name --ascending # ordered the other way
|
|
10451
10484
|
```
|
|
10452
10485
|
|
|
10453
|
-
Groups come back largest first for the same reason
|
|
10486
|
+
Groups come back largest first for the same reason, in the printed bytes even when a key looks
|
|
10487
|
+
like a number; a reader that parses them into a JavaScript object reorders such keys itself.
|
|
10488
|
+
A string equal to `null` or `(absent)` is quoted, so it stays apart from the missing value. A record that carries no
|
|
10454
10489
|
value for the sort field sorts **last in both directions**: it is not the
|
|
10455
10490
|
smallest, it is not on the scale at all, and letting it lead an ascending list
|
|
10456
10491
|
would answer a question nobody asked.
|
|
10457
10492
|
|
|
10458
|
-
|
|
10493
|
+
Rules worth knowing before you rely on them:
|
|
10459
10494
|
|
|
10460
|
-
- **A field
|
|
10495
|
+
- **A field no record carries in a nonempty collection is a presentation error.** A group of zero
|
|
10461
10496
|
over a misspelled field is indistinguishable from a true empty answer, and the
|
|
10462
10497
|
caller reads it as data. The message names the fields that *are* there.
|
|
10498
|
+
Plain and dotted field paths read own properties only at every segment; inherited
|
|
10499
|
+
properties are not record data. Own keys named `constructor`, `prototype` or `toString`
|
|
10500
|
+
are ordinary fields.
|
|
10501
|
+
- **An empty collection is a successful answer.** Count and grouped sums return `{}`,
|
|
10502
|
+
an ungrouped sum returns `0`, and sorted records return `[]`. Tables keep their header
|
|
10503
|
+
and separator without data rows. This applies both to a direct `[]` and to the single
|
|
10504
|
+
array field of an envelope such as `{ items: [], total: 0 }`. With no records, field
|
|
10505
|
+
presence cannot be checked, so a misspelled field answers empty too; malformed paths, unsafe
|
|
10506
|
+
`__proto__` segments and a field of the envelope itself (`--sum total` here) still refuse.
|
|
10463
10507
|
- **An aggregate needs a collection** — the result itself when it is an array,
|
|
10464
10508
|
or the single array field of a result object. An aggregate over a scalar, or
|
|
10465
10509
|
over an object with two array fields, is refused rather than guessed.
|
|
@@ -15342,6 +15386,17 @@ together, only `scope` tells the stack which one is inside.
|
|
|
15342
15386
|
**`active`** (default `true`) switches a layer off without unmounting it;
|
|
15343
15387
|
becoming active again puts it on top of its kind.
|
|
15344
15388
|
|
|
15389
|
+
Layers register, adopt options and clean up in the browser's layout-effect phase.
|
|
15390
|
+
Call the hook before a layout effect that dispatches a key: that effect sees the
|
|
15391
|
+
committed `active`, handler and scope immediately, without waiting for passive
|
|
15392
|
+
effects. Rendering alone never changes the stack; an abandoned render leaves the
|
|
15393
|
+
last committed layer intact. A Suspense boundary that hides committed content
|
|
15394
|
+
disconnects its layout effects, so a layer behind the fallback goes quiet and
|
|
15395
|
+
returns to its place on reveal. The same lifecycle backs `useEscapeLayer` and a
|
|
15396
|
+
zone's outside-key layer. Server rendering installs no listener and does not
|
|
15397
|
+
access `window`. The browser phase is chosen when the module loads, so a test
|
|
15398
|
+
that installs a DOM does so before it imports these hooks.
|
|
15399
|
+
|
|
15345
15400
|
**Fields keep their keys.** Keys pressed in an input, a text area, a select, an
|
|
15346
15401
|
editable region, a combobox, a slider or any area marked `data-local-keys` do not
|
|
15347
15402
|
reach layers — except Escape, which a field that wants it keeps with
|
|
@@ -15393,6 +15448,11 @@ function ChatList({ chats, openId, open }) {
|
|
|
15393
15448
|
| `ignore(event)` | — | a key that is the application's own right now — return `true` and the zone leaves it whole; see [dragging](#a-zone-inside-a-drag-and-drop-list) |
|
|
15394
15449
|
| `onReveal(id)` | — | focus went to an item with no element yet — a row of a virtualized list outside the rendered range; scroll it in, and focus lands on it when it mounts |
|
|
15395
15450
|
|
|
15451
|
+
`role: 'none'` adds neither a container/item role nor `aria-orientation` or
|
|
15452
|
+
`aria-selected`; native links and buttons keep their semantics. The orientation
|
|
15453
|
+
still controls which arrows move focus. Only listbox and tablist zones emit
|
|
15454
|
+
`aria-orientation` (vertical by default).
|
|
15455
|
+
|
|
15396
15456
|
The callbacks return `false` to leave the key to the page, anything else takes
|
|
15397
15457
|
it. A key the zone does not take bubbles on to the layers — in a vertical list
|
|
15398
15458
|
← and → are not the list's keys, so the section switch above hears them.
|
|
@@ -15858,6 +15918,13 @@ cast, and a send cancelled in the queue then waits for its slot and fails as
|
|
|
15858
15918
|
a follow-up call to action after an album costs one more. Reads and edits
|
|
15859
15919
|
(`getMe`, `getFile`, `editMessage*`, `deleteMessage`, `sendChatAction`) do not
|
|
15860
15920
|
spend the budget.
|
|
15921
|
+
- **Two lanes share one rate.** A call is `interactive` by default; a campaign passes
|
|
15922
|
+
`{ lane: 'bulk' }` to `run` or `acquire`, or installs
|
|
15923
|
+
`telegramBudgetTransformer(budget, { lane: 'bulk' })` on its own `Api`. A waiting
|
|
15924
|
+
interactive call is granted first, so a reply never queues behind recipients;
|
|
15925
|
+
the wait it can still see is the interval of the grant before it, up to one
|
|
15926
|
+
album. Bulk runs at whatever rate replies leave, and the sum never exceeds
|
|
15927
|
+
`messagesPerSecond`.
|
|
15861
15928
|
- **The first send after idle is immediate; the rest are spaced.** This is a
|
|
15862
15929
|
strict budget, not a bucket that saves a burst: at 24/s the next send is due
|
|
15863
15930
|
one interval later. A 429 pauses the whole token; when it resumes, one send
|
|
@@ -15869,8 +15936,8 @@ cast, and a send cancelled in the queue then waits for its slot and fails as
|
|
|
15869
15936
|
The refusal may be thrown or returned: a client transformer sits below the
|
|
15870
15937
|
place where grammY turns Telegram's `{ ok: false, error_code: 429, … }` body into
|
|
15871
15938
|
a `GrammyError`, so `run` reads that body too and hands it back unchanged.
|
|
15872
|
-
A 429 from an edit or a read
|
|
15873
|
-
|
|
15939
|
+
A 429 from an edit or a read concerns that call and pauses nothing; `budget.pauseAfter`
|
|
15940
|
+
remains for a caller who decides otherwise. A network failure is rethrown unchanged and stays `unknown`; a 5xx
|
|
15874
15941
|
is rethrown unchanged and stays `server-error`. Neither is retried by the
|
|
15875
15942
|
budget or pauses the token — repeating a send whose outcome is unknown is a
|
|
15876
15943
|
decision, not a primitive's silent guess.
|
|
@@ -16728,6 +16795,88 @@ analytics policy belong to the application.
|
|
|
16728
16795
|
|
|
16729
16796
|
# Upgrading stitchkit
|
|
16730
16797
|
|
|
16798
|
+
## Released migration: 0.116.0
|
|
16799
|
+
|
|
16800
|
+
### send-only-telegram-pause
|
|
16801
|
+
|
|
16802
|
+
**Who must act:** code that relied on a 429 from `editMessage*`, `deleteMessage` or a read to stop a
|
|
16803
|
+
token's sends. Code that only sends needs no change.
|
|
16804
|
+
|
|
16805
|
+
`run` pauses the token only on a method that spends the budget
|
|
16806
|
+
([ADR 0277](../decisions/0277-a-telegram-budget-serves-replies-first.md)). Where an edit must still stop
|
|
16807
|
+
the sends, say so:
|
|
16808
|
+
|
|
16809
|
+
```ts
|
|
16810
|
+
// before
|
|
16811
|
+
await budget.run('editMessageText', payload, signal, send)
|
|
16812
|
+
// after
|
|
16813
|
+
await budget.run('editMessageText', payload, signal, send).catch((error) => {
|
|
16814
|
+
budget.pauseAfter(error)
|
|
16815
|
+
throw error
|
|
16816
|
+
})
|
|
16817
|
+
```
|
|
16818
|
+
|
|
16819
|
+
Search pattern: `budget.run` next to edit and read methods.
|
|
16820
|
+
|
|
16821
|
+
## Released migration: 0.115.0
|
|
16822
|
+
|
|
16823
|
+
### contained-cli-downloads
|
|
16824
|
+
|
|
16825
|
+
**Who must act:** a CLI that uses `--output-dir` on Windows, from a macOS bundle or compiled binary
|
|
16826
|
+
built without `createNativePackaging`, into a directory it cannot write or over bind-mounted files;
|
|
16827
|
+
a coding-tools host that allows `edit` but refuses `read` for a path; and code or CSS that reads
|
|
16828
|
+
`aria-orientation` of a `role: 'none'` zone. A CLI writing into its own directory on Linux or
|
|
16829
|
+
unbundled macOS, and every CLI command without a download, need no change.
|
|
16830
|
+
|
|
16831
|
+
`--output-dir` now writes through a pinned directory descriptor
|
|
16832
|
+
([ADR 0276](../decisions/0276-a-download-writes-through-its-root-capability.md)). There is no
|
|
16833
|
+
path-based fallback, so a platform without that backend refuses the download: the operation still
|
|
16834
|
+
succeeds, its result stays on stdout, stderr names the refusal and the exit is non-zero.
|
|
16835
|
+
|
|
16836
|
+
1. On macOS, build a bundled or compiled CLI with the native packaging plugin:
|
|
16837
|
+
|
|
16838
|
+
```ts
|
|
16839
|
+
// before
|
|
16840
|
+
await Bun.build({
|
|
16841
|
+
entrypoints: ['src/cli.ts'],
|
|
16842
|
+
compile: { target: 'bun-darwin-arm64', outfile: 'dist/cli' },
|
|
16843
|
+
})
|
|
16844
|
+
// after
|
|
16845
|
+
import { createNativePackaging } from 'stitchkit/files/packaging'
|
|
16846
|
+
|
|
16847
|
+
const native = createNativePackaging({
|
|
16848
|
+
platform: 'darwin', architecture: 'arm64', delivery: 'embedded',
|
|
16849
|
+
})
|
|
16850
|
+
if (native.state !== 'ready') throw new Error(native.code)
|
|
16851
|
+
await Bun.build({
|
|
16852
|
+
entrypoints: ['src/cli.ts'],
|
|
16853
|
+
compile: { target: 'bun-darwin-arm64', outfile: 'dist/cli' },
|
|
16854
|
+
plugins: [native.plugin],
|
|
16855
|
+
})
|
|
16856
|
+
```
|
|
16857
|
+
|
|
16858
|
+
A JS bundle uses `delivery: 'companion'`; every shape is in the [native I/O guide](./native-io.md). Search pattern:
|
|
16859
|
+
`createCli` with a `download` option in a project that runs `bun build` for macOS.
|
|
16860
|
+
2. On Windows, run the download through Linux or macOS, or read the URLs from the operation's
|
|
16861
|
+
JSON result and fetch them yourself. Stitchkit offers no weaker path on that platform.
|
|
16862
|
+
3. A download now replaces a file rather than rewriting it. Give the process write permission on
|
|
16863
|
+
the output directory, and do not point it at a bind-mounted file: that refuses with `EBUSY`. A
|
|
16864
|
+
replaced file belongs to the process user, and a read-only file is replaced like any other.
|
|
16865
|
+
4. Read the orientation you configured. A zone with `role: 'none'` has no attribute, and a default
|
|
16866
|
+
would silently turn a horizontal zone vertical:
|
|
16867
|
+
|
|
16868
|
+
```ts
|
|
16869
|
+
// before
|
|
16870
|
+
const axis: ZoneOrientation = zone.zoneProps['aria-orientation']
|
|
16871
|
+
// after
|
|
16872
|
+
const axis: ZoneOrientation = options.orientation ?? 'vertical'
|
|
16873
|
+
```
|
|
16874
|
+
|
|
16875
|
+
Search pattern: `aria-orientation` next to `useNavZone`, and `[aria-orientation]` in CSS and
|
|
16876
|
+
test selectors. Type-check: a read typed as `ZoneOrientation` fails to compile.
|
|
16877
|
+
5. In a coding-tools `authorize`, answer `read` for every path you answer `edit` for. `edit_file`
|
|
16878
|
+
asks both, `read` first.
|
|
16879
|
+
|
|
16731
16880
|
## Released migration: 0.114.0
|
|
16732
16881
|
|
|
16733
16882
|
**Who must act:** code with an exhaustive `switch` or `Record` over
|
|
@@ -23711,7 +23860,7 @@ injected grammY bot. → ADR 0143, ADR 0201, ADR 0274 — [guide](../guide/teleg
|
|
|
23711
23860
|
| `TelegramFetch` / `TelegramBotTransportOpen` / `TelegramBotTransportResolve` / `TelegramBotTransportSocket` | _types_ | the `(url, init) => Promise<Response>` the senders take; the transport's socket factory, resolver and the structural socket it needs (a Node `net.Socket` or `tls.TLSSocket` fits) |
|
|
23712
23861
|
| `TelegramNotDispatchedError` / `TelegramNotDispatchedStage` | class / _type_ | a request that provably never left (`lookup`, `connect` or `request`), so repeating it cannot duplicate a message |
|
|
23713
23862
|
| `TelegramSendFailureReason` / `TELEGRAM_SEND_FAILURE_REASONS` | _type_ / constant | `blocked-by-user` / `user-deactivated` / `chat-not-found` / `not-started` / `bot-to-bot-disabled` / `rate-limited` / `message-invalid` / `server-error` / `not-dispatched` / `unknown`, and the same as a list; a `Record<TelegramSendFailureReason, …>` over them fails to compile when a reason is added |
|
|
23714
|
-
| `telegramOutboundBudget` / `TelegramOutboundBudget` / `TelegramOutboundBudgetConfig` / `TelegramOutboundBudgetStats` | function / _type_ | one token-wide outbound budget: one object per token in the process, strict 24 messages/s by default, weighted albums and multi-message copies, `run(method, payload, signal, send)` as the transformer adapter (a 429 pauses the token whether `send` throws it or resolves with the Bot API's `{ ok: false, … }` body), `pause`/`pauseAfter` for 429, `waitUntilResumed` for non-send retries and `stats`; it paces and never retries, and no public value carries the token |
|
|
23863
|
+
| `telegramOutboundBudget` / `TelegramOutboundBudget` / `TelegramOutboundBudgetConfig` / `TelegramOutboundBudgetStats` / `TelegramOutboundCallOptions` / `TelegramOutboundLane` | function / _type_ | one token-wide outbound budget: one object per token in the process, strict 24 messages/s by default, weighted albums and multi-message copies, an `interactive` lane granted before `bulk`, `run(method, payload, signal, send, { lane })` as the transformer adapter (a 429 on a send pauses the token whether `send` throws it or resolves with the Bot API's `{ ok: false, … }` body), `pause`/`pauseAfter` for 429, `waitUntilResumed` for non-send retries and `stats`; it paces and never retries, and no public value carries the token |
|
|
23715
23864
|
| `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 |
|
|
23716
23865
|
| `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` |
|
|
23717
23866
|
| `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 |
|
|
@@ -24193,9 +24342,9 @@ no component, no styles, no router — see the [keyboard guide](../guide/keyboar
|
|
|
24193
24342
|
|
|
24194
24343
|
| Export | Kind | Summary |
|
|
24195
24344
|
|--------|------|---------|
|
|
24196
|
-
| `useKeyLayer` | hook | put a layer on the window's one key stack
|
|
24345
|
+
| `useKeyLayer` | hook | put a layer on the window's one key stack; registration, options and cleanup follow the browser layout-effect phase, before later layout effects in the caller; asked `overlay` → `local` → `route` → `zone` → `global`, innermost first within a kind |
|
|
24197
24346
|
| `useEscapeLayer` | hook | an `overlay`, `local` or `route` layer for Escape: one press closes one level |
|
|
24198
|
-
| `useNavZone` | hook | a list zone — roving tab stop, arrows move DOM focus, select, highlight or focus mode, cross-axis enter/exit, boundaries, `ignore` for a key the application is using; props carry no key without a value |
|
|
24347
|
+
| `useNavZone` | hook | a list zone — roving tab stop, arrows move DOM focus, select, highlight or focus mode, cross-axis enter/exit, boundaries, `ignore` for a key the application is using; props carry no key without a value; `role: 'none'` omits roles, `aria-orientation` and `aria-selected`, preserving native link/button semantics |
|
|
24199
24348
|
| `nextZoneIndex` | function | where a move lands in a list of a given length: an index, `'before-start'` or `'after-end'` |
|
|
24200
24349
|
| `isKeyFieldTarget` | function | whether a key was pressed in a field or a `data-local-keys` area, the test layers use |
|
|
24201
24350
|
| `KeyLayerOptions` | _type_ | `kind`, `onKey`, `active`, `scope`, `fields`, `phase` — `'capture'` is for a `local` layer only: it hears a key before the element that has focus does, as a menu over a text field must, and a key it takes goes no further |
|