stitchkit 0.94.1 → 0.95.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/dist/agent-runtime/provider-origin.d.ts +7 -0
- package/dist/agent-runtime/provider-origin.d.ts.map +1 -1
- package/dist/agent-runtime/run-operation-lifecycle.d.ts.map +1 -1
- package/dist/application/directory-inbox-contract.d.ts +129 -0
- package/dist/application/directory-inbox-contract.d.ts.map +1 -0
- package/dist/application/directory-inbox.d.ts +3 -0
- package/dist/application/directory-inbox.d.ts.map +1 -0
- package/dist/application/process-lifecycle-transitions.d.ts +175 -0
- package/dist/application/process-lifecycle-transitions.d.ts.map +1 -0
- package/dist/application/process-lifecycle.d.ts +3 -131
- package/dist/application/process-lifecycle.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/harness.js +1 -1
- package/dist/entrypoints/agent-runtime.js +1 -1
- package/dist/entrypoints/application/directory-inbox.d.ts +11 -0
- package/dist/entrypoints/application/directory-inbox.d.ts.map +1 -0
- package/dist/entrypoints/application/directory-inbox.js +221 -0
- package/dist/entrypoints/application.d.ts +3 -1
- package/dist/entrypoints/application.d.ts.map +1 -1
- package/dist/entrypoints/application.js +151 -56
- package/dist/entrypoints/server.js +6 -219
- package/dist/index-5jrd0yng.js +114 -0
- package/dist/{index-7f68ghdn.js → index-8zja4pkf.js} +23 -1
- package/dist/index-tm88avnj.js +221 -0
- package/llms/application-directory-inbox.txt +9 -0
- package/llms/application.2.txt +7 -5
- package/llms/application.txt +88 -24
- package/llms/stitchkit.txt +4 -3
- package/llms/{upgrading-0.37.0-0.50.0.txt → upgrading-0.37.0-0.53.0.txt} +25 -3
- package/llms/{upgrading-0.53.0-0.67.0.txt → upgrading-0.55.0-0.68.0.txt} +53 -25
- package/llms/{upgrading-0.68.0-0.94.0.txt → upgrading-0.69.0-0.95.0.txt} +45 -53
- package/llms/upgrading.txt +3 -3
- package/llms-full.txt +141 -32
- package/llms.txt +6 -5
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,63 @@ additive**; the first breaking change landed in 0.10.0. Grep the file for
|
|
|
15
15
|
|
|
16
16
|
## [Unreleased]
|
|
17
17
|
|
|
18
|
+
## [0.95.1] — 2026-09-23
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `stitchkit/application/directory-inbox` (new, server, evolving) —
|
|
23
|
+
**`createDirectoryInbox({ id, directory, schema, handle })`**, with its
|
|
24
|
+
contract (`DirectoryInboxConfig`, `DirectoryInboxStateSchema`, …) in
|
|
25
|
+
`stitchkit/application`: a managed resource that delivers each `<name>.json` entry
|
|
26
|
+
another program drops into a directory to the application at least once,
|
|
27
|
+
after readiness. Taken and done are separate durable records — a claim with a
|
|
28
|
+
lease before `handle`, a receipt after it and only then the file removed — so
|
|
29
|
+
a restart neither loses an entry nor repeats a finished one. A throwing
|
|
30
|
+
handler is retried with a backoff; an entry that fails its schema, is too
|
|
31
|
+
large or used up `maxAttempts` is moved to `rejected/` with its reason and
|
|
32
|
+
the queue keeps flowing. `stopAdmission` stops taking entries, `force` aborts
|
|
33
|
+
the delivery in flight. A consuming project wrote this receiver by hand.
|
|
34
|
+
|
|
35
|
+
## [0.95.0] — 2026-09-23
|
|
36
|
+
|
|
37
|
+
### ⚠️ Breaking changes
|
|
38
|
+
|
|
39
|
+
**Who must act:** a project that reads `downtimeMs` from a lifecycle start fact,
|
|
40
|
+
switches exhaustively over `LifecycleTermination`, `PreviousExit` or
|
|
41
|
+
`ProcessLifecycleFact`, imports `TransitionReadyInput`, or drives
|
|
42
|
+
`createProcessLifecycleLedger` by hand without `recordReady`. A project that uses `lifecycleLedgerResource` and only
|
|
43
|
+
stores the ledger raises its version range; a ledger file written by an earlier
|
|
44
|
+
version loads unchanged.
|
|
45
|
+
|
|
46
|
+
- `stitchkit/application` — **the lifecycle ledger measures the window nobody
|
|
47
|
+
answered in.** `downtimeMs` was `startedAt` of the new process minus
|
|
48
|
+
`stoppedAt` of the old one, so a 110 s forced drain read as the same ~4 s
|
|
49
|
+
before and after it was fixed. A run now records `unavailableAt` when its
|
|
50
|
+
admission stops (`lifecycleLedgerResource` does it at `stopAdmission`; by
|
|
51
|
+
hand, `ledger.recordDraining()`) and passes an open `draining` phase.
|
|
52
|
+
`ReadyFact.downtimeMs` is `readyAt` of the new run minus `unavailableAt` of
|
|
53
|
+
the last run that served, with `unavailableSince` naming that moment; the old
|
|
54
|
+
number stays on `StartFact` as `processGapMs`. A run that stops before it was
|
|
55
|
+
ever ready ends `startup-failed` — recorded by itself on a rolled-back
|
|
56
|
+
startup, or by the successor that finds it open — and `PreviousExit` gains
|
|
57
|
+
the same value. A start closes every abandoned open run it finds, not only
|
|
58
|
+
the newest. New names: `DrainingFact`, `transitionProcessDraining`.
|
|
59
|
+
`TransitionReadyInput` is `TransitionRunInput`: one shape — which run, and
|
|
60
|
+
when — taken by readiness and draining alike, and extended by
|
|
61
|
+
`TransitionShutdownInput`; a second name for it would be an alias.
|
|
62
|
+
`// before: ledger.subscribe((fact) => fact.type === 'started' && report(fact.downtimeMs))` →
|
|
63
|
+
`// after: ledger.subscribe((fact) => fact.type === 'ready' && report(fact.downtimeMs))`
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
|
|
67
|
+
- `stitchkit/agent-runtime` — **a provider stream cut mid-answer is a
|
|
68
|
+
`provider_failure` on Bun 1.4 too.** Only a throw out of `doStream()` was
|
|
69
|
+
marked as the provider's; Bun 1.4 delivers a cut connection as a rejected
|
|
70
|
+
read of the stream `doStream()` already returned (`AI_APICallError: Failed to
|
|
71
|
+
process successful response`), and that unmarked error ended the run as
|
|
72
|
+
`runtime_failure`. Every failed read of the provider's stream is now marked;
|
|
73
|
+
the runtime's own failures while consuming it keep their classes.
|
|
74
|
+
|
|
18
75
|
## [0.94.1] — 2026-09-23
|
|
19
76
|
|
|
20
77
|
### Added
|
|
@@ -9,4 +9,11 @@ export declare function isOwnInputRefusal(error: unknown): boolean;
|
|
|
9
9
|
export declare function markProviderOrigin<T>(error: T): T;
|
|
10
10
|
/** Whether this error came out of the provider call itself. */
|
|
11
11
|
export declare function hasProviderOrigin(error: unknown): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* The provider's stream, with every failed read marked as the provider's.
|
|
14
|
+
*
|
|
15
|
+
* Only reads of this stream pass through here: the runtime's own work on the
|
|
16
|
+
* parts happens downstream, so its failures stay unmarked.
|
|
17
|
+
*/
|
|
18
|
+
export declare function markProviderStream<T>(stream: ReadableStream<T>): ReadableStream<T>;
|
|
12
19
|
//# sourceMappingURL=provider-origin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-origin.d.ts","sourceRoot":"","sources":["../../src/agent-runtime/provider-origin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"provider-origin.d.ts","sourceRoot":"","sources":["../../src/agent-runtime/provider-origin.ts"],"names":[],"mappings":"AAyBA;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMzD;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAGjD;AAED,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAkBlF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-operation-lifecycle.d.ts","sourceRoot":"","sources":["../../src/agent-runtime/run-operation-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAqB,MAAM,IAAI,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EACL,KAAK,QAAQ,EAGb,KAAK,aAAa,EACnB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAGjD,KAAK,sBAAsB,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEnE,MAAM,WAAW,gCAAgC;IAC/C,KAAK,EAAE,iBAAiB,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,IAAI,QAAQ,CAAC;IACvB,cAAc,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9C,OAAO,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,GAAG,IAAI,IAAI,CAAC;IACZ,oEAAoE;IACpE,SAAS,EAAE,gBAAgB,CAAC;CAC7B;AAED,uEAAuE;AACvE,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,gCAAgC;IAgDrF,gBAAgB,SAAS,MAAM,GAAG,IAAI;IAGhC,YAAY,QACT,aAAa,QACd,MAAM,kBACI,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"run-operation-lifecycle.d.ts","sourceRoot":"","sources":["../../src/agent-runtime/run-operation-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAqB,MAAM,IAAI,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EACL,KAAK,QAAQ,EAGb,KAAK,aAAa,EACnB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAGjD,KAAK,sBAAsB,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEnE,MAAM,WAAW,gCAAgC;IAC/C,KAAK,EAAE,iBAAiB,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,IAAI,QAAQ,CAAC;IACvB,cAAc,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9C,OAAO,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,GAAG,IAAI,IAAI,CAAC;IACZ,oEAAoE;IACpE,SAAS,EAAE,gBAAgB,CAAC;CAC7B;AAED,uEAAuE;AACvE,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,gCAAgC;IAgDrF,gBAAgB,SAAS,MAAM,GAAG,IAAI;IAGhC,YAAY,QACT,aAAa,QACd,MAAM,kBACI,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC;IAyCzB,cAAc,OAAO,MAAM,GAAG,IAAI;IAQlC,mBAAmB,QAAQ,OAAO,GAAG,IAAI;IAIzC,eAAe,cAAc,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUnD,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B,MAAM,QAAQ,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;EAavD"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ManagedResource, ManagedResourceDependency } from './resource.js';
|
|
3
|
+
import type { StateStore } from './state-store.js';
|
|
4
|
+
export declare const DirectoryInboxRejectionReasonSchema: z.ZodEnum<{
|
|
5
|
+
"attempt-limit": "attempt-limit";
|
|
6
|
+
invalid: "invalid";
|
|
7
|
+
"too-large": "too-large";
|
|
8
|
+
}>;
|
|
9
|
+
export type DirectoryInboxRejectionReason = z.infer<typeof DirectoryInboxRejectionReasonSchema>;
|
|
10
|
+
export declare const DirectoryInboxStateSchema: z.ZodObject<{
|
|
11
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
12
|
+
claims: z.ZodArray<z.ZodObject<{
|
|
13
|
+
key: z.ZodString;
|
|
14
|
+
attempts: z.ZodNumber;
|
|
15
|
+
nextAttemptAt: z.ZodString;
|
|
16
|
+
leaseId: z.ZodNullable<z.ZodString>;
|
|
17
|
+
leaseUntil: z.ZodNullable<z.ZodString>;
|
|
18
|
+
}, z.core.$strict>>;
|
|
19
|
+
receipts: z.ZodArray<z.ZodObject<{
|
|
20
|
+
key: z.ZodString;
|
|
21
|
+
completedAt: z.ZodString;
|
|
22
|
+
}, z.core.$strict>>;
|
|
23
|
+
rejected: z.ZodArray<z.ZodObject<{
|
|
24
|
+
key: z.ZodString;
|
|
25
|
+
reason: z.ZodEnum<{
|
|
26
|
+
"attempt-limit": "attempt-limit";
|
|
27
|
+
invalid: "invalid";
|
|
28
|
+
"too-large": "too-large";
|
|
29
|
+
}>;
|
|
30
|
+
detail: z.ZodString;
|
|
31
|
+
rejectedAt: z.ZodString;
|
|
32
|
+
}, z.core.$strict>>;
|
|
33
|
+
}, z.core.$strict>;
|
|
34
|
+
export type DirectoryInboxState = z.infer<typeof DirectoryInboxStateSchema>;
|
|
35
|
+
export type DirectoryInboxClaim = DirectoryInboxState['claims'][number];
|
|
36
|
+
export type DirectoryInboxRejection = DirectoryInboxState['rejected'][number];
|
|
37
|
+
export declare const emptyDirectoryInboxState: () => DirectoryInboxState;
|
|
38
|
+
/**
|
|
39
|
+
* A directory another program drops entries into, handed to the application
|
|
40
|
+
* at least once each. The producer writes each entry atomically as a
|
|
41
|
+
* `<name>.json` file (a temporary name, then a rename); names starting with a
|
|
42
|
+
* dot are never read, which is where the inbox keeps its own state.
|
|
43
|
+
*/
|
|
44
|
+
export interface DirectoryInboxDelivery<TEntry> {
|
|
45
|
+
/** The entry's file name — stable across retries and restarts. */
|
|
46
|
+
readonly key: string;
|
|
47
|
+
readonly entry: TEntry;
|
|
48
|
+
/** 1 on the first delivery of this entry. */
|
|
49
|
+
readonly attempt: number;
|
|
50
|
+
/** Aborted when the application is forced down mid-delivery. */
|
|
51
|
+
readonly signal: AbortSignal;
|
|
52
|
+
}
|
|
53
|
+
export interface DirectoryInboxConfig<TEntry> {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
readonly directory: string;
|
|
56
|
+
readonly schema: z.ZodType<TEntry>;
|
|
57
|
+
/** Throwing leaves the entry for a later attempt. */
|
|
58
|
+
readonly handle: (delivery: DirectoryInboxDelivery<TEntry>) => void | Promise<void>;
|
|
59
|
+
readonly dependsOn?: readonly ManagedResourceDependency[];
|
|
60
|
+
/** Default: `<directory>/.inbox-state.json`, locked across processes. */
|
|
61
|
+
readonly store?: StateStore<DirectoryInboxState>;
|
|
62
|
+
readonly clock?: () => Date;
|
|
63
|
+
/** How often the directory is read while the application runs. Default 1 s. */
|
|
64
|
+
readonly pollIntervalMs?: number;
|
|
65
|
+
/** How long a taken entry is someone's before it may be taken again. Default 5 min. */
|
|
66
|
+
readonly leaseMs?: number;
|
|
67
|
+
/** Deliveries of one entry before it is set aside. Default 20. */
|
|
68
|
+
readonly maxAttempts?: number;
|
|
69
|
+
/** Larger entries are set aside unread. Default 1 MiB. */
|
|
70
|
+
readonly maxEntryBytes?: number;
|
|
71
|
+
/** Receipts and rejections kept. Default 1 000. */
|
|
72
|
+
readonly retain?: number;
|
|
73
|
+
/** An entry was set aside into `<directory>/rejected/`, with the reason. */
|
|
74
|
+
readonly onRejected?: (rejection: DirectoryInboxRejection) => void | Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* A delivery failed (the entry is retried after a backoff) or a whole pass
|
|
77
|
+
* did (storage, the directory; the next poll tries again).
|
|
78
|
+
*/
|
|
79
|
+
readonly onError?: (error: unknown) => void | Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
export interface DirectoryInbox {
|
|
82
|
+
/** Deliver every entry due now; resolves with how many were handled. */
|
|
83
|
+
flush(): Promise<number>;
|
|
84
|
+
state(): Promise<DirectoryInboxState>;
|
|
85
|
+
}
|
|
86
|
+
export interface DirectoryInboxResource extends ManagedResource {
|
|
87
|
+
start(): Promise<{
|
|
88
|
+
readonly value: DirectoryInbox;
|
|
89
|
+
}>;
|
|
90
|
+
}
|
|
91
|
+
/** What the next step does with one entry of the directory. */
|
|
92
|
+
export type InboxStep = {
|
|
93
|
+
readonly kind: 'skip';
|
|
94
|
+
} | {
|
|
95
|
+
readonly kind: 'remove';
|
|
96
|
+
} | {
|
|
97
|
+
readonly kind: 'set-aside';
|
|
98
|
+
} | {
|
|
99
|
+
readonly kind: 'reject';
|
|
100
|
+
readonly rejection: DirectoryInboxRejection;
|
|
101
|
+
} | {
|
|
102
|
+
readonly kind: 'deliver';
|
|
103
|
+
readonly claim: DirectoryInboxClaim;
|
|
104
|
+
};
|
|
105
|
+
interface StepInput {
|
|
106
|
+
readonly key: string;
|
|
107
|
+
readonly now: Date;
|
|
108
|
+
readonly leaseMs: number;
|
|
109
|
+
readonly maxAttempts: number;
|
|
110
|
+
readonly retain: number;
|
|
111
|
+
}
|
|
112
|
+
export declare function withRejection(state: DirectoryInboxState, rejection: DirectoryInboxRejection, retain: number): DirectoryInboxState;
|
|
113
|
+
/**
|
|
114
|
+
* Decide one entry, and take it when it is due. A claim whose attempts are
|
|
115
|
+
* spent is not taken again: an entry whose handling kills the process would
|
|
116
|
+
* otherwise be retried on every restart, forever.
|
|
117
|
+
*/
|
|
118
|
+
export declare function claimEntry(state: DirectoryInboxState, input: StepInput): {
|
|
119
|
+
readonly state: DirectoryInboxState;
|
|
120
|
+
readonly step: InboxStep;
|
|
121
|
+
};
|
|
122
|
+
/** The entry was handled: its receipt replaces its claim. */
|
|
123
|
+
export declare function completeEntry(state: DirectoryInboxState, entryKey: string, now: Date, retain: number): DirectoryInboxState;
|
|
124
|
+
/** The handler refused: wait, then take it again — unless it is no longer ours. */
|
|
125
|
+
export declare function releaseEntry(state: DirectoryInboxState, claim: DirectoryInboxClaim, retryAt: Date): DirectoryInboxState;
|
|
126
|
+
/** Records about entries that are gone from the directory, except a live lease. */
|
|
127
|
+
export declare function forgetMissing(state: DirectoryInboxState, present: ReadonlySet<string>, now: Date): DirectoryInboxState;
|
|
128
|
+
export {};
|
|
129
|
+
//# sourceMappingURL=directory-inbox-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-inbox-contract.d.ts","sourceRoot":"","sources":["../../src/application/directory-inbox-contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-inbox.d.ts","sourceRoot":"","sources":["../../src/application/directory-inbox.ts"],"names":[],"mappings":"AAIA,OAAO,EAKL,KAAK,oBAAoB,EAEzB,KAAK,sBAAsB,EAO5B,MAAM,4BAA4B,CAAC;AAyEpC,wBAAgB,oBAAoB,CAAC,MAAM,EACzC,MAAM,EAAE,oBAAoB,CAAC,MAAM,CAAC,GACnC,sBAAsB,CAiKxB"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Where a run is. `active` and `draining` are open: the run is alive, and
|
|
4
|
+
* `draining` means it has stopped admitting work — from `unavailableAt` on
|
|
5
|
+
* nobody new is answered. The rest are how it ended. `clean`, `forced` and
|
|
6
|
+
* `startup-failed` are recorded by the run itself; `hot-reload` and `abnormal`
|
|
7
|
+
* by its successor, because the run never got to say — the same pid started
|
|
8
|
+
* again, or a different pid found it still open. `abnormal` is a crash
|
|
9
|
+
* observed from outside, not a kill the process acknowledged, so the two stay
|
|
10
|
+
* distinct. `startup-failed` is a run that ended before it was ever ready,
|
|
11
|
+
* whether it said so itself or a successor found it open.
|
|
12
|
+
*/
|
|
13
|
+
export declare const LifecycleTerminationSchema: z.ZodEnum<{
|
|
14
|
+
abnormal: "abnormal";
|
|
15
|
+
active: "active";
|
|
16
|
+
clean: "clean";
|
|
17
|
+
draining: "draining";
|
|
18
|
+
forced: "forced";
|
|
19
|
+
"hot-reload": "hot-reload";
|
|
20
|
+
"startup-failed": "startup-failed";
|
|
21
|
+
}>;
|
|
22
|
+
export type LifecycleTermination = z.infer<typeof LifecycleTerminationSchema>;
|
|
23
|
+
export declare const LifecycleRunSchema: z.ZodObject<{
|
|
24
|
+
runId: z.ZodString;
|
|
25
|
+
pid: z.ZodNumber;
|
|
26
|
+
version: z.ZodString;
|
|
27
|
+
startedAt: z.ZodString;
|
|
28
|
+
readyAt: z.ZodNullable<z.ZodString>;
|
|
29
|
+
unavailableAt: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
30
|
+
stoppedAt: z.ZodNullable<z.ZodString>;
|
|
31
|
+
termination: z.ZodEnum<{
|
|
32
|
+
abnormal: "abnormal";
|
|
33
|
+
active: "active";
|
|
34
|
+
clean: "clean";
|
|
35
|
+
draining: "draining";
|
|
36
|
+
forced: "forced";
|
|
37
|
+
"hot-reload": "hot-reload";
|
|
38
|
+
"startup-failed": "startup-failed";
|
|
39
|
+
}>;
|
|
40
|
+
}, z.core.$strict>;
|
|
41
|
+
export type LifecycleRun = z.infer<typeof LifecycleRunSchema>;
|
|
42
|
+
export declare const LifecycleStateSchema: z.ZodObject<{
|
|
43
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
44
|
+
runs: z.ZodArray<z.ZodObject<{
|
|
45
|
+
runId: z.ZodString;
|
|
46
|
+
pid: z.ZodNumber;
|
|
47
|
+
version: z.ZodString;
|
|
48
|
+
startedAt: z.ZodString;
|
|
49
|
+
readyAt: z.ZodNullable<z.ZodString>;
|
|
50
|
+
unavailableAt: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
51
|
+
stoppedAt: z.ZodNullable<z.ZodString>;
|
|
52
|
+
termination: z.ZodEnum<{
|
|
53
|
+
abnormal: "abnormal";
|
|
54
|
+
active: "active";
|
|
55
|
+
clean: "clean";
|
|
56
|
+
draining: "draining";
|
|
57
|
+
forced: "forced";
|
|
58
|
+
"hot-reload": "hot-reload";
|
|
59
|
+
"startup-failed": "startup-failed";
|
|
60
|
+
}>;
|
|
61
|
+
}, z.core.$strict>>;
|
|
62
|
+
}, z.core.$strict>;
|
|
63
|
+
export type LifecycleState = z.infer<typeof LifecycleStateSchema>;
|
|
64
|
+
export declare const PreviousExitSchema: z.ZodEnum<{
|
|
65
|
+
abnormal: "abnormal";
|
|
66
|
+
clean: "clean";
|
|
67
|
+
"first-boot": "first-boot";
|
|
68
|
+
forced: "forced";
|
|
69
|
+
handoff: "handoff";
|
|
70
|
+
"hot-reload": "hot-reload";
|
|
71
|
+
"startup-failed": "startup-failed";
|
|
72
|
+
}>;
|
|
73
|
+
export type PreviousExit = z.infer<typeof PreviousExitSchema>;
|
|
74
|
+
export interface StartFact {
|
|
75
|
+
readonly type: 'started';
|
|
76
|
+
readonly runId: string;
|
|
77
|
+
readonly pid: number;
|
|
78
|
+
readonly version: string;
|
|
79
|
+
readonly startedAt: string;
|
|
80
|
+
readonly previousExit: PreviousExit;
|
|
81
|
+
readonly previousRunId: string | null;
|
|
82
|
+
readonly previousPid: number | null;
|
|
83
|
+
readonly previousVersion: string | null;
|
|
84
|
+
readonly versionChanged: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* From the predecessor's recorded stop to this start: the gap between two
|
|
87
|
+
* processes, not the time nobody answered — that is `ReadyFact.downtimeMs`.
|
|
88
|
+
*/
|
|
89
|
+
readonly processGapMs: number | null;
|
|
90
|
+
}
|
|
91
|
+
export interface ReadyFact {
|
|
92
|
+
readonly type: 'ready';
|
|
93
|
+
readonly runId: string;
|
|
94
|
+
readonly pid: number;
|
|
95
|
+
readonly readyAt: string;
|
|
96
|
+
readonly startupMs: number;
|
|
97
|
+
/**
|
|
98
|
+
* The window in which nobody answered: from the moment the last run that
|
|
99
|
+
* served stopped admitting work to this run's readiness — its drain plus
|
|
100
|
+
* this start. Zero when that run still answers (a handoff); null on first
|
|
101
|
+
* boot and when its end was never timed (a crash, a hot reload).
|
|
102
|
+
*/
|
|
103
|
+
readonly downtimeMs: number | null;
|
|
104
|
+
/** The moment `downtimeMs` is counted from, when it is known. */
|
|
105
|
+
readonly unavailableSince: string | null;
|
|
106
|
+
/** False when this exact ready transition was already recorded. */
|
|
107
|
+
readonly recorded: boolean;
|
|
108
|
+
}
|
|
109
|
+
export interface DrainingFact {
|
|
110
|
+
readonly type: 'draining';
|
|
111
|
+
readonly runId: string;
|
|
112
|
+
readonly pid: number;
|
|
113
|
+
/** Null for a run that never became ready: it was never available. */
|
|
114
|
+
readonly unavailableAt: string | null;
|
|
115
|
+
readonly recorded: boolean;
|
|
116
|
+
}
|
|
117
|
+
export interface ShutdownFact {
|
|
118
|
+
readonly type: 'stopped';
|
|
119
|
+
readonly runId: string;
|
|
120
|
+
readonly pid: number;
|
|
121
|
+
readonly stoppedAt: string;
|
|
122
|
+
readonly uptimeMs: number | null;
|
|
123
|
+
readonly termination: 'clean' | 'forced' | 'startup-failed';
|
|
124
|
+
readonly recorded: boolean;
|
|
125
|
+
}
|
|
126
|
+
export type ProcessLifecycleFact = StartFact | ReadyFact | DrainingFact | ShutdownFact;
|
|
127
|
+
export interface LifecycleTransition<TFact extends ProcessLifecycleFact> {
|
|
128
|
+
readonly state: LifecycleState;
|
|
129
|
+
readonly fact: TFact;
|
|
130
|
+
}
|
|
131
|
+
export declare const isOpenRun: (run: LifecycleRun) => boolean;
|
|
132
|
+
/**
|
|
133
|
+
* The list is newest-first in the order the transitions wrote it — every write
|
|
134
|
+
* goes through one atomic update, so that order is the causal one. Clocks are
|
|
135
|
+
* not: a successor whose clock lags its predecessor must still find that
|
|
136
|
+
* predecessor at the head, so the list is never re-sorted by `startedAt`.
|
|
137
|
+
* Retention drops finished runs first; an open run — a live handoff
|
|
138
|
+
* predecessor — is dropped only when nothing finished is left to drop.
|
|
139
|
+
*/
|
|
140
|
+
export declare function normalizeLifecycleState(state: LifecycleState | null, retain: number): LifecycleState;
|
|
141
|
+
/**
|
|
142
|
+
* What a start means when the newest run is still open under another pid
|
|
143
|
+
* **and the same version**. `abnormal` (default): the predecessor crashed
|
|
144
|
+
* without recording its exit — one process per deployment, a restart after a
|
|
145
|
+
* kill. `handoff`: processes of one build overlap on purpose (a cluster, a
|
|
146
|
+
* zero-downtime reload of the same build), so every open run stays open and
|
|
147
|
+
* records its own shutdown later. A different version is always a handoff; a
|
|
148
|
+
* version of `unknown` on either side is never a version change.
|
|
149
|
+
*/
|
|
150
|
+
export type SameVersionOverlap = 'abnormal' | 'handoff';
|
|
151
|
+
export interface TransitionStartInput {
|
|
152
|
+
readonly runId: string;
|
|
153
|
+
readonly pid: number;
|
|
154
|
+
readonly version: string;
|
|
155
|
+
readonly now: string;
|
|
156
|
+
readonly retain?: number;
|
|
157
|
+
readonly sameVersionOverlap?: SameVersionOverlap;
|
|
158
|
+
}
|
|
159
|
+
/** Apply one process start without touching persistence or application events. */
|
|
160
|
+
export declare function transitionProcessStart(source: LifecycleState | null, input: TransitionStartInput): LifecycleTransition<StartFact>;
|
|
161
|
+
/** The run a transition applies to — owned by run id plus pid — and when. */
|
|
162
|
+
export interface TransitionRunInput {
|
|
163
|
+
readonly runId: string;
|
|
164
|
+
readonly pid: number;
|
|
165
|
+
readonly now: string;
|
|
166
|
+
readonly retain?: number;
|
|
167
|
+
}
|
|
168
|
+
export declare function transitionProcessReady(source: LifecycleState | null, input: TransitionRunInput): LifecycleTransition<ReadyFact>;
|
|
169
|
+
/** The run stopped admitting work: from here on it answers nobody new. */
|
|
170
|
+
export declare function transitionProcessDraining(source: LifecycleState | null, input: TransitionRunInput): LifecycleTransition<DrainingFact>;
|
|
171
|
+
export interface TransitionShutdownInput extends TransitionRunInput {
|
|
172
|
+
readonly forced?: boolean;
|
|
173
|
+
}
|
|
174
|
+
export declare function transitionProcessShutdown(source: LifecycleState | null, input: TransitionShutdownInput): LifecycleTransition<ShutdownFact>;
|
|
175
|
+
//# sourceMappingURL=process-lifecycle-transitions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-lifecycle-transitions.d.ts","sourceRoot":"","sources":["../../src/application/process-lifecycle-transitions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,141 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type DrainingFact, type LifecycleRun, type LifecycleState, type ProcessLifecycleFact, type ReadyFact, type SameVersionOverlap, type ShutdownFact, type StartFact } from './process-lifecycle-transitions.js';
|
|
2
2
|
import { type ManagedResource } from './resource.js';
|
|
3
3
|
import type { StateStore } from './state-store.js';
|
|
4
|
-
/**
|
|
5
|
-
* How a run ended. `clean` and `forced` are recorded by the run itself;
|
|
6
|
-
* `hot-reload` and `abnormal` are recorded by its successor, because the run
|
|
7
|
-
* never got to say — the same pid started again, or a different pid found it
|
|
8
|
-
* still marked active. `abnormal` is a crash observed from outside, not a kill
|
|
9
|
-
* the process acknowledged, so the two stay distinct in the ledger.
|
|
10
|
-
*/
|
|
11
|
-
export declare const LifecycleTerminationSchema: z.ZodEnum<{
|
|
12
|
-
abnormal: "abnormal";
|
|
13
|
-
active: "active";
|
|
14
|
-
clean: "clean";
|
|
15
|
-
forced: "forced";
|
|
16
|
-
"hot-reload": "hot-reload";
|
|
17
|
-
}>;
|
|
18
|
-
export type LifecycleTermination = z.infer<typeof LifecycleTerminationSchema>;
|
|
19
|
-
export declare const LifecycleRunSchema: z.ZodObject<{
|
|
20
|
-
runId: z.ZodString;
|
|
21
|
-
pid: z.ZodNumber;
|
|
22
|
-
version: z.ZodString;
|
|
23
|
-
startedAt: z.ZodString;
|
|
24
|
-
readyAt: z.ZodNullable<z.ZodString>;
|
|
25
|
-
stoppedAt: z.ZodNullable<z.ZodString>;
|
|
26
|
-
termination: z.ZodEnum<{
|
|
27
|
-
abnormal: "abnormal";
|
|
28
|
-
active: "active";
|
|
29
|
-
clean: "clean";
|
|
30
|
-
forced: "forced";
|
|
31
|
-
"hot-reload": "hot-reload";
|
|
32
|
-
}>;
|
|
33
|
-
}, z.core.$strict>;
|
|
34
|
-
export type LifecycleRun = z.infer<typeof LifecycleRunSchema>;
|
|
35
|
-
export declare const LifecycleStateSchema: z.ZodObject<{
|
|
36
|
-
schemaVersion: z.ZodLiteral<1>;
|
|
37
|
-
runs: z.ZodArray<z.ZodObject<{
|
|
38
|
-
runId: z.ZodString;
|
|
39
|
-
pid: z.ZodNumber;
|
|
40
|
-
version: z.ZodString;
|
|
41
|
-
startedAt: z.ZodString;
|
|
42
|
-
readyAt: z.ZodNullable<z.ZodString>;
|
|
43
|
-
stoppedAt: z.ZodNullable<z.ZodString>;
|
|
44
|
-
termination: z.ZodEnum<{
|
|
45
|
-
abnormal: "abnormal";
|
|
46
|
-
active: "active";
|
|
47
|
-
clean: "clean";
|
|
48
|
-
forced: "forced";
|
|
49
|
-
"hot-reload": "hot-reload";
|
|
50
|
-
}>;
|
|
51
|
-
}, z.core.$strict>>;
|
|
52
|
-
}, z.core.$strict>;
|
|
53
|
-
export type LifecycleState = z.infer<typeof LifecycleStateSchema>;
|
|
54
|
-
export declare const PreviousExitSchema: z.ZodEnum<{
|
|
55
|
-
abnormal: "abnormal";
|
|
56
|
-
clean: "clean";
|
|
57
|
-
"first-boot": "first-boot";
|
|
58
|
-
forced: "forced";
|
|
59
|
-
handoff: "handoff";
|
|
60
|
-
"hot-reload": "hot-reload";
|
|
61
|
-
}>;
|
|
62
|
-
export type PreviousExit = z.infer<typeof PreviousExitSchema>;
|
|
63
|
-
export interface StartFact {
|
|
64
|
-
readonly type: 'started';
|
|
65
|
-
readonly runId: string;
|
|
66
|
-
readonly pid: number;
|
|
67
|
-
readonly version: string;
|
|
68
|
-
readonly startedAt: string;
|
|
69
|
-
readonly previousExit: PreviousExit;
|
|
70
|
-
readonly previousRunId: string | null;
|
|
71
|
-
readonly previousPid: number | null;
|
|
72
|
-
readonly previousVersion: string | null;
|
|
73
|
-
readonly versionChanged: boolean;
|
|
74
|
-
readonly downtimeMs: number | null;
|
|
75
|
-
}
|
|
76
|
-
export interface ReadyFact {
|
|
77
|
-
readonly type: 'ready';
|
|
78
|
-
readonly runId: string;
|
|
79
|
-
readonly pid: number;
|
|
80
|
-
readonly readyAt: string;
|
|
81
|
-
readonly startupMs: number;
|
|
82
|
-
/** False when this exact ready transition was already recorded. */
|
|
83
|
-
readonly recorded: boolean;
|
|
84
|
-
}
|
|
85
|
-
export interface ShutdownFact {
|
|
86
|
-
readonly type: 'stopped';
|
|
87
|
-
readonly runId: string;
|
|
88
|
-
readonly pid: number;
|
|
89
|
-
readonly stoppedAt: string;
|
|
90
|
-
readonly uptimeMs: number | null;
|
|
91
|
-
readonly termination: 'clean' | 'forced';
|
|
92
|
-
readonly recorded: boolean;
|
|
93
|
-
}
|
|
94
|
-
export type ProcessLifecycleFact = StartFact | ReadyFact | ShutdownFact;
|
|
95
|
-
export interface LifecycleTransition<TFact extends ProcessLifecycleFact> {
|
|
96
|
-
readonly state: LifecycleState;
|
|
97
|
-
readonly fact: TFact;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* What a start means when the newest run is still marked active under another
|
|
101
|
-
* pid **and the same version**. `abnormal` (default): the predecessor crashed
|
|
102
|
-
* without recording its exit — one process per deployment, a restart after a
|
|
103
|
-
* kill. `handoff`: two processes of one build overlap on purpose (a cluster, a
|
|
104
|
-
* zero-downtime reload of the same build), so the predecessor stays active and
|
|
105
|
-
* records its own shutdown later. A different version is always a handoff; a
|
|
106
|
-
* version of `unknown` on either side is never a version change.
|
|
107
|
-
*/
|
|
108
|
-
export type SameVersionOverlap = 'abnormal' | 'handoff';
|
|
109
|
-
export interface TransitionStartInput {
|
|
110
|
-
readonly runId: string;
|
|
111
|
-
readonly pid: number;
|
|
112
|
-
readonly version: string;
|
|
113
|
-
readonly now: string;
|
|
114
|
-
readonly retain?: number;
|
|
115
|
-
readonly sameVersionOverlap?: SameVersionOverlap;
|
|
116
|
-
}
|
|
117
|
-
/** Apply one process start without touching persistence or application events. */
|
|
118
|
-
export declare function transitionProcessStart(source: LifecycleState | null, input: TransitionStartInput): LifecycleTransition<StartFact>;
|
|
119
|
-
export interface TransitionReadyInput {
|
|
120
|
-
readonly runId: string;
|
|
121
|
-
readonly pid: number;
|
|
122
|
-
readonly now: string;
|
|
123
|
-
readonly retain?: number;
|
|
124
|
-
}
|
|
125
|
-
export declare function transitionProcessReady(source: LifecycleState | null, input: TransitionReadyInput): LifecycleTransition<ReadyFact>;
|
|
126
|
-
export interface TransitionShutdownInput {
|
|
127
|
-
readonly runId: string;
|
|
128
|
-
readonly pid: number;
|
|
129
|
-
readonly now: string;
|
|
130
|
-
readonly forced?: boolean;
|
|
131
|
-
readonly retain?: number;
|
|
132
|
-
}
|
|
133
|
-
export declare function transitionProcessShutdown(source: LifecycleState | null, input: TransitionShutdownInput): LifecycleTransition<ShutdownFact>;
|
|
134
4
|
export interface ProcessLifecycleLedger {
|
|
135
5
|
recordStart(input: {
|
|
136
6
|
readonly version: string;
|
|
137
7
|
}): Promise<StartFact>;
|
|
138
8
|
recordReady(): Promise<ReadyFact>;
|
|
9
|
+
/** The run stopped admitting work; its `unavailableAt` is now. */
|
|
10
|
+
recordDraining(): Promise<DrainingFact>;
|
|
139
11
|
recordShutdown(input?: {
|
|
140
12
|
readonly forced?: boolean;
|
|
141
13
|
}): Promise<ShutdownFact>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-lifecycle.d.ts","sourceRoot":"","sources":["../../src/application/process-lifecycle.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"process-lifecycle.d.ts","sourceRoot":"","sources":["../../src/application/process-lifecycle.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,cAAc,EAEnB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,SAAS,EAKf,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACrE,WAAW,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAClC,kEAAkE;IAClE,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IACxC,cAAc,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7E,OAAO,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IACxC,IAAI,IAAI,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CAAC;IACzC,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC;CACvF;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACjD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAC3B,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,oBAAoB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,4BAA4B,GACnC,sBAAsB,CAsGxB;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,KAAK,IAAI,OAAO,CAAC;QAAE,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAA;KAAE,CAAC,CAAC;CAC9D;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,sBAAsB,EAC9B,MAAM,EAAE,6BAA6B,GACpC,uBAAuB,CAsCzB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The directory inbox — delivers each entry another program drops into a
|
|
3
|
+
* directory to the application at least once.
|
|
4
|
+
*
|
|
5
|
+
* Its own entrypoint because it reads, renames and removes files (`node:fs`),
|
|
6
|
+
* and `stitchkit/application` must stay importable in a browser. Its contract —
|
|
7
|
+
* the configuration, the delivery, the state and rejection schemas — stays in
|
|
8
|
+
* `stitchkit/application`, as the diagnostic journal's does. → ADR 0156.
|
|
9
|
+
*/
|
|
10
|
+
export { createDirectoryInbox } from '../../application/directory-inbox.js';
|
|
11
|
+
//# sourceMappingURL=directory-inbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-inbox.d.ts","sourceRoot":"","sources":["../../../src/entrypoints/application/directory-inbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC"}
|