stitchkit 0.59.0 → 0.59.2
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/README.md +44 -4
- package/dist/agent-runtime/runtime.d.ts.map +1 -1
- package/dist/agent-runtime/terminal-commit.d.ts +102 -0
- package/dist/agent-runtime/terminal-commit.d.ts.map +1 -0
- package/dist/agent-runtime.js +143 -46
- package/dist/application/activity.d.ts +70 -0
- package/dist/application/activity.d.ts.map +1 -0
- package/dist/application/events.d.ts +65 -0
- package/dist/application/events.d.ts.map +1 -0
- package/dist/application/grammy.d.ts +35 -0
- package/dist/application/grammy.d.ts.map +1 -0
- package/dist/application/graph.d.ts +11 -0
- package/dist/application/graph.d.ts.map +1 -0
- package/dist/application/health.d.ts +13 -0
- package/dist/application/health.d.ts.map +1 -0
- package/dist/application/kernel.d.ts +31 -0
- package/dist/application/kernel.d.ts.map +1 -0
- package/dist/application/latest-sink.d.ts +39 -0
- package/dist/application/latest-sink.d.ts.map +1 -0
- package/dist/application/resource.d.ts +30 -0
- package/dist/application/resource.d.ts.map +1 -0
- package/dist/application/schedule.d.ts +112 -0
- package/dist/application/schedule.d.ts.map +1 -0
- package/dist/application/schemas.d.ts +160 -0
- package/dist/application/schemas.d.ts.map +1 -0
- package/dist/application/server-resource.d.ts +12 -0
- package/dist/application/server-resource.d.ts.map +1 -0
- package/dist/application-grammy.d.ts +2 -0
- package/dist/application-grammy.d.ts.map +1 -0
- package/dist/application-grammy.js +165 -0
- package/dist/application.d.ts +10 -0
- package/dist/application.d.ts.map +1 -0
- package/dist/application.js +1370 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/{index-zk5zn2nh.js → index-3nwng7hs.js} +287 -38
- package/dist/index-dk6e56g0.js +211 -0
- package/dist/{index-9zn9fb4e.js → index-he4psyve.js} +6 -213
- package/dist/index-yr276yz0.js +6 -0
- package/dist/internal/fetch-port.d.ts +2 -0
- package/dist/internal/fetch-port.d.ts.map +1 -0
- package/dist/node.js +115 -13
- package/dist/server/index.js +8 -6
- package/dist/server/node.d.ts.map +1 -1
- package/dist/server/process-signals.d.ts +10 -8
- package/dist/server/process-signals.d.ts.map +1 -1
- package/dist/tools/cli-args.d.ts +16 -0
- package/dist/tools/cli-args.d.ts.map +1 -1
- package/dist/tools/cli-command.d.ts +16 -0
- package/dist/tools/cli-command.d.ts.map +1 -1
- package/dist/tools/cli-policy.d.ts +22 -0
- package/dist/tools/cli-policy.d.ts.map +1 -0
- package/dist/tools/cli.d.ts +2 -1
- package/dist/tools/cli.d.ts.map +1 -1
- package/dist/tools.d.ts +1 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +1 -1
- package/llms-full.txt +471 -14
- package/llms.txt +1 -0
- package/package.json +15 -2
package/llms-full.txt
CHANGED
|
@@ -3570,8 +3570,13 @@ Durably queued records rejected from the local queue remain recoverable through
|
|
|
3570
3570
|
|
|
3571
3571
|
Use `await runtime.interrupt({ conversationId, runId })` when the interruption
|
|
3572
3572
|
must be durable: it first commits `interrupt_requested`, then aborts the local
|
|
3573
|
-
coordinator signal.
|
|
3574
|
-
|
|
3573
|
+
coordinator signal. If provider completion races that revision change, the terminal path reloads
|
|
3574
|
+
the canonical snapshot. An already-terminal winner settles the ticket directly; a still-owned
|
|
3575
|
+
`interrupt_requested` run is committed as `interrupted`, and unrelated aggregate-head conflicts
|
|
3576
|
+
remain retriable while the run is active with the same owner and fencing token. A stale owner or
|
|
3577
|
+
fencing token remains a conflict. Only the execution that applies the terminal mutation emits the
|
|
3578
|
+
terminal event and operator metrics; a loser settles from canonical state without republishing it.
|
|
3579
|
+
`runtime.stop(key)` is the process-local signal-only escape hatch.
|
|
3575
3580
|
|
|
3576
3581
|
## Store operations
|
|
3577
3582
|
|
|
@@ -3739,6 +3744,299 @@ coalescing, collision, stale checkpoint, replay safety, terminal race, compactio
|
|
|
3739
3744
|
invariants against any fresh durable adapter.
|
|
3740
3745
|
|
|
3741
3746
|
|
|
3747
|
+
==============================================================================
|
|
3748
|
+
# Guide: Managed application kernel (docs/guide/application-kernel.md)
|
|
3749
|
+
==============================================================================
|
|
3750
|
+
|
|
3751
|
+
---
|
|
3752
|
+
title: Managed application kernel
|
|
3753
|
+
description: Compose process-local resources, schedules, readiness, drain and optional provider adapters without building a second job platform.
|
|
3754
|
+
type: architecture
|
|
3755
|
+
status: active
|
|
3756
|
+
created: 2026-08-23
|
|
3757
|
+
updated: 2026-08-23
|
|
3758
|
+
---
|
|
3759
|
+
|
|
3760
|
+
# Managed application kernel
|
|
3761
|
+
|
|
3762
|
+
Use `stitchkit/application` when several process-local resources must become
|
|
3763
|
+
ready and shut down as one application. Keep using the lower-level server and
|
|
3764
|
+
signal APIs when one managed server is already the complete lifecycle boundary.
|
|
3765
|
+
|
|
3766
|
+
The neutral entrypoint is server-only and works on Bun and Node ≥ 22. It does
|
|
3767
|
+
not import provider SDKs.
|
|
3768
|
+
|
|
3769
|
+
## Minimal composition
|
|
3770
|
+
|
|
3771
|
+
```ts
|
|
3772
|
+
import {
|
|
3773
|
+
createApplication,
|
|
3774
|
+
createManagedSchedule,
|
|
3775
|
+
defineManagedResource,
|
|
3776
|
+
managedServerResource,
|
|
3777
|
+
} from 'stitchkit/application'
|
|
3778
|
+
import { bindProcessSignals } from 'stitchkit/server'
|
|
3779
|
+
|
|
3780
|
+
const database = defineManagedResource({
|
|
3781
|
+
id: 'database',
|
|
3782
|
+
required: true,
|
|
3783
|
+
start: async ({ signal, reportHealth }) => {
|
|
3784
|
+
await db.connect({ signal })
|
|
3785
|
+
reportHealth('healthy')
|
|
3786
|
+
},
|
|
3787
|
+
close: () => db.disconnect(),
|
|
3788
|
+
})
|
|
3789
|
+
|
|
3790
|
+
const cleanup = createManagedSchedule({
|
|
3791
|
+
id: 'cleanup',
|
|
3792
|
+
dependsOn: ['database'],
|
|
3793
|
+
everyMs: 60_000,
|
|
3794
|
+
startAfterMs: 60_000,
|
|
3795
|
+
overlap: { mode: 'skip' },
|
|
3796
|
+
errorPolicy: 'continue',
|
|
3797
|
+
run: ({ signal }) => removeExpiredRecords(signal),
|
|
3798
|
+
})
|
|
3799
|
+
|
|
3800
|
+
const app = createApplication({
|
|
3801
|
+
id: 'service',
|
|
3802
|
+
resources: [
|
|
3803
|
+
database,
|
|
3804
|
+
managedServerResource({ id: 'http', server, dependsOn: ['database'] }),
|
|
3805
|
+
cleanup,
|
|
3806
|
+
],
|
|
3807
|
+
})
|
|
3808
|
+
|
|
3809
|
+
const signals = bindProcessSignals(app, {
|
|
3810
|
+
shutdown: { gracePeriodMs: 30_000, forceTimeoutMs: 5_000 },
|
|
3811
|
+
onComplete: (result) => {
|
|
3812
|
+
process.exitCode = result.outcome === 'clean' ? 0 : 1
|
|
3813
|
+
},
|
|
3814
|
+
})
|
|
3815
|
+
|
|
3816
|
+
await app.start()
|
|
3817
|
+
```
|
|
3818
|
+
|
|
3819
|
+
The exact resource callbacks are typed by their public configuration. The
|
|
3820
|
+
important ownership rule is stable: the application creates and configures the
|
|
3821
|
+
database/server/provider objects; Stitchkit orders their process-local
|
|
3822
|
+
lifecycle.
|
|
3823
|
+
|
|
3824
|
+
## Resource authoring
|
|
3825
|
+
|
|
3826
|
+
Give every resource a stable, bounded ID and list its dependencies explicitly.
|
|
3827
|
+
The graph is validated before any start. Required resources may depend only on
|
|
3828
|
+
required resources; an optional integration cannot silently become a required
|
|
3829
|
+
dependency.
|
|
3830
|
+
|
|
3831
|
+
Start and readiness are different. A connection can finish setup and return a
|
|
3832
|
+
ready handle. A poller can return a handle immediately, settle `ready` later,
|
|
3833
|
+
and keep a long-lived `completion` promise. Stitchkit observes both.
|
|
3834
|
+
|
|
3835
|
+
Once Stitchkit invokes start/activation, cleanup is guaranteed to be attempted.
|
|
3836
|
+
Write `close` so it is safe when setup was partial:
|
|
3837
|
+
|
|
3838
|
+
```ts
|
|
3839
|
+
let cacheClient: CacheClient | undefined
|
|
3840
|
+
|
|
3841
|
+
const cache = defineManagedResource({
|
|
3842
|
+
id: 'cache',
|
|
3843
|
+
required: false,
|
|
3844
|
+
start: async ({ signal, reportHealth }) => {
|
|
3845
|
+
cacheClient = new CacheClient()
|
|
3846
|
+
await cacheClient.connect(signal)
|
|
3847
|
+
reportHealth('healthy')
|
|
3848
|
+
},
|
|
3849
|
+
close: async () => {
|
|
3850
|
+
await cacheClient?.close()
|
|
3851
|
+
cacheClient = undefined
|
|
3852
|
+
},
|
|
3853
|
+
})
|
|
3854
|
+
```
|
|
3855
|
+
|
|
3856
|
+
Invoking `start` makes the descriptor rollback-eligible immediately. Its
|
|
3857
|
+
`close` callback must therefore clean side effects even when `start` rejects
|
|
3858
|
+
before returning a runtime handle. The kernel calls cleanup once and continues
|
|
3859
|
+
cleaning other attempted resources even if one close fails.
|
|
3860
|
+
|
|
3861
|
+
## Readiness and health
|
|
3862
|
+
|
|
3863
|
+
`await app.start()` resolves only after every required resource is ready and
|
|
3864
|
+
every required post-ready activation has succeeded. Lifecycle `ready` is
|
|
3865
|
+
published before activation so schedules never arm during `starting`;
|
|
3866
|
+
application admission opens only after successful activation. Optional failure
|
|
3867
|
+
may retain lifecycle `ready`, but snapshot health is `degraded`, never
|
|
3868
|
+
`healthy`.
|
|
3869
|
+
|
|
3870
|
+
Readiness is not hidden polling. A resource reports health changes through its
|
|
3871
|
+
lifecycle context; the application decides when a database/provider probe runs.
|
|
3872
|
+
A required long-lived completion that rejects after startup makes readiness
|
|
3873
|
+
false and health unhealthy. Stitchkit records the failure but does not restart
|
|
3874
|
+
the resource or process.
|
|
3875
|
+
|
|
3876
|
+
`createApplicationHealthHandler` exposes the neutral lifecycle/health snapshot
|
|
3877
|
+
through a Fetch-compatible handler, suitable for a raw route on Bun or Node.
|
|
3878
|
+
Product-specific probes may be composed beside it; do not put secrets or raw
|
|
3879
|
+
provider failures in the response.
|
|
3880
|
+
|
|
3881
|
+
## Admission and graceful shutdown
|
|
3882
|
+
|
|
3883
|
+
Use the application operation lease for work that is not already counted by a
|
|
3884
|
+
managed resource:
|
|
3885
|
+
|
|
3886
|
+
```ts
|
|
3887
|
+
const operation = app.admission.acquire()
|
|
3888
|
+
if (!operation) return Response.json({ error: 'unavailable' }, { status: 503 })
|
|
3889
|
+
|
|
3890
|
+
try {
|
|
3891
|
+
await performAcceptedWork()
|
|
3892
|
+
} finally {
|
|
3893
|
+
operation.release()
|
|
3894
|
+
}
|
|
3895
|
+
```
|
|
3896
|
+
|
|
3897
|
+
`release()` is idempotent. Admission and counter increment are atomic, so work
|
|
3898
|
+
cannot slip between the shutdown check and drain accounting.
|
|
3899
|
+
|
|
3900
|
+
Shutdown performs one phase barrier at a time: stop admission everywhere,
|
|
3901
|
+
cancel future schedules, drain admitted work, then close in reverse stable
|
|
3902
|
+
topological order. Every hook shares the same grace deadline. Forced cleanup
|
|
3903
|
+
shares one force deadline. Repeated `shutdown()` calls return the cached promise;
|
|
3904
|
+
a repeated process signal forces that same chain.
|
|
3905
|
+
|
|
3906
|
+
Do not add a second `process.on('SIGTERM')` handler around the application.
|
|
3907
|
+
`bindProcessSignals(app)` is the force/escalation owner. Exit code and hard-exit
|
|
3908
|
+
policy remain application/supervisor choices.
|
|
3909
|
+
|
|
3910
|
+
## Managed schedules
|
|
3911
|
+
|
|
3912
|
+
Schedules activate only after top-level readiness:
|
|
3913
|
+
|
|
3914
|
+
```ts
|
|
3915
|
+
createManagedSchedule({
|
|
3916
|
+
id: 'reconcile',
|
|
3917
|
+
everyMs: 5_000,
|
|
3918
|
+
startAfterMs: 0,
|
|
3919
|
+
overlap: { mode: 'queue-one' },
|
|
3920
|
+
errorPolicy: 'continue',
|
|
3921
|
+
onError: (error) => internalLogger.error(error),
|
|
3922
|
+
run: ({ signal }) => reconcile(signal),
|
|
3923
|
+
})
|
|
3924
|
+
```
|
|
3925
|
+
|
|
3926
|
+
- `skip` ignores a due tick while one execution is active.
|
|
3927
|
+
- `queue-one` retains one successor; additional due ticks coalesce.
|
|
3928
|
+
- `parallel` requires `maxConcurrent`; overflow skips rather than creating a
|
|
3929
|
+
hidden queue.
|
|
3930
|
+
|
|
3931
|
+
The callback receives the application shutdown signal. Normal shutdown waits
|
|
3932
|
+
for admitted executions; force aborts the shared signal. There are no retries,
|
|
3933
|
+
cron/timezone rules, persisted cursors, backfill or cross-process locks. Put
|
|
3934
|
+
those semantics in a durable application scheduler when they are required.
|
|
3935
|
+
Schedule cadence stays monotonic, while status snapshots expose ISO wall-clock
|
|
3936
|
+
`capturedAt`, `changedAt` and next/last-run timestamps for portable observation.
|
|
3937
|
+
|
|
3938
|
+
## Operational projection
|
|
3939
|
+
|
|
3940
|
+
Declare aggregate activity stages, then update them with anonymous handles:
|
|
3941
|
+
|
|
3942
|
+
```ts
|
|
3943
|
+
const generations = createActivityProjection({
|
|
3944
|
+
id: 'generation',
|
|
3945
|
+
stages: ['queued', 'running', 'finalizing'],
|
|
3946
|
+
})
|
|
3947
|
+
|
|
3948
|
+
const activity = generations.open('queued', 'queued')
|
|
3949
|
+
generations.transition(activity, { stage: 'running', state: 'active' })
|
|
3950
|
+
generations.transition(activity, { stage: 'finalizing', state: 'active' })
|
|
3951
|
+
generations.complete(activity)
|
|
3952
|
+
```
|
|
3953
|
+
|
|
3954
|
+
Item identity is deliberately absent from the snapshot. Observers receive
|
|
3955
|
+
aggregate counts with application identity, process epoch, revision and
|
|
3956
|
+
timestamps. Calling a terminal method twice does not double-count.
|
|
3957
|
+
|
|
3958
|
+
```ts
|
|
3959
|
+
const sink = createApplicationSnapshotSink({
|
|
3960
|
+
write: (snapshot) => publishOperationalSnapshot(snapshot),
|
|
3961
|
+
})
|
|
3962
|
+
|
|
3963
|
+
const unsubscribe = generations.subscribe((snapshot) => {
|
|
3964
|
+
sink.publish(snapshot)
|
|
3965
|
+
})
|
|
3966
|
+
|
|
3967
|
+
// During application cleanup:
|
|
3968
|
+
unsubscribe()
|
|
3969
|
+
await sink.close()
|
|
3970
|
+
```
|
|
3971
|
+
|
|
3972
|
+
The sink replays the current absolute value and coalesces obsolete pending
|
|
3973
|
+
revisions behind a slow write. Sink failure is observable but cannot fail the
|
|
3974
|
+
application operation that changed the projection.
|
|
3975
|
+
|
|
3976
|
+
## Optional grammY adapter
|
|
3977
|
+
|
|
3978
|
+
Install grammY only in an application that imports the adapter:
|
|
3979
|
+
|
|
3980
|
+
```ts
|
|
3981
|
+
import { Bot } from 'grammy'
|
|
3982
|
+
import {
|
|
3983
|
+
createGrammyWebhookResource,
|
|
3984
|
+
grammyPollingResource,
|
|
3985
|
+
} from 'stitchkit/application/grammy'
|
|
3986
|
+
```
|
|
3987
|
+
|
|
3988
|
+
For simple long polling, pass an already-configured bot:
|
|
3989
|
+
|
|
3990
|
+
```ts
|
|
3991
|
+
const bot = new Bot(env.BOT_TOKEN)
|
|
3992
|
+
bot.command('start', (ctx) => ctx.reply('Hello'))
|
|
3993
|
+
bot.catch(({ error }) => internalLogger.error(error))
|
|
3994
|
+
|
|
3995
|
+
const telegram = grammyPollingResource({
|
|
3996
|
+
id: 'telegram',
|
|
3997
|
+
bot,
|
|
3998
|
+
required: true,
|
|
3999
|
+
})
|
|
4000
|
+
```
|
|
4001
|
+
|
|
4002
|
+
Readiness follows grammY's `onStart`. Shutdown calls `bot.stop()` once and then
|
|
4003
|
+
awaits the retained `bot.start()` promise, because grammY documents that
|
|
4004
|
+
`stop()` alone does not wait for middleware completion.
|
|
4005
|
+
|
|
4006
|
+
For webhook ingress, `createGrammyWebhookResource` wraps provider-owned update
|
|
4007
|
+
handling with admission and drain. The application still mounts the HTTP route,
|
|
4008
|
+
verifies/configures its webhook and chooses the grammY framework adapter. An
|
|
4009
|
+
update accepted before shutdown may finish; a later update is rejected.
|
|
4010
|
+
|
|
4011
|
+
The adapter never reads the token/env, installs commands, changes `bot.catch`,
|
|
4012
|
+
chooses retry plugins, drops pending updates, sends outbound messages or stores
|
|
4013
|
+
updates. A durable inbox/retry worker remains an application component, not a
|
|
4014
|
+
mode of this adapter.
|
|
4015
|
+
|
|
4016
|
+
## What disappears from an application
|
|
4017
|
+
|
|
4018
|
+
A typical small service can replace roughly 120–220 lines of generic signal,
|
|
4019
|
+
timer, admission and close bookkeeping with resource declarations. A larger
|
|
4020
|
+
multi-resource service commonly carries 250–450 generic lifecycle lines plus
|
|
4021
|
+
15–30 lines for each periodic timer. These are directional review estimates,
|
|
4022
|
+
not an API guarantee.
|
|
4023
|
+
|
|
4024
|
+
The responsibility change is more important than line count:
|
|
4025
|
+
|
|
4026
|
+
| Before | After |
|
|
4027
|
+
|---|---|
|
|
4028
|
+
| hand-written phase enum and readiness waiters | `createApplication` snapshot |
|
|
4029
|
+
| `process.on` signal loop and escalation | `bindProcessSignals(app)` |
|
|
4030
|
+
| interval/timeout handles and overlap flag | `createManagedSchedule` |
|
|
4031
|
+
| global in-flight counter and drain waiter set | application operation leases |
|
|
4032
|
+
| manual stop/close fan-out | resource graph + bounded shutdown |
|
|
4033
|
+
| progress delta events | absolute activity projection |
|
|
4034
|
+
|
|
4035
|
+
Durable job tables, lifecycle journals/outboxes, provider inboxes and business
|
|
4036
|
+
retry rules do **not** disappear. They were never process-local glue and remain
|
|
4037
|
+
application-owned.
|
|
4038
|
+
|
|
4039
|
+
|
|
3742
4040
|
==============================================================================
|
|
3743
4041
|
# Guide: CLI (docs/guide/cli.md)
|
|
3744
4042
|
==============================================================================
|
|
@@ -3879,6 +4177,32 @@ validation, dry-run, error envelopes and exit mapping, but deliberately have no
|
|
|
3879
4177
|
fake service/action/scope/method identity, lifecycle or tool hooks and never
|
|
3880
4178
|
appear in MCP/Agent manifests.
|
|
3881
4179
|
|
|
4180
|
+
A native command with a declared output may also own its final terminal
|
|
4181
|
+
presentation and successful process status. Both callbacks receive the exact
|
|
4182
|
+
Zod output type and run only after output validation; help, dry-run and failed
|
|
4183
|
+
validation never invoke them:
|
|
4184
|
+
|
|
4185
|
+
```ts
|
|
4186
|
+
const doctor = defineCliCommand({
|
|
4187
|
+
name: 'doctor',
|
|
4188
|
+
description: 'Inspect local health',
|
|
4189
|
+
input: z.object({}),
|
|
4190
|
+
output: z.object({ status: z.enum(['ok', 'degraded']) }),
|
|
4191
|
+
handler: () => ({ status: 'degraded' }),
|
|
4192
|
+
present: ({ result, options }) =>
|
|
4193
|
+
options.json ? `${JSON.stringify(result)}\n` : `STATUS ${result.status}\n`,
|
|
4194
|
+
exitCode: (result) => result.status === 'degraded' ? 1 : 0,
|
|
4195
|
+
})
|
|
4196
|
+
```
|
|
4197
|
+
|
|
4198
|
+
`present` returns the exact stdout bytes, which Stitchkit writes once. Without
|
|
4199
|
+
it the canonical JSON output is unchanged. `exitCode` classifies a successfully
|
|
4200
|
+
validated result and must return an integer in `0..255`; failed `ToolResult`
|
|
4201
|
+
envelopes and the application-wide `exitCodes` mapping remain authoritative for
|
|
4202
|
+
failures. A throwing callback, invalid status or non-string presenter becomes a
|
|
4203
|
+
normalized `INTERNAL_SERVER_ERROR`, never partial success output. Void native
|
|
4204
|
+
commands cannot declare either callback.
|
|
4205
|
+
|
|
3882
4206
|
`--version`, a selected native command and its command help run before
|
|
3883
4207
|
`resolveAuth`, services, context or runtime-tool factories. Top-level help is
|
|
3884
4208
|
also credential-free when managed surfaces are static. A dynamic factory must
|
|
@@ -3905,9 +4229,52 @@ string, the schema says what it should be:
|
|
|
3905
4229
|
| `z.object({...})` | `--opts '{"k":"v"}'` (JSON) or `--opts.k v` |
|
|
3906
4230
|
| `.optional()` / `.default()` | not required |
|
|
3907
4231
|
|
|
3908
|
-
|
|
3909
|
-
`myapp generate "a fox"` is
|
|
3910
|
-
|
|
4232
|
+
Without presentation configuration, positional arguments fill non-boolean
|
|
4233
|
+
fields in declaration order, so `myapp generate "a fox"` is
|
|
4234
|
+
`--prompt "a fox"`. A piped value fills the first required unset field:
|
|
4235
|
+
`echo "a fox" | myapp generate`.
|
|
4236
|
+
|
|
4237
|
+
For a stable shell grammar, declare the default command, short aliases and the
|
|
4238
|
+
exact positional fields on `createCli`:
|
|
4239
|
+
|
|
4240
|
+
```ts
|
|
4241
|
+
await createCli({
|
|
4242
|
+
name: 'myapp',
|
|
4243
|
+
version: '1.0.0',
|
|
4244
|
+
services,
|
|
4245
|
+
commands: [doctor],
|
|
4246
|
+
defaultCommand: 'logs',
|
|
4247
|
+
optionAliases: {
|
|
4248
|
+
logs: { f: 'follow', n: 'lines' },
|
|
4249
|
+
},
|
|
4250
|
+
positionals: {
|
|
4251
|
+
logs: ['target'], // `lines` is option-only
|
|
4252
|
+
doctor: [], // no argv positionals
|
|
4253
|
+
},
|
|
4254
|
+
})
|
|
4255
|
+
```
|
|
4256
|
+
|
|
4257
|
+
Now `myapp`, `myapp --json` and `myapp logs --json` select `logs`;
|
|
4258
|
+
`myapp -f -n 100 --target api` maps to
|
|
4259
|
+
`logs --follow --lines 100 --target api`. A leading non-option token remains an
|
|
4260
|
+
explicit command so typos stay loud rather than becoming ambiguous default
|
|
4261
|
+
positionals; use an explicit `myapp logs api` when passing positionals. Leading
|
|
4262
|
+
framework globals may precede that explicit command. Top-level `--help`, `-h`
|
|
4263
|
+
and `--version` never execute the default, and top-level help marks it.
|
|
4264
|
+
|
|
4265
|
+
Aliases are command-local, one ASCII letter and validated against the resolved
|
|
4266
|
+
command schema. `-f` / `-f=false` are boolean forms; values accept `-n 100` and
|
|
4267
|
+
`-n=100`. Arrays accumulate across short and long forms. `-h` is reserved,
|
|
4268
|
+
bundles such as `-fn`, attached values such as `-n100`, `--no-f` and unknown
|
|
4269
|
+
short flags are rejected. Canonical `--no-follow` remains available.
|
|
4270
|
+
|
|
4271
|
+
`positionals` replaces automatic schema-order selection only for the named
|
|
4272
|
+
command. An empty array disables argv positionals. Fields remain available as
|
|
4273
|
+
long/short options and stdin still fills the first required unset field with the
|
|
4274
|
+
same schema-aware coercion. Unknown, duplicate or boolean targets and a required
|
|
4275
|
+
positional after an optional/default positional fail when that command surface
|
|
4276
|
+
resolves. Native dispatch retains its lazy credential-free boundary; dynamic
|
|
4277
|
+
managed policies validate when their identity-dependent surface resolves.
|
|
3911
4278
|
|
|
3912
4279
|
The advertised schema is never mutated — a CLI call validates against the exact
|
|
3913
4280
|
same Zod schema an HTTP or MCP call does.
|
|
@@ -3932,10 +4299,12 @@ diagnostics remain ordinary stderr text. This keeps stdout pipeable and
|
|
|
3932
4299
|
`VALIDATION_ERROR → 1`, `UNAUTHORIZED → 2`, `FORBIDDEN → 3`, `NOT_FOUND → 4`,
|
|
3933
4300
|
…) — override per app with `exitCodes`.
|
|
3934
4301
|
|
|
3935
|
-
Per-command help derives the positional form from the same
|
|
3936
|
-
argv parser. For example, a required `action` and optional `profile` render as
|
|
4302
|
+
Per-command help derives the positional form from the same resolved policy as
|
|
4303
|
+
the argv parser. For example, a required `action` and optional `profile` render as
|
|
3937
4304
|
`Usage: myapp skill <action> [profile] [--flags]`; the argument table also shows
|
|
3938
4305
|
`<action> | --action` and `[profile] | --profile`. Boolean fields remain flags.
|
|
4306
|
+
Declared aliases render beside their canonical options, for example
|
|
4307
|
+
`-n, --lines`.
|
|
3939
4308
|
|
|
3940
4309
|
## `--wait` — background-friendly generation
|
|
3941
4310
|
|
|
@@ -8053,6 +8422,92 @@ Also re-exports the error helpers from `stitchkit/contract`.
|
|
|
8053
8422
|
|
|
8054
8423
|
---
|
|
8055
8424
|
|
|
8425
|
+
## `stitchkit/application`
|
|
8426
|
+
|
|
8427
|
+
Server-only process-local application composition. See the
|
|
8428
|
+
[application kernel guide](../guide/application-kernel.md) and
|
|
8429
|
+
[architecture](../architecture/application-kernel.md).
|
|
8430
|
+
|
|
8431
|
+
### Kernel and resources
|
|
8432
|
+
|
|
8433
|
+
| Export | Kind | Summary |
|
|
8434
|
+
|--------|------|---------|
|
|
8435
|
+
| `createApplication` | function | compose a validated resource DAG into one non-restartable startup, readiness, admission and shutdown state machine |
|
|
8436
|
+
| `defineManagedResource` | function | retain the exact typed resource declaration; every invoked start is rollback-eligible |
|
|
8437
|
+
| `managedServerResource` | function | adapt an existing managed server without copying its HTTP/WebSocket shutdown machine |
|
|
8438
|
+
| `createApplicationHealthHandler` | function | build a Fetch-clean liveness or readiness response from the sanitized application snapshot |
|
|
8439
|
+
| `ApplicationAdmissionError` | class | stable `APPLICATION_NOT_ACCEPTING` rejection from `admission.run(...)` |
|
|
8440
|
+
| `ApplicationConfig` / `ApplicationHandle` | _type_ | application declaration and its start/snapshot/subscription/admission/shutdown handle |
|
|
8441
|
+
| `ApplicationAdmission` / `ApplicationOperationLease` | _type_ | atomic process-local admission and idempotent release primitive |
|
|
8442
|
+
| `ManagedResource` / `ManagedResourceContext` / `ManagedResourceStartResult` | _type_ | resource lifecycle callbacks, shared deadlines, health reporting and separate readiness/completion promises |
|
|
8443
|
+
| `ManagedServerResourceConfig` | _type_ | existing managed server, stable ID, dependencies and policy for `managedServerResource` |
|
|
8444
|
+
| `ApplicationHealthHandlerOptions` / `ApplicationHealthHandlerOptionsSchema` | _type_ / schema | liveness/readiness selection and sanitized `Retry-After` policy |
|
|
8445
|
+
|
|
8446
|
+
### Managed schedules
|
|
8447
|
+
|
|
8448
|
+
| Export | Kind | Summary |
|
|
8449
|
+
|--------|------|---------|
|
|
8450
|
+
| `createManagedSchedule` | function | fixed-rate process-local timer that activates after top-level readiness and participates in drain |
|
|
8451
|
+
| `ManagedScheduleOverlapSchema` / `ManagedScheduleOverlap` | schema / _type_ | `skip`, `queue-one` or bounded `parallel` overlap policy |
|
|
8452
|
+
| `ManagedScheduleErrorPolicySchema` / `ManagedScheduleErrorPolicy` | schema / _type_ | `continue` or `stop-schedule` after an observed callback failure |
|
|
8453
|
+
| `ManagedScheduleDescriptorSchema` / `ManagedScheduleDescriptor` | schema / _type_ | immutable public schedule identity and cadence policy |
|
|
8454
|
+
| `ManagedScheduleStatusSchema` / `ManagedScheduleStatus` | schema / _type_ | absolute schedule state, revision, counters and timestamps |
|
|
8455
|
+
|
|
8456
|
+
Schedule authoring additionally exports `ManagedSchedule`, `ManagedScheduleConfig`,
|
|
8457
|
+
`ManagedScheduleRunContext`, `ManagedScheduleClock` and `ManagedScheduleTimer`.
|
|
8458
|
+
The clock exposes monotonic cadence/deadline arithmetic and a wall-clock projection for portable
|
|
8459
|
+
status timestamps; it is a deterministic test boundary, not a durable scheduler.
|
|
8460
|
+
|
|
8461
|
+
### Application and activity projection
|
|
8462
|
+
|
|
8463
|
+
| Export | Kind | Summary |
|
|
8464
|
+
|--------|------|---------|
|
|
8465
|
+
| `createActivityProjection` | function | aggregate anonymous process-local activity into declared bounded stages and absolute snapshots |
|
|
8466
|
+
| `createApplicationSnapshotSink` | function | latest-value delivery with one write in flight and one replaceable pending revision |
|
|
8467
|
+
| `applicationLifecycleEvent` | function | project a sanitized lifecycle fact from a canonical application snapshot |
|
|
8468
|
+
| `createApplicationEventSink` | function | bounded failure-isolated lifecycle-event delivery; events are not canonical state |
|
|
8469
|
+
| `ActivitySnapshotSchema` / `ActivitySnapshot` | schema / _type_ | epoch, monotonic revision, timestamps, declared stages and aggregate counts |
|
|
8470
|
+
| `ApplicationSnapshotSinkStatusSchema` / `ApplicationSnapshotSinkStatus` | schema / _type_ | immutable latest-value sink delivery and coalescing counters |
|
|
8471
|
+
| `ApplicationLifecycleEventSchema` / `ApplicationLifecycleEvent` | schema / _type_ | sanitized operator-facing application lifecycle fact |
|
|
8472
|
+
|
|
8473
|
+
Activity authoring additionally exports `ActivityId`, `ActivityIdSchema`,
|
|
8474
|
+
`ActivityStageId`, `ActivityStageIdSchema`, `ActivityStageSnapshot`,
|
|
8475
|
+
`ActivityStageSnapshotSchema`, `ActivityLiveState`, `ActivityLiveStateSchema`,
|
|
8476
|
+
`ActivityProjection`, `ActivityProjectionConfig`,
|
|
8477
|
+
`ActivityProjectionSubscriberError`, `ActivityToken` and `ActivityTransition`.
|
|
8478
|
+
Latest-value delivery exports `ApplicationSnapshotSink`,
|
|
8479
|
+
`ApplicationSnapshotSinkConfig`, `ApplicationSnapshotSinkError` and
|
|
8480
|
+
`RevisionedApplicationSnapshot`; event delivery exports `ApplicationEventSink`
|
|
8481
|
+
and `ApplicationEventSinkConfig`.
|
|
8482
|
+
|
|
8483
|
+
### Canonical application records
|
|
8484
|
+
|
|
8485
|
+
The entrypoint exports each Zod schema beside its inferred type:
|
|
8486
|
+
`ApplicationIdSchema` / `ApplicationId`, `ApplicationLifecycleSchema` /
|
|
8487
|
+
`ApplicationLifecycle`, `ApplicationHealthSchema` / `ApplicationHealth`,
|
|
8488
|
+
`ManagedResourceStateSchema` / `ManagedResourceState`,
|
|
8489
|
+
`ApplicationAdmissionSnapshotSchema` / `ApplicationAdmissionSnapshot`,
|
|
8490
|
+
`ManagedResourceSnapshotSchema` / `ManagedResourceSnapshot`,
|
|
8491
|
+
`ApplicationSnapshotSchema` / `ApplicationSnapshot`,
|
|
8492
|
+
`ApplicationResourceShutdownSchema` / `ApplicationResourceShutdown`, and
|
|
8493
|
+
`ApplicationShutdownResultSchema` / `ApplicationShutdownResult`.
|
|
8494
|
+
|
|
8495
|
+
## `stitchkit/application/grammy`
|
|
8496
|
+
|
|
8497
|
+
Isolated optional-peer lifecycle adapters. Importing `stitchkit/application`
|
|
8498
|
+
does not resolve grammY.
|
|
8499
|
+
|
|
8500
|
+
| Export | Kind | Summary |
|
|
8501
|
+
|--------|------|---------|
|
|
8502
|
+
| `grammyPollingResource` | function | adapt an injected bot's long polling with distinct `onStart` readiness, observed completion and one stop chain |
|
|
8503
|
+
| `createGrammyWebhookResource` | function | return a managed resource plus admission-guarded `handleUpdate`; HTTP hosting and webhook registration stay application-owned |
|
|
8504
|
+
| `GrammyWebhookUnavailableError` | class | stable `GRAMMY_WEBHOOK_NOT_ACCEPTING` rejection after webhook admission closes |
|
|
8505
|
+
| `GrammyPollingResourceConfig` | _type_ | injected bot, polling options, resource graph policy and isolated error observer |
|
|
8506
|
+
| `GrammyWebhookResourceConfig` / `GrammyWebhookResource` | _type_ | injected webhook bot declaration and `{ resource, handleUpdate }` handle |
|
|
8507
|
+
| `GrammyUpdate` | _type_ | exact update input inferred from the injected grammY bot context |
|
|
8508
|
+
|
|
8509
|
+
---
|
|
8510
|
+
|
|
8056
8511
|
## `stitchkit/agent-runtime`
|
|
8057
8512
|
|
|
8058
8513
|
Server-only optional application runtime. See the
|
|
@@ -8060,7 +8515,7 @@ Server-only optional application runtime. See the
|
|
|
8060
8515
|
|
|
8061
8516
|
| Export | Kind | Summary |
|
|
8062
8517
|
|--------|------|---------|
|
|
8063
|
-
| `createAgentRuntime` | function | compose durable acceptance, stream loop, checkpoints, coordination, managed tools and terminal publication |
|
|
8518
|
+
| `createAgentRuntime` | function | compose durable acceptance, stream loop, checkpoints, coordination, managed tools and winner-only terminal publication; reconciles same-owner terminal/interrupt/head CAS races before releasing the lane |
|
|
8064
8519
|
| `defineAgentProtocol` | function | declare and validate context, input metadata and canonical message parts |
|
|
8065
8520
|
| `AgentMessageSchema` / `AgentRunSchema` / `AgentSnapshotSchema` | schema | versioned canonical engine records |
|
|
8066
8521
|
| `AgentRuntimeStore` | _type_ | aggregate CAS transaction boundary for message, run and compaction mutations |
|
|
@@ -8265,7 +8720,7 @@ payload.
|
|
|
8265
8720
|
| `createRuntimeToolFactory` | function | bind shared identity and Zod-validated per-call context for runtime tools — [guide](../guide/mcp-and-agents.md#pathless-runtime-tools-and-multimodal-results) |
|
|
8266
8721
|
| `createToolInvoker` | function | compile an exposure-aware in-process dispatcher over the canonical tool runner — [guide](../guide/mcp-and-agents.md#in-process-calls--createtoolinvoker) |
|
|
8267
8722
|
| `createCli` | function | a command-line program from contracts — [guide](../guide/cli.md) (also on `stitchkit/cli`) |
|
|
8268
|
-
| `defineCliCommand` | function | define one typed CLI-only command with
|
|
8723
|
+
| `defineCliCommand` | function | define one typed CLI-only command with optional post-validation `present` and successful `exitCode` policy — [guide](../guide/cli.md#native-binary-commands) (also on `stitchkit/cli`) |
|
|
8269
8724
|
| `createToolkit` | function | context-typed tool mounts — [guide](../guide/cli.md#typed-context) |
|
|
8270
8725
|
| `mountViewFile` | function | a native multimodal "view file" MCP tool |
|
|
8271
8726
|
| `resolveMedia` | function | resolve a media reference for a tool result |
|
|
@@ -8322,11 +8777,12 @@ payload.
|
|
|
8322
8777
|
| `RuntimeToolTransport` | _type_ | runtime exposure: `'MCP' \| 'AGENT' \| 'CLI'`; omission still means MCP+Agent only |
|
|
8323
8778
|
| `AgentMountConfig` | _type_ | config for `mountAgent` |
|
|
8324
8779
|
| `AgentContext` | _type_ | the context merged into agent tool handlers |
|
|
8325
|
-
| `CliConfig` | _type_ | config for `createCli` |
|
|
8780
|
+
| `CliConfig` | _type_ | config for `createCli`, including program-level `defaultCommand` selection and command-scoped `optionAliases` / `positionals` policy |
|
|
8781
|
+
| `CliPresentationPolicyConfig` | _type_ | reusable default-command, short-alias and explicit-positional policy inherited by `CliConfig` |
|
|
8326
8782
|
| `CliSurfaceSource` | _type_ | static managed surface or identity-dependent surface factory for `createCli` |
|
|
8327
8783
|
| `CliCommandDefinition` | _type_ | Zod-first CLI-only command union |
|
|
8328
8784
|
| `CliCommandDefinitionBase` | _type_ | native command name, description and input schema |
|
|
8329
|
-
| `CliCommandDefinitionWithOutput` | _type_ | native command with declared output schema
|
|
8785
|
+
| `CliCommandDefinitionWithOutput` | _type_ | native command with declared output schema, validated handler result and typed optional `present` / `exitCode` callbacks |
|
|
8330
8786
|
| `CliCommandDefinitionWithoutOutput` | _type_ | void native command with no output schema |
|
|
8331
8787
|
| `CliCommandContext` | _type_ | parsed native command input, global options and injected writers |
|
|
8332
8788
|
| `CliWaitConfig` | _type_ | `--wait` polling config |
|
|
@@ -8590,16 +9046,17 @@ SDK nor the `ai` peer.
|
|
|
8590
9046
|
| Export | Kind | Summary |
|
|
8591
9047
|
|--------|------|---------|
|
|
8592
9048
|
| `createCli` | function | build and run a CLI from contracts — [guide](../guide/cli.md) |
|
|
8593
|
-
| `defineCliCommand` | function | define one Zod-typed CLI-only executable command |
|
|
9049
|
+
| `defineCliCommand` | function | define one Zod-typed CLI-only executable command with optional validated-result presentation/exit policy |
|
|
8594
9050
|
| `parseCliArgs` | function | argv → typed tool args against a schema (advanced) |
|
|
8595
9051
|
| `pollUntilDone` | function | the generic `--wait` poller (advanced) |
|
|
8596
9052
|
| `emitResult` | function | write a pretty or compact `ToolResult` record to stdout/stderr + exit code (advanced) |
|
|
8597
9053
|
| `DEFAULT_EXIT_CODES` | const | the default `ToolResult.code` → exit-code map |
|
|
8598
|
-
| `CliConfig` | _type_ | config for `createCli` |
|
|
9054
|
+
| `CliConfig` | _type_ | config for `createCli`; `defaultCommand`, `optionAliases` and `positionals` define the shared command presentation policy |
|
|
9055
|
+
| `CliPresentationPolicyConfig` | _type_ | shared command presentation-policy subset of `CliConfig` |
|
|
8599
9056
|
| `CliSurfaceSource` | _type_ | static service/runtime array or identity-dependent factory |
|
|
8600
9057
|
| `CliCommandDefinition` | _type_ | native command definition union |
|
|
8601
9058
|
| `CliCommandDefinitionBase` | _type_ | native command name, description and input schema |
|
|
8602
|
-
| `CliCommandDefinitionWithOutput` | _type_ | native command with validated declared output |
|
|
9059
|
+
| `CliCommandDefinitionWithOutput` | _type_ | native command with validated declared output and typed optional `present` / successful `exitCode` callbacks |
|
|
8603
9060
|
| `CliCommandDefinitionWithoutOutput` | _type_ | native void command without an output contract |
|
|
8604
9061
|
| `CliCommandContext` | _type_ | parsed input, global options and stdout/stderr writers |
|
|
8605
9062
|
| `CliRunOptions` | _type_ | parsed global flags (`--json` compacts success/error records, `--wait`, …) |
|
package/llms.txt
CHANGED
|
@@ -11,6 +11,7 @@ Build with stitchkit: define a contract once, then `implement` it and serve it (
|
|
|
11
11
|
- [Typed client](https://github.com/max-listov/stitchkit/blob/master/docs/guide/client.md): createClient/createHttpClient, the typed call surface, scoped clients, SSE
|
|
12
12
|
- [MCP & agents](https://github.com/max-listov/stitchkit/blob/master/docs/guide/mcp-and-agents.md): contracts as MCP tools (createMcpHandler) and AI-agent tools (mountAgent); tool lifecycle, extend, identity
|
|
13
13
|
- [Agent application runtime](https://github.com/max-listov/stitchkit/blob/master/docs/guide/agent-runtime.md): optional durable history, prompt/model composition, stream loop, coordination, fencing and events
|
|
14
|
+
- [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
|
|
14
15
|
- [CLI](https://github.com/max-listov/stitchkit/blob/master/docs/guide/cli.md): contracts as a command-line program
|
|
15
16
|
- [Realtime](https://github.com/max-listov/stitchkit/blob/master/docs/guide/realtime.md): Socket.IO server/client wrappers, handshake auth, the cache bridge, a raw WebSocket lane
|
|
16
17
|
- [Auth & errors](https://github.com/max-listov/stitchkit/blob/master/docs/guide/auth-and-errors.md): scopes, createAuthHook, JWT/cookies, the AppError model, the stitch error-code registry
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stitchkit",
|
|
3
|
-
"version": "0.59.
|
|
3
|
+
"version": "0.59.2",
|
|
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",
|
|
@@ -84,6 +84,14 @@
|
|
|
84
84
|
"types": "./dist/agent-runtime-openrouter.d.ts",
|
|
85
85
|
"import": "./dist/agent-runtime-openrouter.js"
|
|
86
86
|
},
|
|
87
|
+
"./application": {
|
|
88
|
+
"types": "./dist/application.d.ts",
|
|
89
|
+
"import": "./dist/application.js"
|
|
90
|
+
},
|
|
91
|
+
"./application/grammy": {
|
|
92
|
+
"types": "./dist/application-grammy.d.ts",
|
|
93
|
+
"import": "./dist/application-grammy.js"
|
|
94
|
+
},
|
|
87
95
|
"./testing": {
|
|
88
96
|
"types": "./dist/testing.d.ts",
|
|
89
97
|
"import": "./dist/testing.js"
|
|
@@ -103,7 +111,7 @@
|
|
|
103
111
|
"scripts": {
|
|
104
112
|
"check": "bun x tsc --noEmit",
|
|
105
113
|
"build:browser": "bun build src/index.ts src/react.ts src/contract/index.ts --outdir dist --target node --packages external --splitting --root src",
|
|
106
|
-
"build:server": "bun build src/server/index.ts src/node.ts src/tools.ts src/cli.ts src/remote.ts src/files.ts src/testing.ts src/observability/index.ts src/agent-runtime.ts src/agent-runtime-openrouter.ts --outdir dist --target node --packages external --splitting --root src",
|
|
114
|
+
"build:server": "bun build src/server/index.ts src/node.ts src/tools.ts src/cli.ts src/remote.ts src/files.ts src/testing.ts src/observability/index.ts src/agent-runtime.ts src/agent-runtime-openrouter.ts src/application.ts src/application-grammy.ts --outdir dist --target node --packages external --splitting --root src",
|
|
107
115
|
"build:js": "bun run build:browser && bun run build:server",
|
|
108
116
|
"build:types": "bun x tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
109
117
|
"build": "rm -rf dist && bun run build:js && bun run build:types && bun scripts/check-browser-clean.mjs && bun scripts/check-env-live.mjs && bun scripts/check-public-types.mjs",
|
|
@@ -124,6 +132,7 @@
|
|
|
124
132
|
"@socket.io/component-emitter": "^3.1.2",
|
|
125
133
|
"@tanstack/react-query": ">=5",
|
|
126
134
|
"ai": "^7.0.0",
|
|
135
|
+
"grammy": "^1.45.1",
|
|
127
136
|
"react": ">=18",
|
|
128
137
|
"react-query-kit": "^3.3.3",
|
|
129
138
|
"socket.io": "^4.8.3",
|
|
@@ -156,6 +165,9 @@
|
|
|
156
165
|
"ai": {
|
|
157
166
|
"optional": true
|
|
158
167
|
},
|
|
168
|
+
"grammy": {
|
|
169
|
+
"optional": true
|
|
170
|
+
},
|
|
159
171
|
"react": {
|
|
160
172
|
"optional": true
|
|
161
173
|
},
|
|
@@ -188,6 +200,7 @@
|
|
|
188
200
|
"@types/react": "^19.2.18",
|
|
189
201
|
"@typescript/typescript6": "^6.0.2",
|
|
190
202
|
"ai": "^7.0.65",
|
|
203
|
+
"grammy": "^1.45.1",
|
|
191
204
|
"react": "^19.2.8",
|
|
192
205
|
"react-query-kit": "^3.3.4",
|
|
193
206
|
"socket.io": "^4.8.3",
|