stitchkit 0.105.2 → 0.106.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/dist/agent-runtime/coding-shell-process.d.ts.map +1 -1
- package/dist/agent-runtime/store-conformance-lifecycle.d.ts +10 -10
- package/dist/agent-runtime/store-conformance-support.d.ts +5 -5
- package/dist/entrypoints/agent-runtime/coding-tools.js +2 -2
- package/dist/entrypoints/agent-runtime/sandbox.js +2 -2
- package/dist/entrypoints/process.js +1 -1
- package/dist/{index-3s86a7kf.js → index-4q9jvqg7.js} +216 -51
- package/dist/{index-sevbwsnn.js → index-9bskshe3.js} +2 -4
- package/dist/process/cleanup.d.ts.map +1 -1
- package/dist/process/command-owner.d.ts.map +1 -1
- package/dist/process/contract.d.ts +84 -9
- package/dist/process/contract.d.ts.map +1 -1
- package/dist/process/group.d.ts +12 -0
- package/dist/process/group.d.ts.map +1 -1
- package/dist/process/launch.d.ts +5 -0
- package/dist/process/launch.d.ts.map +1 -1
- package/dist/process/output-drain.d.ts +14 -0
- package/dist/process/output-drain.d.ts.map +1 -0
- package/dist/process/owned-child.d.ts +9 -0
- package/dist/process/owned-child.d.ts.map +1 -1
- package/dist/process/terminate.d.ts +2 -0
- package/dist/process/terminate.d.ts.map +1 -1
- package/dist/process/transport.d.ts +5 -0
- package/dist/process/transport.d.ts.map +1 -1
- package/llms/process.txt +69 -22
- package/llms/stitchkit.txt +3 -3
- package/llms/{upgrading-0.37.0-0.50.0.txt → upgrading-0.37.0-0.53.0.txt} +25 -3
- package/llms/{upgrading-0.53.0-0.67.0.txt → upgrading-0.55.0-0.68.0.txt} +53 -25
- package/llms/{upgrading-0.68.0-0.94.0.txt → upgrading-0.69.0-0.95.0.txt} +45 -53
- package/llms/{upgrading-0.95.0-0.105.0.txt → upgrading-0.96.0-0.106.0.txt} +40 -45
- package/llms/upgrading.txt +4 -4
- package/llms-full.txt +109 -25
- package/llms.txt +5 -5
- package/package.json +3 -3
|
@@ -1,14 +1,56 @@
|
|
|
1
|
-
# Upgrading 0.
|
|
1
|
+
# Upgrading 0.69.0 → 0.95.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.69.0 → 0.95.0 (docs/guide/upgrading.md)
|
|
7
7
|
|
|
8
8
|
==============================================================================
|
|
9
|
-
# Guide: Upgrading, 0.
|
|
9
|
+
# Guide: Upgrading, 0.69.0 → 0.95.0 (docs/guide/upgrading.md)
|
|
10
10
|
==============================================================================
|
|
11
11
|
|
|
12
|
+
## Released migration: 0.95.0
|
|
13
|
+
|
|
14
|
+
One breaking change in `stitchkit/application`: the process lifecycle ledger
|
|
15
|
+
counts downtime as the window nobody answered in, and gains the `draining`
|
|
16
|
+
phase and the `startup-failed` outcome. A ledger file written by an earlier
|
|
17
|
+
version loads unchanged — the new `unavailableAt` reads as `null`.
|
|
18
|
+
|
|
19
|
+
1. **Read downtime from the ready fact.** **Who must act:** a project that
|
|
20
|
+
reads `downtimeMs` from a `started` fact. It is gone from `StartFact`; the
|
|
21
|
+
number it carried is `processGapMs`. The downtime now arrives with the new
|
|
22
|
+
run's readiness:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// before
|
|
26
|
+
ledger.subscribe((fact) => {
|
|
27
|
+
if (fact.type === 'started') report(fact.previousExit, fact.downtimeMs);
|
|
28
|
+
});
|
|
29
|
+
// after
|
|
30
|
+
ledger.subscribe((fact) => {
|
|
31
|
+
if (fact.type === 'started') previousExit = fact.previousExit;
|
|
32
|
+
if (fact.type === 'ready') report(previousExit, fact.downtimeMs);
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
2. **Handle the new values.** **Who must act:** a project that switches
|
|
37
|
+
exhaustively over `LifecycleTermination` (new: `draining`,
|
|
38
|
+
`startup-failed`), `PreviousExit` (new: `startup-failed`) or
|
|
39
|
+
`ProcessLifecycleFact` (new: `DrainingFact`, `type: 'draining'`). The type
|
|
40
|
+
checker names each switch. An open run is `active` or `draining`; a check
|
|
41
|
+
written as `termination === 'active'` to mean "still running" becomes
|
|
42
|
+
`termination === 'active' || termination === 'draining'`.
|
|
43
|
+
`TransitionReadyInput` is renamed `TransitionRunInput` — the same fields,
|
|
44
|
+
now also taken by `transitionProcessDraining`; rename the import.
|
|
45
|
+
|
|
46
|
+
3. **Record the drain and the readiness when driving the ledger by hand.**
|
|
47
|
+
**Who must act:** only a project that calls `createProcessLifecycleLedger`
|
|
48
|
+
methods itself instead of mounting `lifecycleLedgerResource`. Call
|
|
49
|
+
`recordDraining()` where the application stops admitting work, before it
|
|
50
|
+
drains; without it downtime is counted from the recorded stop. Call
|
|
51
|
+
`recordReady()` when the run serves; a run stopped without it now ends
|
|
52
|
+
`startup-failed`, not `clean`.
|
|
53
|
+
|
|
12
54
|
## Released migration: 0.94.0
|
|
13
55
|
|
|
14
56
|
One breaking minor that consolidates: tool options move into one group, and
|
|
@@ -1107,53 +1149,3 @@ else renderExistingRole(message)
|
|
|
1107
1149
|
|
|
1108
1150
|
No data migration is needed. The schema still accepts all earlier records, and applications that
|
|
1109
1151
|
do not exhaustively branch over these unions compile unchanged.
|
|
1110
|
-
|
|
1111
|
-
## Released migration: 0.68.0
|
|
1112
|
-
|
|
1113
|
-
### Make Unix transport selection explicit outside Bun
|
|
1114
|
-
|
|
1115
|
-
The legacy `unix` option remains a Bun convenience, but on Node or another
|
|
1116
|
-
runtime it now fails before dispatch. Replace it with the owned adapter and close
|
|
1117
|
-
that adapter with the application:
|
|
1118
|
-
|
|
1119
|
-
```ts
|
|
1120
|
-
// before — unsafe outside Bun: an unsupported fetch could dial baseUrl over TCP
|
|
1121
|
-
const http = createHttpClient({ baseUrl, unix: '/run/service.sock' })
|
|
1122
|
-
|
|
1123
|
-
// after — Bun and Node; every dispatch and redirect stays on the socket
|
|
1124
|
-
import { createUnixClientTransport } from 'stitchkit/server' // or stitchkit/node
|
|
1125
|
-
const transport = createUnixClientTransport({ socketPath: '/run/service.sock' })
|
|
1126
|
-
const http = createHttpClient({ baseUrl, fetch: transport.fetch })
|
|
1127
|
-
// during shutdown
|
|
1128
|
-
await transport.close()
|
|
1129
|
-
```
|
|
1130
|
-
|
|
1131
|
-
Do not automatically replay `possibly-dispatched`: a timeout or connection loss
|
|
1132
|
-
after bytes left the process does not prove that a write did not happen.
|
|
1133
|
-
|
|
1134
|
-
### Choose tolerant stream parsing explicitly
|
|
1135
|
-
|
|
1136
|
-
`parseNDJSON` and `parseSSE` now throw on malformed JSON, invalid UTF-8 and an
|
|
1137
|
-
over-limit line. The default line ceiling is 1 MiB. If a feed deliberately skips
|
|
1138
|
-
bad records, retain that policy explicitly:
|
|
1139
|
-
|
|
1140
|
-
```ts
|
|
1141
|
-
// before — malformed input disappeared implicitly
|
|
1142
|
-
parseNDJSON(response)
|
|
1143
|
-
|
|
1144
|
-
// after — ordinary fail-closed path
|
|
1145
|
-
parseNDJSON(response, { maxLineBytes: 256 * 1024 })
|
|
1146
|
-
|
|
1147
|
-
// after — deliberately tolerant path
|
|
1148
|
-
parseNDJSON(response, { onParseError: (raw, error) => report(raw, error) })
|
|
1149
|
-
```
|
|
1150
|
-
|
|
1151
|
-
### Extend exhaustive framework-error handling
|
|
1152
|
-
|
|
1153
|
-
If a switch makes `StitchErrorCode` exhaustive, add
|
|
1154
|
-
`STREAM_ITEM_INVALID`, `STREAM_FRAME_TOO_LARGE`,
|
|
1155
|
-
`STREAM_TERMINAL_MISSING` and `STREAM_LIFETIME_EXCEEDED`. A partial application
|
|
1156
|
-
status map needs no change (ADR 0105).
|
|
1157
|
-
|
|
1158
|
-
The admission/channel APIs and endpoint `stream` descriptor are additive; raw
|
|
1159
|
-
responses and raw `streamingRoute` remain supported.
|
|
@@ -1,14 +1,51 @@
|
|
|
1
|
-
# Upgrading 0.
|
|
1
|
+
# Upgrading 0.96.0 → 0.106.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.96.0 → 0.106.0 (docs/guide/upgrading.md)
|
|
7
7
|
|
|
8
8
|
==============================================================================
|
|
9
|
-
# Guide: Upgrading, 0.
|
|
9
|
+
# Guide: Upgrading, 0.96.0 → 0.106.0 (docs/guide/upgrading.md)
|
|
10
10
|
==============================================================================
|
|
11
11
|
|
|
12
|
+
## Released migration: 0.106.0
|
|
13
|
+
|
|
14
|
+
### a stopped leader settles as stopped
|
|
15
|
+
|
|
16
|
+
**Who must act:** code passed to `onLeaderSettled` of `runNativeCommand` (`stitchkit/process`) that
|
|
17
|
+
reads `kind: 'error'` as "the command was stopped". Code that only handles `kind: 'exit'`, or does
|
|
18
|
+
not pass `onLeaderSettled`, needs no change.
|
|
19
|
+
|
|
20
|
+
A command stopped by a caller abort, its `timeoutMs`, an exceeded output budget or a failing sink
|
|
21
|
+
used to settle at once as `{ kind: 'error', cause }`. It now waits for the stop signals and settles
|
|
22
|
+
as `{ kind: 'stopped', cause, exitCode, signal }`, with how the kernel reported the leader's end
|
|
23
|
+
([ADR 0248](../decisions/0248-a-stopped-leader-settles-with-its-exit-and-a-command-may-join-the-callers-group.md)).
|
|
24
|
+
`'error'` is left for a leader whose exit was never observed.
|
|
25
|
+
|
|
26
|
+
1. Where the hook handled a stop under `'error'`, handle `'stopped'` there, and take the exit from
|
|
27
|
+
the event instead of reading the child process:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// before
|
|
31
|
+
onLeaderSettled: (event) => {
|
|
32
|
+
if (event.kind === 'exit') record(event.exitCode, event.signal)
|
|
33
|
+
else stopped(event.cause)
|
|
34
|
+
}
|
|
35
|
+
// after
|
|
36
|
+
onLeaderSettled: (event) => {
|
|
37
|
+
if (event.kind === 'error') return failed(event.cause)
|
|
38
|
+
record(event.exitCode, event.signal)
|
|
39
|
+
if (event.kind === 'stopped') stopped(event.cause)
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Search pattern: `onLeaderSettled` together with `kind === 'error'` or `kind !== 'exit'`.
|
|
44
|
+
2. Type-check: an exhaustive `switch (event.kind)` without a `'stopped'` case fails on the new kind.
|
|
45
|
+
3. A hook that stops an external scope on a stopped command now runs once the leader is gone,
|
|
46
|
+
still bounded by `cleanupTimeoutMs`; no change is needed unless the leader waited for that scope
|
|
47
|
+
to exit (it gets KILL when the grace ends either way).
|
|
48
|
+
|
|
12
49
|
## Released migration: 0.105.0
|
|
13
50
|
|
|
14
51
|
### CLI publication has its own entrypoint
|
|
@@ -895,45 +932,3 @@ it; only a context built by hand needs it.
|
|
|
895
932
|
hand before `bot.stop()`. A project that wrote its own `getUpdates`
|
|
896
933
|
transformer for this (waiting on `app.admission` before returning a batch)
|
|
897
934
|
deletes it; keeping both waits twice and is harmless.
|
|
898
|
-
|
|
899
|
-
## Released migration: 0.95.0
|
|
900
|
-
|
|
901
|
-
One breaking change in `stitchkit/application`: the process lifecycle ledger
|
|
902
|
-
counts downtime as the window nobody answered in, and gains the `draining`
|
|
903
|
-
phase and the `startup-failed` outcome. A ledger file written by an earlier
|
|
904
|
-
version loads unchanged — the new `unavailableAt` reads as `null`.
|
|
905
|
-
|
|
906
|
-
1. **Read downtime from the ready fact.** **Who must act:** a project that
|
|
907
|
-
reads `downtimeMs` from a `started` fact. It is gone from `StartFact`; the
|
|
908
|
-
number it carried is `processGapMs`. The downtime now arrives with the new
|
|
909
|
-
run's readiness:
|
|
910
|
-
|
|
911
|
-
```ts
|
|
912
|
-
// before
|
|
913
|
-
ledger.subscribe((fact) => {
|
|
914
|
-
if (fact.type === 'started') report(fact.previousExit, fact.downtimeMs);
|
|
915
|
-
});
|
|
916
|
-
// after
|
|
917
|
-
ledger.subscribe((fact) => {
|
|
918
|
-
if (fact.type === 'started') previousExit = fact.previousExit;
|
|
919
|
-
if (fact.type === 'ready') report(previousExit, fact.downtimeMs);
|
|
920
|
-
});
|
|
921
|
-
```
|
|
922
|
-
|
|
923
|
-
2. **Handle the new values.** **Who must act:** a project that switches
|
|
924
|
-
exhaustively over `LifecycleTermination` (new: `draining`,
|
|
925
|
-
`startup-failed`), `PreviousExit` (new: `startup-failed`) or
|
|
926
|
-
`ProcessLifecycleFact` (new: `DrainingFact`, `type: 'draining'`). The type
|
|
927
|
-
checker names each switch. An open run is `active` or `draining`; a check
|
|
928
|
-
written as `termination === 'active'` to mean "still running" becomes
|
|
929
|
-
`termination === 'active' || termination === 'draining'`.
|
|
930
|
-
`TransitionReadyInput` is renamed `TransitionRunInput` — the same fields,
|
|
931
|
-
now also taken by `transitionProcessDraining`; rename the import.
|
|
932
|
-
|
|
933
|
-
3. **Record the drain and the readiness when driving the ledger by hand.**
|
|
934
|
-
**Who must act:** only a project that calls `createProcessLifecycleLedger`
|
|
935
|
-
methods itself instead of mounting `lifecycleLedgerResource`. Call
|
|
936
|
-
`recordDraining()` where the application stops admitting work, before it
|
|
937
|
-
drains; without it downtime is counted from the recorded stop. Call
|
|
938
|
-
`recordReady()` when the run serves; a run stopped without it now ends
|
|
939
|
-
`startup-failed`, not `clean`.
|
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.37.0 → 0.
|
|
14
|
+
- 0.96.0 → 0.106.0: `llms/upgrading-0.96.0-0.106.0.txt`
|
|
15
|
+
- 0.69.0 → 0.95.0: `llms/upgrading-0.69.0-0.95.0.txt`
|
|
16
|
+
- 0.55.0 → 0.68.0: `llms/upgrading-0.55.0-0.68.0.txt`
|
|
17
|
+
- 0.37.0 → 0.53.0: `llms/upgrading-0.37.0-0.53.0.txt`
|
|
18
18
|
|
|
19
19
|
# Upgrading stitchkit
|
|
20
20
|
|
package/llms-full.txt
CHANGED
|
@@ -74,12 +74,12 @@ own, recorded as an ADR.
|
|
|
74
74
|
| `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
|
|
75
75
|
| `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
|
|
76
76
|
| `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
|
|
77
|
-
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the
|
|
77
|
+
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the 51 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
|
|
78
78
|
| `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, plus the managed-resource conformance kit |
|
|
79
79
|
| `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
|
|
80
80
|
| `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
|
|
81
81
|
| `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) |
|
|
82
|
-
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 23 of the
|
|
82
|
+
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 23 of the 51 minors since 0.56.2, most recently 0.105.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
|
|
83
83
|
| `stitchkit/agent-runtime/sandbox` | server | evolving | optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see [sandbox guide](sandbox.md) |
|
|
84
84
|
| `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 |
|
|
85
85
|
| `stitchkit/agent-runtime/harness` | server | evolving | resource-aware process-local facade over the canonical Agent runtime; supervision stays outside |
|
|
@@ -91,7 +91,7 @@ own, recorded as an ADR.
|
|
|
91
91
|
| `stitchkit/agent-runtime/sqlite/bun` | server (Bun) | evolving | durable built-in SQLite store for the agent runtime |
|
|
92
92
|
| `stitchkit/agent-runtime/sqlite/node` | server (Node ≥ 22.5) | evolving | durable built-in SQLite store for the agent runtime |
|
|
93
93
|
| `stitchkit-tui` | terminal (Bun) | evolving | optional official OpenTUI host over a caller-composed headless runtime |
|
|
94
|
-
| `stitchkit/application` | browser + server | evolving<br>_redefined in 13 of the
|
|
94
|
+
| `stitchkit/application` | browser + server | evolving<br>_redefined in 13 of the 51 minors since 0.56.2, most recently 0.105.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
|
|
95
95
|
| `stitchkit/application/grammy` | server | evolving | a grammY bot as application resources — configuration, then polling with updates admitted by batch — and the webhook adapter |
|
|
96
96
|
| `stitchkit/application/opentelemetry` | server | evolving | maps application snapshots onto an injected OpenTelemetry `Meter` |
|
|
97
97
|
| `stitchkit/application/schemas` | browser + server | evolving | the application's snapshot, health and shutdown schemas alone, without the kernel |
|
|
@@ -8355,7 +8355,9 @@ command the same way, by its `stop` policy:
|
|
|
8355
8355
|
| `graceMs` | How long the leader (or the group) has to leave before the whole group gets KILL. 0 to 3 600 000 (one hour). Required. |
|
|
8356
8356
|
| `killOn` | Optional `AbortSignal`. Its abort stops the command with KILL to the whole group at once, also in the middle of a grace. |
|
|
8357
8357
|
|
|
8358
|
-
Omitting `stop` means `{ target: 'group', signal: 'SIGTERM', graceMs: 100 }
|
|
8358
|
+
Omitting `stop` means `{ target: 'group', signal: 'SIGTERM', graceMs: 100 }`; a command in the
|
|
8359
|
+
caller's group (`group: 'caller'`) stops its leader alone, so its default is `target: 'leader'`
|
|
8360
|
+
and a group target is refused (see [Terminal commands](#terminal-commands-inherited-stdio-and-the-callers-group)).
|
|
8359
8361
|
|
|
8360
8362
|
```ts
|
|
8361
8363
|
// Cooperative cancellation: the leader rolls its work back, its helpers are not asked.
|
|
@@ -8410,13 +8412,15 @@ so a helper started in the background races the leader:
|
|
|
8410
8412
|
|
|
8411
8413
|
| launched by the leader as | after the leader exits |
|
|
8412
8414
|
|---|---|
|
|
8413
|
-
| `setsid -f helper`
|
|
8415
|
+
| `setsid -f helper` | usually survives: `setsid -f` forks and returns at once, and the child calls `setsid()` a moment later, so a leader that exits immediately can still catch it in the group (13 of 300 launches under CPU load) |
|
|
8414
8416
|
| `setsid helper &`, `(setsid helper &)`, `nohup helper &` | stopped: the leader usually exits before the background job has left the group |
|
|
8417
|
+
| a launch the leader waits on until the helper reports it has left the group | survives |
|
|
8415
8418
|
| any of these under `descendants: 'leave'` | survives |
|
|
8416
8419
|
|
|
8417
|
-
Start a daemon so that the
|
|
8418
|
-
|
|
8419
|
-
`'leave'` only for a helper that has to outlive the command while
|
|
8420
|
+
Start a daemon so that the leader waits for the session to exist before it returns: the helper
|
|
8421
|
+
writes its pid, or prints a line, only after its own `setsid()`, and the leader waits for that.
|
|
8422
|
+
Or declare `'leave'`. Declare `'leave'` only for a helper that has to outlive the command while
|
|
8423
|
+
staying in its group:
|
|
8420
8424
|
|
|
8421
8425
|
```ts
|
|
8422
8426
|
await runNativeCommand({
|
|
@@ -8426,7 +8430,8 @@ await runNativeCommand({
|
|
|
8426
8430
|
})
|
|
8427
8431
|
```
|
|
8428
8432
|
|
|
8429
|
-
A command
|
|
8433
|
+
A command in the caller's group (`group: 'caller'`) has no group of its own: `descendants` is
|
|
8434
|
+
refused there and nothing is stopped after its leader exits. A command whose group this package did not create (a structural
|
|
8430
8435
|
launcher supplied by a host) has no group to stop, and `descendants` has nothing to act on there.
|
|
8431
8436
|
|
|
8432
8437
|
|
|
@@ -8442,26 +8447,68 @@ bounded tar or capture commands get their own explicit limits.
|
|
|
8442
8447
|
A child the caller holds until it exits is the same call. A guardian that forwards its own SIGTERM
|
|
8443
8448
|
passes an abort signal and `stop: { target: 'leader', signal: 'SIGTERM', graceMs }`. It records the
|
|
8444
8449
|
pid in `onLeaderStarted({ pid })`, which runs once right after the leader exists (a throw stops the
|
|
8445
|
-
command with that error),
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
`
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
terminal is stopped by the kernel (`SIGTTIN`), so an interactive re-execution stays a plain
|
|
8454
|
-
spawn in the caller's group. Importing one leaf does not make
|
|
8450
|
+
command with that error), and the leader's exit code and signal in `onLeaderSettled`: `'exit'`
|
|
8451
|
+
when the leader ended on its own, `'stopped'` with the same fields when the guardian stopped it.
|
|
8452
|
+
It reads stderr through `onOutput` or `capture` with `maxOutputBytes`. `drainTimeoutMs` bounds how
|
|
8453
|
+
long the output pipes may stay open after the leader exited: a holder that left the group with
|
|
8454
|
+
`setsid` keeps them open, and without the option the command waits for it until `timeoutMs` or
|
|
8455
|
+
the signal; with it the command ends with `COMMAND_CLEANUP` (a holder inside the group is already
|
|
8456
|
+
stopped by `descendants`). A worker whose whole group must stop on abort is the default
|
|
8457
|
+
`target: 'group'`. A command that uses the caller's terminal is the next section. Importing one leaf does not make
|
|
8455
8458
|
installing the whole npm package smaller; choose a dependency after measuring packed size and its
|
|
8456
8459
|
dependency closure.
|
|
8457
8460
|
|
|
8461
|
+
## Terminal commands: inherited stdio and the caller's group
|
|
8462
|
+
|
|
8463
|
+
An operator CLI that re-runs itself, or any command that prompts or prints in colour, needs the
|
|
8464
|
+
caller's terminal itself rather than pipes. Two options give it that:
|
|
8465
|
+
|
|
8466
|
+
```ts
|
|
8467
|
+
const { exitCode } = await runNativeCommand({
|
|
8468
|
+
executable: process.execPath, args: [cliPath, ...argv], envPolicy: 'ambient',
|
|
8469
|
+
signal: shutdown.signal,
|
|
8470
|
+
stdio: 'inherit', // the command's stdin, stdout and stderr are the caller's: a TTY stays a TTY
|
|
8471
|
+
group: 'caller', // it joins the caller's process group, so a Ctrl-C at the terminal reaches it
|
|
8472
|
+
})
|
|
8473
|
+
process.exitCode = exitCode ?? 1
|
|
8474
|
+
```
|
|
8475
|
+
|
|
8476
|
+
`stdio: 'inherit'` hands the caller's three descriptors to the command; its bytes never pass
|
|
8477
|
+
through this package, so `capture`, `onOutput`, `stdin`, `maxOutputBytes` and `drainTimeoutMs` are
|
|
8478
|
+
refused by name with it, and the result's buffers stay empty.
|
|
8479
|
+
|
|
8480
|
+
`group: 'caller'` keeps the command in the caller's process group instead of a group of its own.
|
|
8481
|
+
That is what an interactive command needs: the terminal sends Ctrl-C to its foreground group,
|
|
8482
|
+
and a command in a group of its own is a background group there, which the kernel stops
|
|
8483
|
+
(`SIGTTIN`) as soon as it reads the terminal. In the caller's group the command has no group of
|
|
8484
|
+
its own, so:
|
|
8485
|
+
|
|
8486
|
+
- a stop signals the leader alone: `stop.target` is `'leader'` (the default here is
|
|
8487
|
+
`{ target: 'leader', signal: 'SIGTERM', graceMs: 100 }`), and `target: 'group'` is refused,
|
|
8488
|
+
because a group signal would reach the caller;
|
|
8489
|
+
- `descendants` does not apply and is refused: what the leader leaves behind belongs to the
|
|
8490
|
+
caller's group, and `descendantsStopped` is always `false`;
|
|
8491
|
+
- a Ctrl-C reaches the caller too; handle `SIGINT` in the caller when it must outlive the command.
|
|
8492
|
+
|
|
8493
|
+
The two options are independent: `stdio: 'inherit'` alone keeps colour and `isatty` for a command
|
|
8494
|
+
that never reads the terminal, and `group: 'caller'` alone forwards Ctrl-C to a piped command.
|
|
8495
|
+
|
|
8458
8496
|
## Resource-scoped launchers and shared owners
|
|
8459
8497
|
|
|
8460
8498
|
`onLeaderSettled(event, signal)` observes leader exit before inherited stdout/stderr pipes
|
|
8461
8499
|
close. A resource owner can stop its external scope there, allowing pipe drain to complete.
|
|
8462
|
-
The callback runs once
|
|
8463
|
-
|
|
8464
|
-
|
|
8500
|
+
The callback runs once, with one of three events:
|
|
8501
|
+
|
|
8502
|
+
| `event.kind` | when | carries |
|
|
8503
|
+
|---|---|---|
|
|
8504
|
+
| `'exit'` | the leader ended on its own | `exitCode`, `signal` as the kernel reported them |
|
|
8505
|
+
| `'stopped'` | the command was stopped (caller abort, `timeoutMs`, output budget, failing sink) and the leader's exit after the stop signals was observed | the stop's `cause`, and the leader's `exitCode` and `signal` (for example `SIGTERM`, or `SIGKILL` once the grace ended) |
|
|
8506
|
+
| `'error'` | no exit of the leader was observed: it could not start, or its exit did not arrive within `cleanupTimeoutMs` | the `cause` |
|
|
8507
|
+
|
|
8508
|
+
A leader that ended on its own settles before the pipes drain; a stopped one settles after the
|
|
8509
|
+
stop sequence, once its exit is known. A stop that comes after the leader already exited (a
|
|
8510
|
+
deadline while a helper holds the pipe) does not change its `'exit'` event. Unavailable
|
|
8511
|
+
executables, output sink failure and caller cancellation settle through the same owner. Synchronous native launch
|
|
8465
8512
|
failures such as `E2BIG` also return a rejected result after this bounded settlement;
|
|
8466
8513
|
schema-invalid and already-aborted inputs refuse before native ownership and do not invoke
|
|
8467
8514
|
the hook. A failing hook preserves both the initial launch error and cleanup cause.
|
|
@@ -15533,6 +15580,43 @@ analytics policy belong to the application.
|
|
|
15533
15580
|
|
|
15534
15581
|
# Upgrading stitchkit
|
|
15535
15582
|
|
|
15583
|
+
## Released migration: 0.106.0
|
|
15584
|
+
|
|
15585
|
+
### a stopped leader settles as stopped
|
|
15586
|
+
|
|
15587
|
+
**Who must act:** code passed to `onLeaderSettled` of `runNativeCommand` (`stitchkit/process`) that
|
|
15588
|
+
reads `kind: 'error'` as "the command was stopped". Code that only handles `kind: 'exit'`, or does
|
|
15589
|
+
not pass `onLeaderSettled`, needs no change.
|
|
15590
|
+
|
|
15591
|
+
A command stopped by a caller abort, its `timeoutMs`, an exceeded output budget or a failing sink
|
|
15592
|
+
used to settle at once as `{ kind: 'error', cause }`. It now waits for the stop signals and settles
|
|
15593
|
+
as `{ kind: 'stopped', cause, exitCode, signal }`, with how the kernel reported the leader's end
|
|
15594
|
+
([ADR 0248](../decisions/0248-a-stopped-leader-settles-with-its-exit-and-a-command-may-join-the-callers-group.md)).
|
|
15595
|
+
`'error'` is left for a leader whose exit was never observed.
|
|
15596
|
+
|
|
15597
|
+
1. Where the hook handled a stop under `'error'`, handle `'stopped'` there, and take the exit from
|
|
15598
|
+
the event instead of reading the child process:
|
|
15599
|
+
|
|
15600
|
+
```ts
|
|
15601
|
+
// before
|
|
15602
|
+
onLeaderSettled: (event) => {
|
|
15603
|
+
if (event.kind === 'exit') record(event.exitCode, event.signal)
|
|
15604
|
+
else stopped(event.cause)
|
|
15605
|
+
}
|
|
15606
|
+
// after
|
|
15607
|
+
onLeaderSettled: (event) => {
|
|
15608
|
+
if (event.kind === 'error') return failed(event.cause)
|
|
15609
|
+
record(event.exitCode, event.signal)
|
|
15610
|
+
if (event.kind === 'stopped') stopped(event.cause)
|
|
15611
|
+
}
|
|
15612
|
+
```
|
|
15613
|
+
|
|
15614
|
+
Search pattern: `onLeaderSettled` together with `kind === 'error'` or `kind !== 'exit'`.
|
|
15615
|
+
2. Type-check: an exhaustive `switch (event.kind)` without a `'stopped'` case fails on the new kind.
|
|
15616
|
+
3. A hook that stops an external scope on a stopped command now runs once the leader is gone,
|
|
15617
|
+
still bounded by `cleanupTimeoutMs`; no change is needed unless the leader waited for that scope
|
|
15618
|
+
to exit (it gets KILL when the grace ends either way).
|
|
15619
|
+
|
|
15536
15620
|
## Released migration: 0.105.0
|
|
15537
15621
|
|
|
15538
15622
|
### CLI publication has its own entrypoint
|
|
@@ -22646,12 +22730,12 @@ Native POSIX Bun/Node one-shot command execution. See [native IO](../guide/nativ
|
|
|
22646
22730
|
| Export | Kind | Purpose |
|
|
22647
22731
|
|---|---|---|
|
|
22648
22732
|
| `runNativeCommand` | function | caller-lifetime streaming or explicitly bounded binary capture |
|
|
22649
|
-
| `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`); `onLeaderStarted({ pid })` (once, after the leader exists), `drainTimeoutMs` (bound on the pipes staying open after the leader exited, `COMMAND_CLEANUP`); an unknown key is refused by name, a removed one (`killGraceMs`) with its replacement |
|
|
22733
|
+
| `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`); `stdio` (`'pipe'`, or `'inherit'` for the caller's descriptors, refusing the pipe-only options) and `group` (`'own'`, or `'caller'`: joins the caller's process group, stops only the leader, refuses `descendants` and a group stop); `onLeaderStarted({ pid })` (once, after the leader exists), `drainTimeoutMs` (bound on the pipes staying open after the leader exited, `COMMAND_CLEANUP`); an unknown key is refused by name, a removed one (`killGraceMs`) with its replacement |
|
|
22650
22734
|
| `NativeCommandStopPolicy` | type | how a cancelled command stops: `target` `'group'` (signal every member) or `'leader'` (signal only the leader; its exit ends the grace), `signal` (default `SIGTERM`), `graceMs` (at most one hour) before KILL to the group, and `killOn`, an `AbortSignal` that skips the grace; default `{ target: 'group', signal: 'SIGTERM', graceMs: 100 }` |
|
|
22651
22735
|
| `NativeCommandResult` | type | observed nullable exit code/signal, `descendantsStopped` (members left in the group after the leader exited were stopped) and captured stdout/stderr bytes |
|
|
22652
|
-
| `NativeCommandError` | class | COMMAND_LIMIT with machine reason `deadline` or `output-budget`; COMMAND_UNAVAILABLE / COMMAND_CLEANUP have no limit reason. Preserves internal cause and existing constructor; caller-created limits without supplied reason remain unclassified |
|
|
22736
|
+
| `NativeCommandError` | class | COMMAND_LIMIT with machine reason `deadline` or `output-budget`; COMMAND_UNAVAILABLE / COMMAND_CLEANUP have no limit reason; COMMAND_CLEANUP means the command's resources were not proven closed, either past `cleanupTimeoutMs` after a stop or past `drainTimeoutMs` after the leader exited, and `cause` holds that bound's failure. Preserves internal cause and existing constructor; caller-created limits without supplied reason remain unclassified |
|
|
22653
22737
|
|
|
22654
|
-
| `NativeCommandSettlement` | type |
|
|
22738
|
+
| `NativeCommandSettlement` | type | `exit` (the leader ended on its own), `stopped` (the command was stopped and the leader's exit after the stop observed: the stop's `cause` with `exitCode`/`signal`) or `error` (no exit observed), including synchronous native launch failure; `onLeaderSettled` runs once before drain, bounded by cleanupTimeoutMs, with a cancellable settlement signal; schema/pre-abort refusal creates no settlement obligation |
|
|
22655
22739
|
| `observeProcessInstance` / `ProcessInstanceObservation` | function / type | Linux/Darwin lifetime observation; observed identity or unavailable with its original cause, never guessed absence |
|
|
22656
22740
|
| `ProcessInstanceSchema` / `ProcessInstance` | schema / type | platform, boot ID, namespace and process start identity from the shared native reader |
|
|
22657
22741
|
| `probeProcessOwner` / `ProcessOwnerEvidence` | function / type | compare lifetimes on one caller-established machine; matched, boot change, reused PID, gone, legacy or unavailable with cause |
|
package/llms.txt
CHANGED
|
@@ -56,15 +56,15 @@ Load the slice for each entrypoint your code imports — `import … from 'stitc
|
|
|
56
56
|
- **stitchkit/node**: [llms/node.txt](llms/node.txt) 3.1 KB
|
|
57
57
|
- **stitchkit/agent-runtime/react**: [llms/agent-runtime-react.txt](llms/agent-runtime-react.txt) 1.0 KB
|
|
58
58
|
- **stitchkit/agent-runtime/realtime**: [llms/agent-runtime-realtime.txt](llms/agent-runtime-realtime.txt) 2.6 KB
|
|
59
|
-
- **stitchkit/process**: [llms/process.txt](llms/process.txt)
|
|
59
|
+
- **stitchkit/process**: [llms/process.txt](llms/process.txt) 39.9 KB
|
|
60
60
|
- **stitchkit/files/packaging**: [llms/files-packaging.txt](llms/files-packaging.txt) 2.8 KB
|
|
61
61
|
|
|
62
62
|
## Upgrading slices
|
|
63
63
|
- **Upgrading — how to move across versions**: [llms/upgrading.txt](llms/upgrading.txt) 10.3 KB
|
|
64
|
-
- **Upgrading 0.
|
|
65
|
-
- **Upgrading 0.
|
|
66
|
-
- **Upgrading 0.
|
|
67
|
-
- **Upgrading 0.37.0 → 0.
|
|
64
|
+
- **Upgrading 0.96.0 → 0.106.0**: [llms/upgrading-0.96.0-0.106.0.txt](llms/upgrading-0.96.0-0.106.0.txt) 46.6 KB
|
|
65
|
+
- **Upgrading 0.69.0 → 0.95.0**: [llms/upgrading-0.69.0-0.95.0.txt](llms/upgrading-0.69.0-0.95.0.txt) 46.6 KB
|
|
66
|
+
- **Upgrading 0.55.0 → 0.68.0**: [llms/upgrading-0.55.0-0.68.0.txt](llms/upgrading-0.55.0-0.68.0.txt) 47.0 KB
|
|
67
|
+
- **Upgrading 0.37.0 → 0.53.0**: [llms/upgrading-0.37.0-0.53.0.txt](llms/upgrading-0.37.0-0.53.0.txt) 32.6 KB
|
|
68
68
|
|
|
69
69
|
## Guide (web)
|
|
70
70
|
- [Getting started](https://github.com/max-listov/stitchkit/blob/master/docs/guide/getting-started.md): install, entrypoints, and a first contract → server → client app
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stitchkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.106.1",
|
|
4
4
|
"description": "Contract-first backend framework — one defineContract() into an HTTP API, MCP tools, AI-agent tools and a typed client. Bun and Node.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -265,10 +265,10 @@
|
|
|
265
265
|
"build:unlocked": "rm -rf dist && cp ../../CHANGELOG.md ./CHANGELOG.md && bun run build:js && chmod +x dist/entrypoints/bin/upgrade-cli.js && bun run build:types && bun scripts/check-browser-clean.mjs && bun scripts/check-browser-executes.mjs && bun scripts/check-env-live.mjs && bun scripts/check-public-types.mjs && bun scripts/check-durability-port-standalone.mjs && bun scripts/check-declarations-strict.mjs",
|
|
266
266
|
"dev": "bun run build:entrypoints -- --watch",
|
|
267
267
|
"prepack": "bun ../../scripts/sync-package-readme.ts && bun ../../scripts/gen-llms.ts && bun run build",
|
|
268
|
-
"test": "bun test",
|
|
268
|
+
"test": "bun ../../scripts/test-leak-gate.ts -- bun test",
|
|
269
269
|
"smoke:node": "node scripts/node-smoke.mjs",
|
|
270
270
|
"smoke:next-ssr": "node scripts/next-ssr-retry-smoke.mjs",
|
|
271
|
-
"consumer-lane": "bun scripts/consumer-lane/run.mjs",
|
|
271
|
+
"consumer-lane": "bun ../../scripts/test-leak-gate.ts -- bun scripts/consumer-lane/run.mjs",
|
|
272
272
|
"bench:mcp-preparation": "bun scripts/benchmark-mcp-preparation.ts",
|
|
273
273
|
"bench:durable-store": "bun scripts/bench-durable-store.ts",
|
|
274
274
|
"build:entrypoints": "bun scripts/generate-native-assets.ts && bun scripts/build-entrypoints.mjs"
|