@orkestrel/scaffold 0.0.67 → 0.0.69
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/dist/bin/main.js +67 -44
- package/dist/bin/main.js.map +1 -1
- package/dist/host/agents/templates/brief.md +9 -0
- package/dist/host/claude/agents/orkestrel.md +4 -4
- package/dist/host/claude/rules/names.md +15 -0
- package/dist/host/claude/rules/tests.md +33 -4
- package/dist/host/claude/rules/workspace.md +14 -2
- package/dist/host/dotfiles/prettierignore +3 -0
- package/dist/host/guides/README.md +65 -0
- package/dist/host/guides/abort.md +169 -0
- package/dist/host/guides/agent.md +1567 -0
- package/dist/host/guides/brief.md +1266 -0
- package/dist/host/guides/browser.md +2200 -0
- package/dist/host/guides/budget.md +196 -0
- package/dist/host/guides/codec.md +519 -0
- package/dist/host/guides/console.md +785 -0
- package/dist/host/guides/contract.md +1193 -0
- package/dist/host/guides/csv.md +541 -0
- package/dist/host/guides/database.md +2518 -0
- package/dist/host/guides/emitter.md +233 -0
- package/dist/host/guides/form.md +1791 -0
- package/dist/host/guides/html.md +717 -0
- package/dist/host/guides/indexeddb.md +505 -0
- package/dist/host/guides/interpret.md +1029 -0
- package/dist/host/guides/lsp.md +515 -0
- package/dist/host/guides/markdown.md +964 -0
- package/dist/host/guides/mcp.md +5554 -0
- package/dist/host/guides/middleware.md +927 -0
- package/dist/host/guides/msg.md +440 -0
- package/dist/host/guides/ndjson.md +120 -0
- package/dist/host/guides/ollama.md +380 -0
- package/dist/host/guides/pool.md +280 -0
- package/dist/host/guides/probe.md +1210 -0
- package/dist/host/guides/process.md +1620 -0
- package/dist/host/guides/program.md +1110 -0
- package/dist/host/guides/qualifier.md +854 -0
- package/dist/host/guides/queue.md +370 -0
- package/dist/host/guides/rater.md +330 -0
- package/dist/host/guides/reason.md +1122 -0
- package/dist/host/guides/relation.md +373 -0
- package/dist/host/guides/router.md +753 -0
- package/dist/host/guides/scaffold.md +192 -31
- package/dist/host/guides/sea.md +383 -0
- package/dist/host/guides/server.md +752 -0
- package/dist/host/guides/sqlite.md +330 -0
- package/dist/host/guides/sse.md +187 -0
- package/dist/host/guides/supervisor.md +4890 -0
- package/dist/host/guides/table.md +1556 -0
- package/dist/host/guides/template.md +280 -0
- package/dist/host/guides/terminal.md +1145 -0
- package/dist/host/guides/test.md +2969 -0
- package/dist/host/guides/timeout.md +252 -0
- package/dist/host/guides/tool.md +507 -0
- package/dist/host/guides/toolbox.md +1038 -0
- package/dist/host/guides/websocket.md +282 -0
- package/dist/host/guides/worker.md +615 -0
- package/dist/host/guides/workflow.md +1507 -0
- package/dist/host/guides/workspace.md +595 -0
- package/dist/host/manifest.json +1218 -10
- package/dist/host/tests/policy.test.ts +279 -2
- package/dist/host/tests/setupPolicy.ts +445 -6
- package/dist/src/core/index.cjs +38 -16
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +33 -9
- package/dist/src/core/index.d.ts +33 -9
- package/dist/src/core/index.js +37 -17
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +1750 -1567
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +106 -24
- package/dist/src/server/index.d.ts +106 -24
- package/dist/src/server/index.js +1751 -1570
- package/dist/src/server/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Timeout
|
|
2
|
+
|
|
3
|
+
> The time-bound half of the substrate's time-and-cancellation pair: a
|
|
4
|
+
> controllable `setTimeout` wrapper carrying a trace `id` and a deadline `ms`,
|
|
5
|
+
> whose native `AbortSignal` aborts on expiry.
|
|
6
|
+
|
|
7
|
+
Arm the deadline with `start()`, then race its `signal` against work to bound
|
|
8
|
+
how long that work may run; `clear()` cancels the deadline without firing it,
|
|
9
|
+
and a `start()` after an expiry swaps in a fresh signal, so one handle serves a
|
|
10
|
+
sequence of deadlines without re-construction. The package is deliberately
|
|
11
|
+
thin: not a scheduler, not a debounce, not a retry policy — one `setTimeout`
|
|
12
|
+
made re-armable, clearable, and parent-linkable. The native signal is the
|
|
13
|
+
complete observation surface, so there is no separate event map. Source:
|
|
14
|
+
[`src/core`](../src/core). Surfaced through the `@src/core` barrel.
|
|
15
|
+
|
|
16
|
+
## Surface
|
|
17
|
+
|
|
18
|
+
Create a deadline handle, arm it, and hand its `signal` to deadline-aware
|
|
19
|
+
work — call `clear()` on the deadline if the work finishes first:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { createTimeout } from '@orkestrel/timeout'
|
|
23
|
+
|
|
24
|
+
const timeout = createTimeout({ ms: 5_000 })
|
|
25
|
+
timeout.start()
|
|
26
|
+
|
|
27
|
+
// `signal` aborts on expiry — pass it anywhere a native AbortSignal is accepted:
|
|
28
|
+
const response = await fetch(url, { signal: timeout.signal })
|
|
29
|
+
|
|
30
|
+
timeout.clear() // work finished first — cancel the deadline
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Construction is a strict JavaScript boundary. Options must be a plain readable
|
|
34
|
+
record; a defined `id` must be a string; `ms` must be an integer in the
|
|
35
|
+
inclusive range from `0` through `MAX_TIMEOUT_MS`; and a defined parent
|
|
36
|
+
`signal` must be a genuine native `AbortSignal`. Invalid input throws
|
|
37
|
+
`ContractError` from `@orkestrel/contract`: malformed or unreadable options use
|
|
38
|
+
code `bound`, while invalid `id`, `ms`, and `signal` values use `literal`,
|
|
39
|
+
`range`, and `placement`, respectively. Each error carries safe `path`, `limit`,
|
|
40
|
+
and `received` context. The package does not re-export `ContractError`.
|
|
41
|
+
|
|
42
|
+
An optional parent signal clears the timeout rather than expiring it if it
|
|
43
|
+
aborts before the deadline. An optional `id` labels the handle for tracing and
|
|
44
|
+
defaults to a random UUID.
|
|
45
|
+
|
|
46
|
+
### Factories
|
|
47
|
+
|
|
48
|
+
| API | Kind | Summary |
|
|
49
|
+
| --------------- | -------- | ------------------------------------------------------------------------------------------------- |
|
|
50
|
+
| `createTimeout` | function | Creates a deadline handle from validated `TimeoutOptions` and returns it as a `TimeoutInterface`. |
|
|
51
|
+
|
|
52
|
+
### Classes
|
|
53
|
+
|
|
54
|
+
| API | Kind | Summary |
|
|
55
|
+
| --------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
56
|
+
| `Timeout` | class | Implements `TimeoutInterface` exactly, as a controllable `setTimeout` wrapper over one owned `AbortController` whose signal aborts when the deadline expires. |
|
|
57
|
+
|
|
58
|
+
### Constants
|
|
59
|
+
|
|
60
|
+
A `Shape` cell holds the constant's declared type.
|
|
61
|
+
|
|
62
|
+
| API | Kind | Shape | Summary |
|
|
63
|
+
| ---------------- | ----- | -------- | ------------------------------------------------------------------------------------- |
|
|
64
|
+
| `MAX_TIMEOUT_MS` | const | `number` | Names the largest timeout duration the package accepts, `2_147_483_647` milliseconds. |
|
|
65
|
+
|
|
66
|
+
### Validators
|
|
67
|
+
|
|
68
|
+
In a guard table a `Shape` cell holds the type the guard narrows to.
|
|
69
|
+
|
|
70
|
+
| API | Kind | Shape | Summary |
|
|
71
|
+
| ------------------- | -------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
72
|
+
| `isTimeoutDuration` | function | `number` | Determines whether a value is an integer in the inclusive range from `0` through `MAX_TIMEOUT_MS`, staying total for every input. |
|
|
73
|
+
| `isTimeoutSignal` | function | `AbortSignal` | Determines whether a value is a genuine native `AbortSignal`, staying total for a structural spoof and for a hostile or revoked proxy. |
|
|
74
|
+
|
|
75
|
+
### Helpers
|
|
76
|
+
|
|
77
|
+
| API | Kind | Summary |
|
|
78
|
+
| ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
79
|
+
| `validateTimeoutOptions` | function | Validates once-read timeout construction options and returns a fresh normalized copy omitting absent optional keys. |
|
|
80
|
+
|
|
81
|
+
### Types
|
|
82
|
+
|
|
83
|
+
A `Shape` cell holds an interface's data members as bare names in braces, `?` marking an optional member and `plus` introducing its call-signature members, and a type alias's own type literal with a union's arms escaped as `\|`.
|
|
84
|
+
|
|
85
|
+
| Type | Kind | Shape | Summary |
|
|
86
|
+
| ------------------ | --------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
87
|
+
| `TimeoutOptions` | interface | `{ id?, ms, signal? }` | Represents the options `createTimeout` and the `Timeout` constructor accept. |
|
|
88
|
+
| `TimeoutInterface` | interface | `{ id, ms, signal, expired } plus start, clear` | Represents a controllable deadline exposing a native `AbortSignal` that aborts on expiry. |
|
|
89
|
+
|
|
90
|
+
The `id`, `ms`, `signal`, and `expired` members of `TimeoutInterface` are
|
|
91
|
+
`readonly` data members (Shape cell, earlier) — its call-signature methods are
|
|
92
|
+
documented under [Methods](#methods). `expired` derives directly from the
|
|
93
|
+
owned signal's `aborted` state rather than storing a duplicate lifecycle flag.
|
|
94
|
+
|
|
95
|
+
## Methods
|
|
96
|
+
|
|
97
|
+
The public methods of `TimeoutInterface` — every call-signature member listed
|
|
98
|
+
(its `readonly` members `id` / `ms` / `signal` / `expired` have no method row).
|
|
99
|
+
`Timeout` implements the interface exactly, so this doubles as the class's
|
|
100
|
+
instance-method surface (AGENTS.md, Documentation contract).
|
|
101
|
+
|
|
102
|
+
#### `TimeoutInterface`
|
|
103
|
+
|
|
104
|
+
The call-signature members, each with the type it returns:
|
|
105
|
+
|
|
106
|
+
| Method | Returns | Summary |
|
|
107
|
+
| ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
108
|
+
| `start` | `void` | Arms or re-arms the deadline for `ms`, installing a fresh `signal` when the current one has already aborted. |
|
|
109
|
+
| `clear` | `void` | Cancels an armed deadline without aborting its `signal`, and resets expiry by installing a fresh signal when the current one has already aborted. |
|
|
110
|
+
|
|
111
|
+
## Contract
|
|
112
|
+
|
|
113
|
+
These invariants hold across `src/core` ↔ `timeout.md`:
|
|
114
|
+
|
|
115
|
+
1. **DOC ↔ SOURCE bijection.** Every `function` / `class` / `const` /
|
|
116
|
+
`interface` row in the `## Surface` tables is a real export of the timeout
|
|
117
|
+
source, and every export appears as a Surface row — exhaustive, both
|
|
118
|
+
directions (AGENTS.md, Documentation contract).
|
|
119
|
+
2. **Strict construction boundary.** `validateTimeoutOptions` requires a plain
|
|
120
|
+
readable record, reads `id`, `ms`, and `signal` exactly once inside a
|
|
121
|
+
contained boundary, validates them, and returns a fresh normalized copy that
|
|
122
|
+
omits absent optional keys. Defined identifiers must be strings, durations
|
|
123
|
+
must be integers in inclusive `[0, MAX_TIMEOUT_MS]`, and defined parent
|
|
124
|
+
signals must pass the native brand check. `Timeout` calls this helper before
|
|
125
|
+
allocating its controller or listener. Negative zero and zero are valid;
|
|
126
|
+
zero intentionally expires on the next turn. Invalid inputs throw the coded
|
|
127
|
+
`ContractError` taxonomy described under Surface.
|
|
128
|
+
3. **Deadline signal and derived expiry.** The exposed `signal` fires (aborts)
|
|
129
|
+
on expiry. `expired` derives from that owned signal's `aborted` state, so
|
|
130
|
+
`expired` and `aborted` cannot drift apart.
|
|
131
|
+
4. **Signal identity swaps only on a real expiry.** A cleared-but-never-fired
|
|
132
|
+
timeout keeps its original `signal` (not aborted); the identity is only
|
|
133
|
+
swapped for a fresh, non-aborted controller after the current controller has
|
|
134
|
+
fired — whether that swap happens inside `clear()` or at the next `start()`.
|
|
135
|
+
5. **Parent linking clears, never expires.** A parent `options.signal` abort
|
|
136
|
+
clears the timeout — it does not expire the timeout, abort the timeout's own
|
|
137
|
+
signal, or forward the parent reason. The parent listener is attached only
|
|
138
|
+
while a timer is armed (added on `start()`, removed on expiry or `clear()`);
|
|
139
|
+
once the parent has aborted, a later `start()` is a no-op.
|
|
140
|
+
6. **Identifiers are strict.** Omitted `id` values generate a random UUID and an
|
|
141
|
+
empty string is retained, but every other defined non-string value throws a
|
|
142
|
+
`literal`-coded `ContractError` rather than being coerced or replaced.
|
|
143
|
+
7. **Native observation.** Consumers observe expiry through the complete native
|
|
144
|
+
`AbortSignal`; `Timeout` adds no `Emitter` or parallel event system.
|
|
145
|
+
|
|
146
|
+
## Patterns
|
|
147
|
+
|
|
148
|
+
### Race work against a deadline
|
|
149
|
+
|
|
150
|
+
Builds a deadline handle, arms it, and clears it in a `finally` once the race resolves:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { createTimeout } from '@orkestrel/timeout'
|
|
154
|
+
|
|
155
|
+
async function fetchWithDeadline(url: string, ms: number): Promise<Response> {
|
|
156
|
+
const timeout = createTimeout({ ms })
|
|
157
|
+
timeout.start()
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
return await fetch(url, { signal: timeout.signal })
|
|
161
|
+
} finally {
|
|
162
|
+
timeout.clear() // cancels the still-armed deadline when the fetch won the race
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Link a parent signal
|
|
168
|
+
|
|
169
|
+
A parent `AbortSignal` clears the deadline instead of letting it expire — so
|
|
170
|
+
an outer cancellation (a request abort, a shutdown signal) short-circuits the
|
|
171
|
+
timer cleanly without aborting the timeout's own signal:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { createTimeout } from '@orkestrel/timeout'
|
|
175
|
+
|
|
176
|
+
function withDeadline(parent: AbortSignal, ms: number) {
|
|
177
|
+
const timeout = createTimeout({ id: 'request-deadline', ms, signal: parent })
|
|
178
|
+
timeout.start()
|
|
179
|
+
|
|
180
|
+
timeout.signal.addEventListener(
|
|
181
|
+
'abort',
|
|
182
|
+
() => {
|
|
183
|
+
if (timeout.expired) giveUp() // only a real timeout expiry reaches this listener
|
|
184
|
+
},
|
|
185
|
+
{ once: true },
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
return timeout
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Reuse a handle across deadlines
|
|
193
|
+
|
|
194
|
+
Clears an armed deadline before it fires, then arms the same handle again for a fresh window:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
import { createTimeout } from '@orkestrel/timeout'
|
|
198
|
+
|
|
199
|
+
const timeout = createTimeout({ ms: 100 })
|
|
200
|
+
|
|
201
|
+
timeout.start()
|
|
202
|
+
timeout.clear() // cancels before firing — expired stays false
|
|
203
|
+
|
|
204
|
+
timeout.start() // re-armed; a fresh deadline window begins
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Practices
|
|
208
|
+
|
|
209
|
+
- **Race, don't poll** — attach a listener to `signal` (or pass it straight to
|
|
210
|
+
an API that accepts an `AbortSignal`, for example `fetch`) rather than
|
|
211
|
+
polling `expired`.
|
|
212
|
+
- **`clear()` is always safe to call** — clearing an idle or already-cleared
|
|
213
|
+
handle is a no-op; after expiry it installs a fresh non-aborted signal. Call
|
|
214
|
+
it unconditionally in a `finally`.
|
|
215
|
+
- **Keep parent cancellation distinct** — a parent abort clears the timer but
|
|
216
|
+
does not abort the timeout signal or forward the parent reason.
|
|
217
|
+
- **Reuse, don't reconstruct** — call `start()` again on the same handle for a
|
|
218
|
+
new deadline window instead of constructing a fresh `Timeout`.
|
|
219
|
+
|
|
220
|
+
## Tests
|
|
221
|
+
|
|
222
|
+
- [`tests/guides.test.ts`](../tests/guides.test.ts) — the `## Surface` ↔
|
|
223
|
+
`src/core` bijection over value and type exports, the `TimeoutInterface` ↔
|
|
224
|
+
`Timeout` method bijection, and the equality gate: every `Summary` cell
|
|
225
|
+
against its declaration's description paragraph, the titled fence against the
|
|
226
|
+
`@example` block of that title (pinned so the titled pair cannot be retired
|
|
227
|
+
silently), and the README pitch against this guide's tagline. It also runs the
|
|
228
|
+
flagship fences and asserts the values their comments claim.
|
|
229
|
+
- [`tests/src/core/Timeout.test.ts`](../tests/src/core/Timeout.test.ts) —
|
|
230
|
+
public-constructor integration, real expiry / clear / replacement / churn
|
|
231
|
+
behavior, signal identity and derived expiry, and the intentional parent-clear
|
|
232
|
+
lifecycle.
|
|
233
|
+
- [`tests/src/core/helpers.test.ts`](../tests/src/core/helpers.test.ts) — fresh
|
|
234
|
+
normalized copies, omitted optional keys, exactly-once property reads, hostile
|
|
235
|
+
getter containment, duration boundaries, and exact structured errors.
|
|
236
|
+
- [`tests/src/core/validators.test.ts`](../tests/src/core/validators.test.ts) —
|
|
237
|
+
total duration and native-signal validation, including spoofed values and a
|
|
238
|
+
revoked proxy.
|
|
239
|
+
- [`tests/src/core/factories.test.ts`](../tests/src/core/factories.test.ts) —
|
|
240
|
+
`createTimeout` returns a working `TimeoutInterface` and preserves the strict
|
|
241
|
+
construction boundary.
|
|
242
|
+
|
|
243
|
+
## See also
|
|
244
|
+
|
|
245
|
+
- [`AGENTS.md`](../AGENTS.md) — the rules, including the documentation contract
|
|
246
|
+
and the fixed lifecycle meanings of `start` and `clear`.
|
|
247
|
+
- [`contract.md`](contract.md) — the mirrored guide for `@orkestrel/contract`,
|
|
248
|
+
the source of the validation primitives and `ContractError` used at the
|
|
249
|
+
construction boundary.
|
|
250
|
+
- [`guide.md`](guide.md) — the mirrored guide for `@orkestrel/guide`, the
|
|
251
|
+
devDependency powering this repo's guides-parity test suite.
|
|
252
|
+
- [`README.md`](README.md) — the guides index.
|