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.
Files changed (61) hide show
  1. package/README.md +44 -4
  2. package/dist/agent-runtime/runtime.d.ts.map +1 -1
  3. package/dist/agent-runtime/terminal-commit.d.ts +102 -0
  4. package/dist/agent-runtime/terminal-commit.d.ts.map +1 -0
  5. package/dist/agent-runtime.js +143 -46
  6. package/dist/application/activity.d.ts +70 -0
  7. package/dist/application/activity.d.ts.map +1 -0
  8. package/dist/application/events.d.ts +65 -0
  9. package/dist/application/events.d.ts.map +1 -0
  10. package/dist/application/grammy.d.ts +35 -0
  11. package/dist/application/grammy.d.ts.map +1 -0
  12. package/dist/application/graph.d.ts +11 -0
  13. package/dist/application/graph.d.ts.map +1 -0
  14. package/dist/application/health.d.ts +13 -0
  15. package/dist/application/health.d.ts.map +1 -0
  16. package/dist/application/kernel.d.ts +31 -0
  17. package/dist/application/kernel.d.ts.map +1 -0
  18. package/dist/application/latest-sink.d.ts +39 -0
  19. package/dist/application/latest-sink.d.ts.map +1 -0
  20. package/dist/application/resource.d.ts +30 -0
  21. package/dist/application/resource.d.ts.map +1 -0
  22. package/dist/application/schedule.d.ts +112 -0
  23. package/dist/application/schedule.d.ts.map +1 -0
  24. package/dist/application/schemas.d.ts +160 -0
  25. package/dist/application/schemas.d.ts.map +1 -0
  26. package/dist/application/server-resource.d.ts +12 -0
  27. package/dist/application/server-resource.d.ts.map +1 -0
  28. package/dist/application-grammy.d.ts +2 -0
  29. package/dist/application-grammy.d.ts.map +1 -0
  30. package/dist/application-grammy.js +165 -0
  31. package/dist/application.d.ts +10 -0
  32. package/dist/application.d.ts.map +1 -0
  33. package/dist/application.js +1370 -0
  34. package/dist/cli.d.ts +1 -0
  35. package/dist/cli.d.ts.map +1 -1
  36. package/dist/cli.js +1 -1
  37. package/dist/{index-zk5zn2nh.js → index-3nwng7hs.js} +287 -38
  38. package/dist/index-dk6e56g0.js +211 -0
  39. package/dist/{index-9zn9fb4e.js → index-he4psyve.js} +6 -213
  40. package/dist/index-yr276yz0.js +6 -0
  41. package/dist/internal/fetch-port.d.ts +2 -0
  42. package/dist/internal/fetch-port.d.ts.map +1 -0
  43. package/dist/node.js +115 -13
  44. package/dist/server/index.js +8 -6
  45. package/dist/server/node.d.ts.map +1 -1
  46. package/dist/server/process-signals.d.ts +10 -8
  47. package/dist/server/process-signals.d.ts.map +1 -1
  48. package/dist/tools/cli-args.d.ts +16 -0
  49. package/dist/tools/cli-args.d.ts.map +1 -1
  50. package/dist/tools/cli-command.d.ts +16 -0
  51. package/dist/tools/cli-command.d.ts.map +1 -1
  52. package/dist/tools/cli-policy.d.ts +22 -0
  53. package/dist/tools/cli-policy.d.ts.map +1 -0
  54. package/dist/tools/cli.d.ts +2 -1
  55. package/dist/tools/cli.d.ts.map +1 -1
  56. package/dist/tools.d.ts +1 -0
  57. package/dist/tools.d.ts.map +1 -1
  58. package/dist/tools.js +1 -1
  59. package/llms-full.txt +471 -14
  60. package/llms.txt +1 -0
  61. 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. `runtime.stop(key)` is the process-local signal-only escape
3574
- hatch.
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
- Positional arguments fill non-boolean fields in declaration order, so
3909
- `myapp generate "a fox"` is `--prompt "a fox"`. A piped value fills the first
3910
- unset field: `echo "a fox" | myapp generate`.
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 schema order as the
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 no fake managed-tool identity — [guide](../guide/cli.md#native-binary-commands) (also on `stitchkit/cli`) |
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 and validated handler result |
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.0",
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",