stitchkit 0.103.8 → 0.103.10
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 +21 -0
- package/dist/agent-runtime/sandbox-process.d.ts +2 -2
- package/dist/agent-runtime/sandbox-process.d.ts.map +1 -1
- package/dist/agent-runtime/store-conformance-lifecycle.d.ts +10 -10
- package/dist/durability/contract.d.ts +3 -2
- package/dist/durability/contract.d.ts.map +1 -1
- package/dist/durability/effect.d.ts.map +1 -1
- package/dist/durability/engine.d.ts.map +1 -1
- package/dist/durability/json.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/harness.js +2 -2
- package/dist/entrypoints/agent-runtime/sandbox.js +29 -81
- package/dist/entrypoints/agent-runtime.js +2 -2
- package/dist/entrypoints/application/diagnostic-journal.js +2 -1
- package/dist/entrypoints/cli.js +1 -1
- package/dist/entrypoints/files.d.ts +2 -0
- package/dist/entrypoints/files.d.ts.map +1 -1
- package/dist/entrypoints/files.js +14 -6
- package/dist/entrypoints/primitives.js +77 -57
- package/dist/entrypoints/process.d.ts +5 -0
- package/dist/entrypoints/process.d.ts.map +1 -0
- package/dist/entrypoints/process.js +20 -0
- package/dist/entrypoints/tools.js +12 -3
- package/dist/files/boundary.d.ts +19 -1
- package/dist/files/boundary.d.ts.map +1 -1
- package/dist/files/file-io.d.ts +5 -1
- package/dist/files/file-io.d.ts.map +1 -1
- package/dist/files/read.d.ts +13 -0
- package/dist/files/read.d.ts.map +1 -0
- package/dist/index-12m2v2a9.js +98 -0
- package/dist/index-6m6a9ty4.js +285 -0
- package/dist/index-8a9ksm91.js +95 -0
- package/dist/{index-90ppdx3q.js → index-9jb61j5a.js} +1 -1
- package/dist/{index-5vyd0fkb.js → index-ary5s7k0.js} +40 -61
- package/dist/index-c1jmtxa0.js +74 -0
- package/dist/index-ga597cvy.js +184 -0
- package/dist/index-mbnnw3f2.js +25 -0
- package/dist/index-nybn2err.js +213 -0
- package/dist/{index-v4a2fjtk.js → index-sybedc8b.js} +124 -55
- package/dist/internal/abort-race.d.ts +3 -0
- package/dist/internal/abort-race.d.ts.map +1 -0
- package/dist/internal/atomic-file.d.ts +20 -2
- package/dist/internal/atomic-file.d.ts.map +1 -1
- package/dist/internal/atomic-publication.d.ts +19 -0
- package/dist/internal/atomic-publication.d.ts.map +1 -0
- package/dist/internal/exclusive-lock.d.ts +2 -1
- package/dist/internal/exclusive-lock.d.ts.map +1 -1
- package/dist/internal/json-data.d.ts +8 -0
- package/dist/internal/json-data.d.ts.map +1 -0
- package/dist/internal/process-instance.d.ts +46 -9
- package/dist/internal/process-instance.d.ts.map +1 -1
- package/dist/internal/with-exclusive-lock.d.ts +4 -3
- package/dist/internal/with-exclusive-lock.d.ts.map +1 -1
- package/dist/primitives/canonical-json.d.ts +11 -0
- package/dist/primitives/canonical-json.d.ts.map +1 -0
- package/dist/primitives/index.d.ts +1 -0
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/process/command-owner.d.ts +13 -0
- package/dist/process/command-owner.d.ts.map +1 -0
- package/dist/process/command.d.ts +3 -0
- package/dist/process/command.d.ts.map +1 -0
- package/dist/process/contract.d.ts +45 -0
- package/dist/process/contract.d.ts.map +1 -0
- package/dist/process/group.d.ts +6 -0
- package/dist/process/group.d.ts.map +1 -0
- package/dist/process/leader-settlement.d.ts +4 -0
- package/dist/process/leader-settlement.d.ts.map +1 -0
- package/dist/tools/transfer/managed-file-error.d.ts.map +1 -1
- package/llms/files.txt +9 -1
- package/llms/primitives.txt +31 -1
- package/llms/process.txt +242 -0
- package/llms/stitchkit.txt +1 -0
- package/llms/tools.txt +18 -0
- package/llms-full.txt +292 -2
- package/llms.txt +6 -4
- package/native/darwin-arm64.node +0 -0
- package/native/darwin-x64.node +0 -0
- package/package.json +5 -1
- package/dist/index-7kxw1awn.js +0 -328
- package/dist/index-aan6hqb9.js +0 -65
package/llms-full.txt
CHANGED
|
@@ -59,6 +59,7 @@ own, recorded as an ADR.
|
|
|
59
59
|
| `stitchkit/tools/connections` | server (Bun or Node) | evolving | consume external MCP servers and a bounded OpenAPI subset — typed reauthorization, a per-request host fence and per-call credentials |
|
|
60
60
|
| `stitchkit/cli` | server | stable | `createCli` — the CLI transport, light (no MCP SDK / `ai`) |
|
|
61
61
|
| `stitchkit/remote` | browser **and** server | stable | peer-free `implementRemote` for thin HTTP proxy processes |
|
|
62
|
+
| `stitchkit/process` | server (Bun or Node, POSIX) | evolving | finite native commands, byte sinks, bounded capture and process-group cancellation |
|
|
62
63
|
| `stitchkit/files` | server (Bun or Node) | stable | peer-free managed local-file boundary |
|
|
63
64
|
| `stitchkit/telegram` | server (Bun or Node) | evolving | peer-free Telegram platform primitives — Mini App `initData` verification, send-failure classification, resumable broadcasts, the operator channel with dedupe, local Bot API files, webhook ownership and durable webhook update intake |
|
|
64
65
|
| `stitchkit/telegram/html` | browser and server | evolving | Telegram's HTML as a tree — clean any markup to what Telegram accepts, cut long text into valid parts by what the reader sees, check markup before it is sent |
|
|
@@ -3872,6 +3873,10 @@ where both exist the runtime's wins, because the run is recorded in its ledger.
|
|
|
3872
3873
|
|
|
3873
3874
|
#### An effect in another system — `effect`, at most once
|
|
3874
3875
|
|
|
3876
|
+
Standalone callers must hold an application-owned exclusive execution lease for the conversation/run
|
|
3877
|
+
through the whole effect call. Sharing a ledger or separate ledger adapters is not an atomic claim;
|
|
3878
|
+
the runtime supplies its run lease. Process-local coalescing only covers the same ledger object.
|
|
3879
|
+
|
|
3875
3880
|
`step` records its result **after** the body, so a body cut short by a crash
|
|
3876
3881
|
runs again. For sending a message or starting a turn at a provider, a repeat is
|
|
3877
3882
|
worse than a loss. The engine's `effect` records the intent **before** it runs:
|
|
@@ -3894,6 +3899,20 @@ throws, or a `reconcile` that throws or overruns `reconcileTimeoutMs` (default
|
|
|
3894
3899
|
call. The proof is JSON of at most 64 KiB — the identity the recipient assigned,
|
|
3895
3900
|
not a payload. → [ADR 0200](../decisions/0200-an-effect-is-recorded-before-it-runs.md)
|
|
3896
3901
|
|
|
3902
|
+
Caller abort during reconcile releases the wait with `StepAbortedError`, leaves the intent and ignores
|
|
3903
|
+
a late result. A coalesced caller can cancel its own await without cancelling the shared owner;
|
|
3904
|
+
the first caller owns reconciliation handlers/deadline. `reconcileTimeoutMs` cannot exceed the native
|
|
3905
|
+
timer range (2147483647 ms). It does not turn cancellation into proof of absence. Neither `null` nor an absence digest
|
|
3906
|
+
proves that an earlier recipient request cannot complete later. Safe retries require recipient-side
|
|
3907
|
+
idempotency or a verified fence. See [ADR 0224](../decisions/0224-native-primitives-have-one-owner.md).
|
|
3908
|
+
|
|
3909
|
+
Ledger reads are paged at 10 000 and incremental in one engine; a fresh engine replays the conversation
|
|
3910
|
+
and retains its durable keys. This is not a bounded outstanding index/direct terminal receipt store.
|
|
3911
|
+
For application delivery, `defineDomainEventDelivery` in `stitchkit/primitives` composes a caller-owned
|
|
3912
|
+
atomic outbox claim with delivered/retryable/terminal/unknown states, bounded dispatch count (default
|
|
3913
|
+
100). Storage retention, per-key lookup, recipient proof and transactions remain in that adapter;
|
|
3914
|
+
it is not an automatic cutover for a different reconciliation protocol.
|
|
3915
|
+
|
|
3897
3916
|
### Typed MCP call metadata
|
|
3898
3917
|
|
|
3899
3918
|
Contract handlers, runtime-tool handlers/factories, lifecycle and tool hooks all
|
|
@@ -8002,6 +8021,223 @@ workspace-relative or canonical `/workspace/...` paths. Unsupported policies mus
|
|
|
8002
8021
|
be refused explicitly by the backend.
|
|
8003
8022
|
|
|
8004
8023
|
|
|
8024
|
+
==============================================================================
|
|
8025
|
+
# Guide: Native IO (docs/guide/native-io.md)
|
|
8026
|
+
==============================================================================
|
|
8027
|
+
|
|
8028
|
+
---
|
|
8029
|
+
title: Конечные команды и файловые гарантии
|
|
8030
|
+
description: Native IO для Bun и Node, с явно выбранной durability, безопасными bounds и caller lifetime.
|
|
8031
|
+
type: guide
|
|
8032
|
+
status: active
|
|
8033
|
+
created: 2026-10-01 20:44 +07:00
|
|
8034
|
+
updated: 2026-10-02 00:37 +07:00
|
|
8035
|
+
participants:
|
|
8036
|
+
- role: authored
|
|
8037
|
+
harness: Codex
|
|
8038
|
+
model: GPT-6
|
|
8039
|
+
at: 2026-10-01 20:44 +07:00
|
|
8040
|
+
- role: implemented
|
|
8041
|
+
harness: Codex
|
|
8042
|
+
model: GPT-6
|
|
8043
|
+
at: 2026-10-02 00:08 +07:00
|
|
8044
|
+
---
|
|
8045
|
+
|
|
8046
|
+
# Native IO
|
|
8047
|
+
|
|
8048
|
+
Примеры используют публичные imports и одинаково исполняются в Bun и Node ≥22.
|
|
8049
|
+
|
|
8050
|
+
## Запись файла
|
|
8051
|
+
|
|
8052
|
+
```ts
|
|
8053
|
+
import { writeFileAtomic, AtomicFilePublicationError } from 'stitchkit/files'
|
|
8054
|
+
|
|
8055
|
+
try {
|
|
8056
|
+
await writeFileAtomic('/srv/app/receipt.json', JSON.stringify({ id: 'receipt-1' }), {
|
|
8057
|
+
replace: false,
|
|
8058
|
+
mode: 0o600,
|
|
8059
|
+
durability: 'directory',
|
|
8060
|
+
})
|
|
8061
|
+
} catch (error) {
|
|
8062
|
+
if (error instanceof AtomicFilePublicationError) {
|
|
8063
|
+
// target уже виден. Проверьте receipt, прежде чем решать о повторе.
|
|
8064
|
+
console.error(error.phase, error.cause)
|
|
8065
|
+
} else throw error
|
|
8066
|
+
}
|
|
8067
|
+
await writeFileAtomic('/srv/app/state.json', '{"version":2}', {
|
|
8068
|
+
replace: true, durability: 'directory',
|
|
8069
|
+
})
|
|
8070
|
+
```
|
|
8071
|
+
|
|
8072
|
+
По умолчанию `replace: true`, `durability: 'file'`, `mode: 0o600`: existing вызовы сохраняют
|
|
8073
|
+
file-fsync и atomic replacement. `durability: 'none'` отключает sync; `'directory'` выполняет
|
|
8074
|
+
полную запись → exact descriptor chmod → file fsync → rename (replace) либо link (create) →
|
|
8075
|
+
удаление staging link → parent fsync. `writeFileAtomicSync` имеет те же options и порядок.
|
|
8076
|
+
Create отказывает с native `EEXIST` при существующем файле, symlink или concurrent winner.
|
|
8077
|
+
Никогда не переводите этот отказ в replace автоматически.
|
|
8078
|
+
|
|
8079
|
+
`AtomicFilePublicationError.published === true` отличает видимость от неподтверждённого
|
|
8080
|
+
acknowledgement. `phase` — `cleanup`, `directory-sync` или `directory-close`; первичная причина
|
|
8081
|
+
сохранена в `cause`. Ошибка до publish оставляет прежний target. Cleanup вторичен к первичной ошибке.
|
|
8082
|
+
При create кратко существует второй hardlink; strict single-link reader вправе отказать в этом окне.
|
|
8083
|
+
|
|
8084
|
+
Directory fsync — native POSIX/filesystem capability. Windows явно отказывает; иной filesystem
|
|
8085
|
+
может отказать при open/sync. Проверка на Linux не подтверждает поведение macOS, сетевой FS или
|
|
8086
|
+
сохранность при отключении питания. Состояние диска определяется гарантиями самой FS/ОС.
|
|
8087
|
+
`createManagedFileBoundary.write(..., { durable: true })` использует тот же publish owner и parent sync;
|
|
8088
|
+
его create по умолчанию остаётся create, а `replace: true` явно разрешает replacement.
|
|
8089
|
+
|
|
8090
|
+
## Строгое чтение
|
|
8091
|
+
|
|
8092
|
+
```ts
|
|
8093
|
+
import { createManagedFileBoundary } from 'stitchkit/files'
|
|
8094
|
+
|
|
8095
|
+
const files = await createManagedFileBoundary({ root: '/srv/app', maxReadBytes: 64 * 1024 })
|
|
8096
|
+
const source = await files.read('receipt.json', {
|
|
8097
|
+
rejectSymlinks: true, singleLink: true, stable: true, observe: true,
|
|
8098
|
+
})
|
|
8099
|
+
console.log(source.observation) // dev, ino, size, nlink, mtimeMs, ctimeMs
|
|
8100
|
+
const receipt = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(source.bytes))
|
|
8101
|
+
// schema.parse(receipt) и проверка digest принадлежат приложению.
|
|
8102
|
+
```
|
|
8103
|
+
|
|
8104
|
+
Без новых options ответ сохраняет `{ ref, bytes }`, допускает trusted in-root symlink и hardlink.
|
|
8105
|
+
`rejectSymlinks` запрещает requested leaf, `singleLink` проверяет `nlink` открытого descriptor,
|
|
8106
|
+
`stable` сравнивает dev/ino/size/mtime/ctime/nlink вокруг byte read; `observe` добавляет metadata.
|
|
8107
|
+
`FILE_NOT_FOUND`, `FILE_NOT_REGULAR`, `FILE_UNSAFE_LINK`, `FILE_TOO_LARGE`, `FILE_CHANGED`,
|
|
8108
|
+
`FILE_UNSUPPORTED` и `FILE_IO_ERROR` различаются. Abort сохраняет caller reason.
|
|
8109
|
+
Nonblocking open позволяет отказать FIFO без ожидания writer. Bytes ограничены во время чтения,
|
|
8110
|
+
включая рост файла, не только initial stat. Chunk allocation ≤ maxBytes+1+64 KiB, flatten ≤ maxBytes;
|
|
8111
|
+
FD закрывается при success, отказе, abort и IO error.
|
|
8112
|
+
Ошибка close сохраняет первичную ошибку чтения; после успешного чтения ошибка close возвращается caller.
|
|
8113
|
+
|
|
8114
|
+
Root и ancestors принадлежат trusted actor. Эти options не дают descriptor-relative containment
|
|
8115
|
+
при hostile concurrent ancestor replacement. Отдельного переключателя «считать ancestors безопасными»
|
|
8116
|
+
нет: portable owner не предоставляет такую capability. Metadata stability не доказывает immutable
|
|
8117
|
+
snapshot против произвольного hostile writer; используйте application lock/immutable publication.
|
|
8118
|
+
|
|
8119
|
+
## Команды
|
|
8120
|
+
|
|
8121
|
+
```ts
|
|
8122
|
+
import { runNativeCommand } from 'stitchkit/process'
|
|
8123
|
+
|
|
8124
|
+
const captured = await runNativeCommand({
|
|
8125
|
+
executable: '/usr/bin/git', args: ['rev-parse', 'HEAD'], cwd: '/srv/app',
|
|
8126
|
+
envPolicy: 'declared-only', env: { PATH: '/usr/bin:/bin' },
|
|
8127
|
+
capture: true, maxOutputBytes: 4096, timeoutMs: 5000,
|
|
8128
|
+
})
|
|
8129
|
+
console.log(captured.exitCode, new TextDecoder().decode(captured.stdout))
|
|
8130
|
+
|
|
8131
|
+
const lifetime = new AbortController()
|
|
8132
|
+
await runNativeCommand({
|
|
8133
|
+
executable: '/usr/bin/git', args: ['status'], signal: lifetime.signal,
|
|
8134
|
+
onOutput: async (bytes, channel, outputSignal) => {
|
|
8135
|
+
outputSignal.throwIfAborted()
|
|
8136
|
+
await output.write(bytes, channel, outputSignal) // application-owned bounded sink
|
|
8137
|
+
},
|
|
8138
|
+
})
|
|
8139
|
+
```
|
|
8140
|
+
|
|
8141
|
+
Команда требует caller signal или finite `timeoutMs` (1–2147483647 ms: native timer range; большее значение отказывается, не превращается в 1 ms). Streaming имеет caller lifetime, без скрытого
|
|
8142
|
+
60-second timeout или 1-MiB output limit. `capture` по умолчанию false; true требует
|
|
8143
|
+
`maxOutputBytes` для суммарных stdout+stderr. Лимит считает исходные bytes; API возвращает
|
|
8144
|
+
`Uint8Array`, не преобразует invalid UTF-8. Result содержит наблюдаемый `exitCode: number | null`
|
|
8145
|
+
и `signal: string | null`; signal termination не превращается в выдуманный exit code. `maxOutputBytes` может ограничивать и streaming.
|
|
8146
|
+
`stdin` — bytes с `maxStdinBytes` (default 1 MiB). `envPolicy` default `declared-only`: отсутствие env
|
|
8147
|
+
означает пустой environment; `ambient` явно разрешает наследование. Cwd/executable policy остаётся
|
|
8148
|
+
приложению; этот primitive запускает native executable и сам не создаёт shell.
|
|
8149
|
+
|
|
8150
|
+
Вывод читается с backpressure отдельно для stdout/stderr: один выполняющийся sink на канал плюс
|
|
8151
|
+
bounded native Readable buffer; накопления всей истории при streaming нет. Callback получает
|
|
8152
|
+
lifetime signal. Abort освобождает ожидание даже игнорирующего signal callback, но не способен
|
|
8153
|
+
отменить сторонние действия, которые сам callback продолжит после abort. Sink обязан отменять свои
|
|
8154
|
+
IO, не сохранять бесконечную историю и не изменять shared descriptor flags. После abort новых
|
|
8155
|
+
callbacks owner не запускает. Normal completion ждёт всех bytes и sinks.
|
|
8156
|
+
|
|
8157
|
+
Cleanup: POSIX process group, TERM, `killGraceMs` (default 100, maximum 10 000), затем KILL;
|
|
8158
|
+
`cleanupTimeoutMs` (default 2000, maximum 30 000) ограничивает ожидание close после сигналов.
|
|
8159
|
+
На Darwin временный `EPERM` при сигнале группе может означать zombies, ещё не убранные
|
|
8160
|
+
OS reaper. Повтор ограничен `cleanupTimeoutMs`; успех требует доставленного сигнала или
|
|
8161
|
+
`ESRCH`, постоянный отказ сохраняется в cause. Закрытие каждого owned pipe и выход leader
|
|
8162
|
+
наблюдаются отдельно, включая отсутствие общего `child.close` при teardown.
|
|
8163
|
+
Сохраняется caller/sink причина; failure cleanup — `NativeCommandError` с `COMMAND_CLEANUP` и
|
|
8164
|
+
AggregateError cause. Даже вышедший parent не исключает helper, удерживающий pipe. Windows
|
|
8165
|
+
отказывает с `COMMAND_UNAVAILABLE`; потомок, самостоятельно покинувший группу через setsid,
|
|
8166
|
+
лежит за границей этой capability. Это one-shot execution, не PTY, supervisor или daemon host.
|
|
8167
|
+
|
|
8168
|
+
## Механическая адаптация
|
|
8169
|
+
|
|
8170
|
+
Atomic file wrapper заменяется одним вызовом `writeFileAtomic` с выбранными options. Bounded
|
|
8171
|
+
regular-file read заменяется `files.read`; JSON/schema, receipt conflicts, journal rotation и
|
|
8172
|
+
application locks сохраняются. Spawn/drain/capture/cancellation wrapper заменяется `runNativeCommand`;
|
|
8173
|
+
shell policy, command admission, логирование, redaction, bytes→text decoder и operator sink сохраняются.
|
|
8174
|
+
Длительные signal-only команды остаются streaming; bounded tar/capture получают свои явные limits.
|
|
8175
|
+
Импорт leaf не делает установку всего npm package маленькой; выбирайте dependency после измерения
|
|
8176
|
+
packed размера и dependency closure.
|
|
8177
|
+
## Resource-scoped launchers and shared owners
|
|
8178
|
+
|
|
8179
|
+
`onLeaderSettled(event, signal)` observes leader exit before inherited stdout/stderr pipes
|
|
8180
|
+
close. A resource owner can stop its external scope there, allowing pipe drain to complete.
|
|
8181
|
+
The callback runs once: `event.kind === 'exit'` carries observed `exitCode`/`signal`; a terminal
|
|
8182
|
+
failure uses `kind: 'error'` and preserves its cause. Unavailable executables, output sink
|
|
8183
|
+
failure and caller cancellation settle through the same owner. `cleanupTimeoutMs` bounds
|
|
8184
|
+
the callback after settlement starts; it never becomes a deadline for signal-only execution.
|
|
8185
|
+
Honor the settlement signal; arbitrary user promises cannot be forcibly cancelled.
|
|
8186
|
+
|
|
8187
|
+
```ts
|
|
8188
|
+
await runNativeCommand({
|
|
8189
|
+
executable: launcher,
|
|
8190
|
+
args,
|
|
8191
|
+
signal: scope.signal,
|
|
8192
|
+
onOutput: (bytes, channel, signal) => scope.write(bytes, channel, signal),
|
|
8193
|
+
onLeaderSettled: (event, signal) => scope.settle(event, signal),
|
|
8194
|
+
});
|
|
8195
|
+
```
|
|
8196
|
+
|
|
8197
|
+
`observeProcessInstance(pid)` returns `observed` with a `ProcessInstance`, or `unavailable`
|
|
8198
|
+
with its cause. `probeProcessOwner(pid, recorded)` compares that evidence on the machine the
|
|
8199
|
+
caller established: `matched`, `different-boot`, `reused-pid`, `pid-gone`, `legacy` or
|
|
8200
|
+
`unavailable`. Missing/partial/denied evidence is not death. Supervisor tree fencing remains
|
|
8201
|
+
the caller's job; a PID lifetime is not proof that its whole workload stopped.
|
|
8202
|
+
|
|
8203
|
+
An exclusive lock applies exact requested permissions through its creating descriptor,
|
|
8204
|
+
independent of umask. Default `0600` stays private. Shared `0640` requires a common group and
|
|
8205
|
+
traversable directories; another UID also needs directory write permission to reclaim a
|
|
8206
|
+
proven-dead owner's file. Set `ownerlessGraceMs: null` to refuse every age-only reclaim,
|
|
8207
|
+
including ownerless reclaim guards. The default remains 5000 ms for existing clients.
|
|
8208
|
+
Восстановление stale reclaim guard использует тот же lock owner и следующий guard:
|
|
8209
|
+
проверка inode и удаление выполняются под ним. Конкурирующий writer не обходит guard,
|
|
8210
|
+
пока прежнее удаление приостановлено; live и unknown lifetime evidence остаются отказом.
|
|
8211
|
+
|
|
8212
|
+
## Libraries with a Zod-only runtime
|
|
8213
|
+
|
|
8214
|
+
Public leaves keep optional peers out of their import closure. Installing `stitchkit` still
|
|
8215
|
+
installs the complete package and ky; selective imports alone do not avoid that installation.
|
|
8216
|
+
A library can use Stitchkit as a build dependency, bundle its selected public native imports,
|
|
8217
|
+
keep Zod external, and publish the resulting implementation with its library artifact.
|
|
8218
|
+
|
|
8219
|
+
```ts
|
|
8220
|
+
// The library's build entry; all mechanisms remain owned by Stitchkit.
|
|
8221
|
+
export { canonicalJson } from 'stitchkit/primitives';
|
|
8222
|
+
export { writeFileAtomic, withExclusiveLock } from 'stitchkit/files';
|
|
8223
|
+
export { observeProcessInstance, probeProcessOwner, runNativeCommand } from 'stitchkit/process';
|
|
8224
|
+
```
|
|
8225
|
+
|
|
8226
|
+
Bundle for Node-compatible execution with Zod external. Publish declarations from the same
|
|
8227
|
+
version: carry their reachable relative `.d.ts` closure, rather than emitting references to
|
|
8228
|
+
`stitchkit` that force clients to install it for types. A library exposing its own DTOs may
|
|
8229
|
+
instead emit declarations for only that DTO contract. Keep the library's manifest at runtime
|
|
8230
|
+
`dependencies: {}` and `peerDependencies: { zod: ... }` when that is its declared promise.
|
|
8231
|
+
|
|
8232
|
+
Darwin consumers need the published native binaries at the bundled loader's relative native
|
|
8233
|
+
directory. A JS-only bundle is not portable evidence. Qualify the packed library outside its
|
|
8234
|
+
build tree in Bun and Node, test its declarations, and check that importing an unbundled
|
|
8235
|
+
Stitchkit leaf fails there. A separate schema-only entry must not import the native entry.
|
|
8236
|
+
|
|
8237
|
+
This delivery removes a runtime kernel installation; it does not remove the build-time
|
|
8238
|
+
Stitchkit installation or create an independent lightweight npm package.
|
|
8239
|
+
|
|
8240
|
+
|
|
8005
8241
|
==============================================================================
|
|
8006
8242
|
# Guide: Generic application primitives (docs/guide/primitives.md)
|
|
8007
8243
|
==============================================================================
|
|
@@ -8012,7 +8248,7 @@ description: Declare lifecycle, access, exact values, audit, delivery and export
|
|
|
8012
8248
|
type: guide
|
|
8013
8249
|
status: active
|
|
8014
8250
|
created: 2026-09-01
|
|
8015
|
-
updated: 2026-
|
|
8251
|
+
updated: 2026-10-01 21:03 +07:00
|
|
8016
8252
|
---
|
|
8017
8253
|
|
|
8018
8254
|
# Generic application primitives
|
|
@@ -8105,6 +8341,31 @@ of the application's existing async operation. The input, scope, metadata and to
|
|
|
8105
8341
|
change. The application creates bytes and owns operation persistence; the managed-file boundary
|
|
8106
8342
|
streams them.
|
|
8107
8343
|
|
|
8344
|
+
## Canonical JSON
|
|
8345
|
+
|
|
8346
|
+
```ts
|
|
8347
|
+
import { canonicalJson } from 'stitchkit/primitives'
|
|
8348
|
+
|
|
8349
|
+
const bytes = canonicalJson({ '2': 'two', '10': 'ten', optional: undefined, nested: [1, null] }, {
|
|
8350
|
+
maxDepth: 20, maxNodes: 10_000, maxBytes: 64 * 1024,
|
|
8351
|
+
})
|
|
8352
|
+
// {"10":"ten","2":"two","nested":[1,null]}
|
|
8353
|
+
// Native crypto or browser WebCrypto hashes these same UTF-8 bytes.
|
|
8354
|
+
```
|
|
8355
|
+
|
|
8356
|
+
`canonicalJson` использует единый serializer исторических digest: object keys в UTF-16 code-unit
|
|
8357
|
+
order, включая integer-like keys; array order сохраняется. Optional object members с undefined
|
|
8358
|
+
опускаются. Top-level/array undefined, sparse arrays, functions/symbols/BigInt, non-finite numbers,
|
|
8359
|
+
negative zero, cycles, user prototypes, accessors, non-enumerable/symbol members отказаны до
|
|
8360
|
+
serialization. Приложение валидирует свою schema первым; canonical boundary не заменяет её.
|
|
8361
|
+
|
|
8362
|
+
Defaults: depth 100 (maximum 100), nodes 100 000, UTF-8 bytes 1 MiB. Превышение или не-JSON data —
|
|
8363
|
+
TypeError; неверные options — Zod validation error. Это browser-safe leaf без Node/Bun/crypto,
|
|
8364
|
+
agent-runtime/testing или optional peers. Native и browser используют один algorithm; hashing
|
|
8365
|
+
остаётся platform adapter. Переносите только serializer recursion, сохраняя proof schemas и
|
|
8366
|
+
verification boundary. Существующие внутренние historical normalization/digest fixtures не меняются;
|
|
8367
|
+
новый public boundary сознательно отказывает неоднозначным values вместо фиктивной совместимости.
|
|
8368
|
+
|
|
8108
8369
|
|
|
8109
8370
|
==============================================================================
|
|
8110
8371
|
# Guide: Application migration recipes (docs/guide/application-migration-recipes.md)
|
|
@@ -18804,6 +19065,12 @@ schedules, transports and file generation remain application-owned.
|
|
|
18804
19065
|
|
|
18805
19066
|
---
|
|
18806
19067
|
|
|
19068
|
+
| Export | Kind | Purpose |
|
|
19069
|
+
|---|---|---|
|
|
19070
|
+
| `canonicalJson` | function | bounded plain JSON, UTF-16 key sort, optional object members omitted |
|
|
19071
|
+
| `CanonicalJsonOptions` | type | inferred depth/node/UTF-8 bytes limits |
|
|
19072
|
+
|
|
19073
|
+
|
|
18807
19074
|
## `stitchkit/server`
|
|
18808
19075
|
|
|
18809
19076
|
Server-only. Builds and runs the HTTP server, and carries the server primitives.
|
|
@@ -20371,7 +20638,7 @@ available from `stitchkit/contract`.
|
|
|
20371
20638
|
| `ManagedFileInspector` | _type_ | bounded-prefix read/write inspection callback with a finite cancellation signal that cannot own path or size |
|
|
20372
20639
|
| `ManagedFileInspectionInput` / `ManagedFileInspection` | _type_ | inspector prefix/name/declared media/signal input and validated metadata-only result |
|
|
20373
20640
|
| `writeFileAtomic` / `writeFileAtomicSync` / `WriteFileAtomicOptions` | function / _type_ | replace a file atomically: a random staging name created exclusively (never through a planted link), the mode set on the descriptor before the file is visible (default `0o600`, not masked by the umask), `fsync`, rename; a failure leaves the target and no staging file. The asynchronous form keeps the event loop running |
|
|
20374
|
-
| `withExclusiveLock` / `ExclusiveLockOptions` / `ExclusiveLock` / `ExclusiveLockOwner` | function / _type_ | run work under an exclusive lock between processes — a file recording its owner (pid, host, machine identity, time and nullable kernel process identity); waits up to `timeoutMs` (default 10 s) and stops on `signal`; a dead owner on this machine is taken over, a live, slow or foreign one never is; an ownerless lock only after `ownerlessGraceMs` |
|
|
20641
|
+
| `withExclusiveLock` / `ExclusiveLockOptions` / `ExclusiveLock` / `ExclusiveLockOwner` | function / _type_ | run work under an exclusive lock between processes — a file recording its owner (pid, host, machine identity, time and nullable kernel process identity); waits up to `timeoutMs` (default 10 s) and stops on `signal`; a dead owner on this machine is taken over, a live, slow or foreign one never is; an ownerless lock only after `ownerlessGraceMs` (default 5000 ms, `null` disables age-based reclaim including guards); exact `mode` is independent of umask; shared readers need a common group and traversable directories |
|
|
20375
20642
|
| `ExclusiveLockError` | class | `LOCK_TIMEOUT` naming the resource and its holder, or `LOCK_ABORTED` with the signal's reason |
|
|
20376
20643
|
| `createChunkSpool` | function | the server half of a chunked upload: parts on disk under `owner` + client-minted `uploadId`, each with a size+sha256 receipt; idempotent `open` and `put`, the first writer of a part wins across processes, `assemble` in order once every part is in, `sweep` of untouched uploads — [guide](../guide/client.md#chunked-uploads) |
|
|
20377
20644
|
| `ChunkSpool` / `ChunkSpoolConfig` / `ChunkSpoolKey` / `ChunkSpoolOpen` / `ChunkSpoolPart` / `ChunkSpoolAssembly` | _type_ | the spool, its directory, part size, file limit, meta schema and age; an upload's key; its declaration; one part; the assembled parts with a concatenating `stream()` |
|
|
@@ -20380,6 +20647,12 @@ available from `stitchkit/contract`.
|
|
|
20380
20647
|
|
|
20381
20648
|
---
|
|
20382
20649
|
|
|
20650
|
+
| Export | Kind | Purpose |
|
|
20651
|
+
|---|---|---|
|
|
20652
|
+
| `AtomicFilePublicationError` | class | published=true with cleanup/directory-sync/directory-close phase |
|
|
20653
|
+
| `FileObservation` | type | observed descriptor dev/ino/size/nlink/mtimeMs/ctimeMs |
|
|
20654
|
+
|
|
20655
|
+
|
|
20383
20656
|
## `stitchkit/telegram`
|
|
20384
20657
|
|
|
20385
20658
|
Peer-free server-only Telegram platform primitives — the Bot API's own
|
|
@@ -20907,3 +21180,20 @@ AI-only peer boundary. Existing custom tool callbacks need no new import.
|
|
|
20907
21180
|
| Export | Kind | Summary |
|
|
20908
21181
|
|--------|------|---------|
|
|
20909
21182
|
| `createAgentHarnessTools` / `AgentHarnessToolsConfig` | function / _type_ | async per-run full mount configuration (`services` plus all `AgentMountConfig` options); composes application lifecycle then runtime fence exactly once |
|
|
21183
|
+
|
|
21184
|
+
|
|
21185
|
+
## `stitchkit/process`
|
|
21186
|
+
|
|
21187
|
+
Native POSIX Bun/Node one-shot command execution. See [native IO](../guide/native-io.md).
|
|
21188
|
+
|
|
21189
|
+
| Export | Kind | Purpose |
|
|
21190
|
+
|---|---|---|
|
|
21191
|
+
| `runNativeCommand` | function | caller-lifetime streaming or explicitly bounded binary capture |
|
|
21192
|
+
| `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink and finite cleanup limits |
|
|
21193
|
+
| `NativeCommandResult` | type | observed nullable exit code/signal and captured stdout/stderr bytes |
|
|
21194
|
+
| `NativeCommandError` | class | COMMAND_LIMIT, COMMAND_UNAVAILABLE or COMMAND_CLEANUP with internal cause |
|
|
21195
|
+
|
|
21196
|
+
| `NativeCommandSettlement` | type | observed leader `exit` or terminal `error`; `onLeaderSettled` runs once before drain, bounded by cleanupTimeoutMs, with a cancellable settlement signal |
|
|
21197
|
+
| `observeProcessInstance` / `ProcessInstanceObservation` | function / type | Linux/Darwin lifetime observation; observed identity or unavailable with its original cause, never guessed absence |
|
|
21198
|
+
| `ProcessInstanceSchema` / `ProcessInstance` | schema / type | platform, boot ID, namespace and process start identity from the shared native reader |
|
|
21199
|
+
| `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
|
@@ -9,18 +9,18 @@ Build with stitchkit: define a contract once, then `implement` it and serve it (
|
|
|
9
9
|
Load the slice for each entrypoint your code imports — `import … from 'stitchkit/server'` → `llms/server.txt`; the root `stitchkit` import → `llms/stitchkit.txt`. A slice holds that entrypoint's API reference section and the guide pages whose home it is; every guide lives in exactly one slice, and a slice that needs another's guide names it under "Also read". Each file is at most 50.0 KB; a longer one continues in numbered parts, each naming the next at its top. Moving across versions: load `llms/upgrading.txt` and the range slices it lists between your version and the target. `llms-full.txt` inlines everything; it is far larger than a context window, so do not read it whole.
|
|
10
10
|
|
|
11
11
|
## Entrypoint slices
|
|
12
|
-
- **stitchkit**: [llms/stitchkit.txt](llms/stitchkit.txt) 17.
|
|
12
|
+
- **stitchkit**: [llms/stitchkit.txt](llms/stitchkit.txt) 17.2 KB → [llms/stitchkit.2.txt](llms/stitchkit.2.txt) 45.2 KB → [llms/stitchkit.3.txt](llms/stitchkit.3.txt) 17.1 KB
|
|
13
13
|
- **stitchkit/live**: [llms/live.txt](llms/live.txt) 21.6 KB
|
|
14
14
|
- **stitchkit/react**: [llms/react.txt](llms/react.txt) 9.0 KB
|
|
15
15
|
- **stitchkit/react/keyboard**: [llms/react-keyboard.txt](llms/react-keyboard.txt) 9.4 KB
|
|
16
|
-
- **stitchkit/tools**: [llms/tools.txt](llms/tools.txt)
|
|
16
|
+
- **stitchkit/tools**: [llms/tools.txt](llms/tools.txt) 47.4 KB → [llms/tools.2.txt](llms/tools.2.txt) 26.9 KB → [llms/tools.3.txt](llms/tools.3.txt) 25.5 KB
|
|
17
17
|
- **stitchkit/tools/contract**: [llms/tools-contract.txt](llms/tools-contract.txt) 0.2 KB
|
|
18
18
|
- **stitchkit/tools/invoker**: [llms/tools-invoker.txt](llms/tools-invoker.txt) 0.2 KB
|
|
19
19
|
- **stitchkit/tools/connections**: [llms/tools-connections.txt](llms/tools-connections.txt) 3.1 KB
|
|
20
20
|
- **stitchkit/cli**: [llms/cli.txt](llms/cli.txt) 43.6 KB → [llms/cli.2.txt](llms/cli.2.txt) 8.1 KB
|
|
21
21
|
- **stitchkit/remote**: [llms/remote.txt](llms/remote.txt) 1.0 KB
|
|
22
22
|
- **stitchkit/contract**: [llms/contract.txt](llms/contract.txt) 31.9 KB
|
|
23
|
-
- **stitchkit/primitives**: [llms/primitives.txt](llms/primitives.txt)
|
|
23
|
+
- **stitchkit/primitives**: [llms/primitives.txt](llms/primitives.txt) 11.2 KB
|
|
24
24
|
- **stitchkit/server**: [llms/server.txt](llms/server.txt) 45.3 KB → [llms/server.2.txt](llms/server.2.txt) 14.6 KB → [llms/server.3.txt](llms/server.3.txt) 45.6 KB → [llms/server.4.txt](llms/server.4.txt) 38.1 KB → [llms/server.5.txt](llms/server.5.txt) 21.8 KB
|
|
25
25
|
- **stitchkit/observability**: [llms/observability.txt](llms/observability.txt) 44.8 KB
|
|
26
26
|
- **stitchkit/agent-runtime**: [llms/agent-runtime.txt](llms/agent-runtime.txt) 36.8 KB → [llms/agent-runtime.2.txt](llms/agent-runtime.2.txt) 46.7 KB → [llms/agent-runtime.3.txt](llms/agent-runtime.3.txt) 34.3 KB
|
|
@@ -39,7 +39,7 @@ Load the slice for each entrypoint your code imports — `import … from 'stitc
|
|
|
39
39
|
- **stitchkit/application/schemas**: [llms/application-schemas.txt](llms/application-schemas.txt) 1.8 KB
|
|
40
40
|
- **stitchkit/testing**: [llms/testing.txt](llms/testing.txt) 30.8 KB
|
|
41
41
|
- **stitchkit/agent-runtime/sandbox**: [llms/agent-runtime-sandbox.txt](llms/agent-runtime-sandbox.txt) 8.1 KB
|
|
42
|
-
- **stitchkit/files**: [llms/files.txt](llms/files.txt) 4.
|
|
42
|
+
- **stitchkit/files**: [llms/files.txt](llms/files.txt) 4.5 KB
|
|
43
43
|
- **stitchkit/telegram**: [llms/telegram.txt](llms/telegram.txt) 26.9 KB
|
|
44
44
|
- **stitchkit/telegram/html**: [llms/telegram-html.txt](llms/telegram-html.txt) 2.7 KB
|
|
45
45
|
- **stitchkit/telegram/screens**: [llms/telegram-screens.txt](llms/telegram-screens.txt) 21.2 KB
|
|
@@ -55,6 +55,7 @@ Load the slice for each entrypoint your code imports — `import … from 'stitc
|
|
|
55
55
|
- **stitchkit/agent-runtime/react**: [llms/agent-runtime-react.txt](llms/agent-runtime-react.txt) 1.0 KB
|
|
56
56
|
- **stitchkit/agent-runtime/realtime**: [llms/agent-runtime-realtime.txt](llms/agent-runtime-realtime.txt) 1.8 KB
|
|
57
57
|
- **stitchkit/agent-runtime/harness-tools**: [llms/agent-runtime-harness-tools.txt](llms/agent-runtime-harness-tools.txt) 1.3 KB
|
|
58
|
+
- **stitchkit/process**: [llms/process.txt](llms/process.txt) 15.9 KB
|
|
58
59
|
|
|
59
60
|
## Upgrading slices
|
|
60
61
|
- **Upgrading — how to move across versions**: [llms/upgrading.txt](llms/upgrading.txt) 10.3 KB
|
|
@@ -75,6 +76,7 @@ Load the slice for each entrypoint your code imports — `import … from 'stitc
|
|
|
75
76
|
- [Agent composition](https://github.com/max-listov/stitchkit/blob/master/docs/guide/agent-composition.md): tool factories, authorized realtime control, shared React views and exact-run behavior checks
|
|
76
77
|
- [Managed application kernel](https://github.com/max-listov/stitchkit/blob/master/docs/guide/application-kernel.md): process-local resources, readiness, admission, schedules, projections and optional provider adapters
|
|
77
78
|
- [Optional process sandbox](https://github.com/max-listov/stitchkit/blob/master/docs/guide/sandbox.md): Linux Bubblewrap sessions, durable workspace reconnect, network policy and host credential brokering
|
|
79
|
+
- [Native IO](https://github.com/max-listov/stitchkit/blob/master/docs/guide/native-io.md): finite commands, durable atomic publication and strict trusted-root file reads
|
|
78
80
|
- [Generic application primitives](https://github.com/max-listov/stitchkit/blob/master/docs/guide/primitives.md): lifecycle transitions, owner scope, permissions, exact money and quantities, deadlines, audit, delivery and exports — declared, not persisted
|
|
79
81
|
- [Application migration recipes](https://github.com/max-listov/stitchkit/blob/master/docs/guide/application-migration-recipes.md): executable database, poller, queue-consumer and operational publishing cutovers
|
|
80
82
|
- [CLI](https://github.com/max-listov/stitchkit/blob/master/docs/guide/cli.md): contracts as a command-line program
|
package/native/darwin-arm64.node
CHANGED
|
Binary file
|
package/native/darwin-x64.node
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stitchkit",
|
|
3
|
-
"version": "0.103.
|
|
3
|
+
"version": "0.103.10",
|
|
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",
|
|
@@ -233,6 +233,10 @@
|
|
|
233
233
|
"./agent-runtime/harness-tools": {
|
|
234
234
|
"types": "./dist/entrypoints/agent-runtime/harness-tools.d.ts",
|
|
235
235
|
"import": "./dist/entrypoints/agent-runtime/harness-tools.js"
|
|
236
|
+
},
|
|
237
|
+
"./process": {
|
|
238
|
+
"types": "./dist/entrypoints/process.d.ts",
|
|
239
|
+
"import": "./dist/entrypoints/process.js"
|
|
236
240
|
}
|
|
237
241
|
},
|
|
238
242
|
"publishConfig": {
|