@orkestrel/scaffold 0.0.66 → 0.0.68
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 +8 -8
- 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 +1509 -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 +311 -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 +437 -6
- package/dist/src/core/index.cjs +44 -22
- 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 +43 -23
- 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 +9 -9
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Pool
|
|
2
|
+
|
|
3
|
+
> A typed resource pool with optional bounded capacity, unique ownership, FIFO settlement,
|
|
4
|
+
> validated reuse, caller-owned cancellation, explicit cleanup failures, and a stable
|
|
5
|
+
> event-driven teardown barrier.
|
|
6
|
+
|
|
7
|
+
The pool has no warm floor, eviction timer, acquire timeout, or polling loop. Every wait parks
|
|
8
|
+
on a promise or a signal listener and wakes when a settlement reaches it, and the lifecycle
|
|
9
|
+
hooks are the caller's, so the engine itself performs no I/O.
|
|
10
|
+
|
|
11
|
+
## Surface
|
|
12
|
+
|
|
13
|
+
`createPool` constructs the interface-oriented form; `Pool` exposes the same contract as a
|
|
14
|
+
class. Each created value receives an opaque ownership record, so duplicate primitives,
|
|
15
|
+
`undefined`, `NaN`, and repeated references are independent resources.
|
|
16
|
+
|
|
17
|
+
### Create a pool
|
|
18
|
+
|
|
19
|
+
Construct a pool from create, destroy, and validate hooks, then acquire and release one token:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { createPool } from '@orkestrel/pool'
|
|
23
|
+
|
|
24
|
+
const pool = createPool<Connection>({
|
|
25
|
+
create: () => connect(),
|
|
26
|
+
destroy: (connection) => connection.close(),
|
|
27
|
+
validate: (connection) => connection.alive,
|
|
28
|
+
max: 8,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const token = await pool.acquire()
|
|
32
|
+
try {
|
|
33
|
+
await token.value.query('select 1')
|
|
34
|
+
} finally {
|
|
35
|
+
token.release()
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Factories
|
|
40
|
+
|
|
41
|
+
| API | Kind | Summary |
|
|
42
|
+
| ------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
43
|
+
| `createPool` | function | Creates a distinct `PoolInterface` from resource lifecycle hooks, with optional bounded capacity, unique ownership, and FIFO settlement. |
|
|
44
|
+
|
|
45
|
+
### Classes
|
|
46
|
+
|
|
47
|
+
| API | Kind | Summary |
|
|
48
|
+
| ----------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
49
|
+
| `Pool` | class | Represents a capacity-aware resource pool whose opaque ownership records preserve FIFO settlement, cancellation, exact lease release, and deterministic teardown under concurrent hooks. |
|
|
50
|
+
| `PoolError` | class | Represents a stable, machine-readable pool failure that retains the original thrown value as its cause without unsafe coercion, alongside structured context. |
|
|
51
|
+
|
|
52
|
+
### Guards
|
|
53
|
+
|
|
54
|
+
In a guard table a `Shape` cell holds the type the guard narrows to.
|
|
55
|
+
|
|
56
|
+
| API | Kind | Shape | Summary |
|
|
57
|
+
| -------------- | -------- | ------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
58
|
+
| `isPoolError` | function | `PoolError` | Tests whether an unknown value is a `PoolError`, returning `false` for hostile proxies. |
|
|
59
|
+
| `isPoolMax` | function | `number` | Tests whether a value is a positive safe integer, the only valid explicit pool maximum. |
|
|
60
|
+
| `isPoolSignal` | function | `AbortSignal` | Tests whether a value is a native `AbortSignal` for the acquire boundary, returning `false` for hostile proxies. |
|
|
61
|
+
|
|
62
|
+
### Types
|
|
63
|
+
|
|
64
|
+
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 `\|`.
|
|
65
|
+
|
|
66
|
+
| API | Kind | Shape | Summary |
|
|
67
|
+
| ------------------ | --------- | -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
68
|
+
| `PoolCode` | type | `'invalid' \| 'destroyed' \| 'create' \| 'cleanup'` | Names the machine-readable failure codes produced by `PoolError`. |
|
|
69
|
+
| `PoolContext` | interface | `{ value?, failures? }` | Represents the structured context attached to a `PoolError`: the rejected input, or the distinct destroy-hook failures an aggregate cleanup collected. |
|
|
70
|
+
| `PoolErrorOptions` | interface | `{ code, cause?, context? }` | Represents the construction options for `PoolError`: the stable code, an optional cause, and optional structured context. |
|
|
71
|
+
| `PoolEventMap` | type | `{ create, acquire, release, destroy }` | Represents the observable resource lifecycle events emitted by a `PoolInterface`. |
|
|
72
|
+
| `PoolToken` | interface | `{ value } plus release` | Represents a unique lease over one pool-owned resource record, exposing that record as a readonly `value` and returning it through an idempotent `release`. |
|
|
73
|
+
| `PoolOptions` | interface | `{ on?, error?, create, destroy?, validate?, max? }` | Represents the resource lifecycle options for `Pool` and `createPool`: creation, destruction, validation, capacity, and observation. |
|
|
74
|
+
| `PoolInterface` | interface | `{ emitter, size, idle, active } plus acquire, clear, destroy` | Represents a FIFO resource pool with optional bounded capacity and deterministic teardown, exposing its record counts and a typed lifecycle emitter. |
|
|
75
|
+
|
|
76
|
+
`size` counts every owned record, including records being validated or destroyed. `idle`
|
|
77
|
+
counts only immediately available records. `active` counts only leased records. An in-flight
|
|
78
|
+
create reservation claims capacity but is not yet an owned record and therefore is not part
|
|
79
|
+
of `size`.
|
|
80
|
+
|
|
81
|
+
## Methods
|
|
82
|
+
|
|
83
|
+
The public call-signature members of `PoolInterface` and `PoolToken`; `Pool` implements the
|
|
84
|
+
`PoolInterface` list exactly.
|
|
85
|
+
|
|
86
|
+
#### `PoolInterface`
|
|
87
|
+
|
|
88
|
+
| Method | Returns | Summary |
|
|
89
|
+
| --------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
90
|
+
| `acquire` | `Promise<PoolToken<T>>` | Queues the caller in FIFO order, validates an idle record or creates one, and settles queued acquires in that same order. |
|
|
91
|
+
| `clear` | `Promise<void>` | Destroys the records that are idle at this call's synchronous snapshot. |
|
|
92
|
+
| `destroy` | `Promise<void>` | Tears down the pool permanently and returns its stable completion barrier. |
|
|
93
|
+
|
|
94
|
+
#### `PoolToken`
|
|
95
|
+
|
|
96
|
+
The lease returned by `acquire`, with the operation that returns its record.
|
|
97
|
+
|
|
98
|
+
| Method | Returns | Summary |
|
|
99
|
+
| --------- | ------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
100
|
+
| `release` | `void` | Gives this exact record back to the pool once; a repeat call, and a call after teardown took ownership, are no-ops. |
|
|
101
|
+
|
|
102
|
+
## Contract
|
|
103
|
+
|
|
104
|
+
### Capacity and FIFO
|
|
105
|
+
|
|
106
|
+
Every `acquire` receives its queue position before a create or validation hook starts. The
|
|
107
|
+
reentrancy-safe pump may assign several hook operations concurrently, but a head commit
|
|
108
|
+
barrier settles successes and failures in request order. A later fast create or validation
|
|
109
|
+
cannot overtake an earlier slow one. Capacity obeys:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
owned records + create reservations <= max
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`max` must be a positive safe integer. Omit it for an unbounded pool; `Infinity`, fractions,
|
|
116
|
+
zero, negative values, and unsafe integers are invalid. Construction snapshots `max` once and
|
|
117
|
+
validates it before retention, then snapshots `on` and `error` once each.
|
|
118
|
+
|
|
119
|
+
Record phases are disjoint:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
create reservation -> ready -> leased -> available -> validating -> ready
|
|
123
|
+
\-> destroying -> removed
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Invalid validation, whether `false` or a thrown value, claims and cleans the record before a
|
|
127
|
+
replacement capacity slot becomes available. Cleanup failure rejects that acquire with
|
|
128
|
+
`PoolError` code `cleanup`; successful cleanup lets the same FIFO waiter seek a replacement.
|
|
129
|
+
The bound outcome and replacement eligibility are established before synchronous `destroy`
|
|
130
|
+
observers can reenter acquisition. A create failure rejects its bound acquire with code
|
|
131
|
+
`create` and never strands later waiters.
|
|
132
|
+
|
|
133
|
+
### Cancellation
|
|
134
|
+
|
|
135
|
+
`acquire` validates a native `AbortSignal` before queueing. An invalid signal throws a
|
|
136
|
+
code-`invalid` `PoolError` synchronously instead of returning a rejected promise. A
|
|
137
|
+
pre-aborted signal and every later abort preserve the caller's exact `signal.reason`. The
|
|
138
|
+
listener is attached, recorded, and followed by an aborted-state recheck, then detached on
|
|
139
|
+
every settlement. Aborting while create or validation work is assigned removes the waiter
|
|
140
|
+
exactly once; any late resource is returned to the live pump or cleaned during teardown. A
|
|
141
|
+
ready result waiting behind a slower head can likewise be aborted without leaking its record.
|
|
142
|
+
If cancelled validation later proves the record invalid and its cleanup fails, the acquire
|
|
143
|
+
still preserves the caller's abort reason while the cleanup failure is retained for the
|
|
144
|
+
eventual `destroy()` barrier.
|
|
145
|
+
|
|
146
|
+
### Release and cleanup
|
|
147
|
+
|
|
148
|
+
A token captures its exact opaque record, so `release()` is correct even when multiple
|
|
149
|
+
records contain the same value. Release is idempotent and removes the lease synchronously.
|
|
150
|
+
With a waiter, the record is validated before handoff. Without an assignable waiter, it
|
|
151
|
+
becomes idle and emits `release`. Release after teardown ownership transferred is a no-op.
|
|
152
|
+
|
|
153
|
+
`clear()` synchronously snapshots idle records and installs one cleanup promise per record
|
|
154
|
+
before invoking the hook. Concurrent clears therefore own disjoint snapshots, and a lease
|
|
155
|
+
released after a snapshot is taken is not part of it. Every claimed record stays in `size` until its
|
|
156
|
+
hook attempt completes. Distinct failures are aggregated in a code-`cleanup` `PoolError`
|
|
157
|
+
whose `context.failures` retains the original thrown values.
|
|
158
|
+
Each claimed record's cleanup settlement independently wakes queued acquires after the
|
|
159
|
+
destroy ledger transition, whether its cleanup hook succeeded or failed; a failed `clear()`
|
|
160
|
+
still rejects its own aggregate cleanup barrier.
|
|
161
|
+
|
|
162
|
+
### Destruction
|
|
163
|
+
|
|
164
|
+
`destroy()` is deliberately non-`async`: it installs and returns its exact promise before it
|
|
165
|
+
rejects waiters, emits events, or invokes cleanup. Reentrant and repeated calls return that
|
|
166
|
+
same object. Teardown invalidates idle, leased, and ready records, waits for create,
|
|
167
|
+
validation, existing clear cleanup, and new cleanup activity, and disposes every late
|
|
168
|
+
resource. Unresolved hooks keep the barrier pending without polling.
|
|
169
|
+
|
|
170
|
+
Cleanup already owned by an overlapping `clear()` is shared; its failure is reported to both
|
|
171
|
+
the clear call and the destroy aggregate. Create failures that produced no resource do not
|
|
172
|
+
fail destruction. The emitter is destroyed last, after every resource `destroy` event and
|
|
173
|
+
hook attempt, then the stable barrier resolves or rejects.
|
|
174
|
+
|
|
175
|
+
### Errors
|
|
176
|
+
|
|
177
|
+
`PoolError.code` is stable and lowercase:
|
|
178
|
+
|
|
179
|
+
| Code | Owner |
|
|
180
|
+
| ----------- | ------------------------------------------------------------------------ |
|
|
181
|
+
| `invalid` | Invalid explicit `max`, invalid acquire signal, or an internal boundary. |
|
|
182
|
+
| `destroyed` | Acquire or clear attempted after terminal teardown began. |
|
|
183
|
+
| `create` | The create hook failed for its bound acquire. |
|
|
184
|
+
| `cleanup` | Invalid-handoff, clear, or destroy cleanup failed. |
|
|
185
|
+
|
|
186
|
+
The original thrown value is retained as `cause`; aggregate cleanup values are also in
|
|
187
|
+
`context.failures`. Message construction and `isPoolError` avoid unsafe string coercion and
|
|
188
|
+
return safely for hostile proxies.
|
|
189
|
+
|
|
190
|
+
## Observing
|
|
191
|
+
|
|
192
|
+
The composed `Emitter` isolates listener throws through the optional `error` handler and
|
|
193
|
+
invokes listeners synchronously at each emission point. The `destroy` emission is deliberately
|
|
194
|
+
one microtask after cleanup settlement so bound outcomes precede observer reentry. Events
|
|
195
|
+
follow their ledger transitions:
|
|
196
|
+
|
|
197
|
+
| Event | Emission point |
|
|
198
|
+
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
199
|
+
| `create` | After a fresh resource is inserted into the ownership ledger. |
|
|
200
|
+
| `acquire` | After the waiter promise receives its token and the record is leased. |
|
|
201
|
+
| `release` | Only when the released or orphaned-ready record remains idle. |
|
|
202
|
+
| `destroy` | After the hook attempt and resource-ledger removal, one microtask after private cleanup settlement, while destroying ownership remains installed through the event. |
|
|
203
|
+
|
|
204
|
+
Because listeners may synchronously reenter or destroy the pool, the engine checks terminal
|
|
205
|
+
and waiter state after every awaited hook and every emit.
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
import { createPool } from '@orkestrel/pool'
|
|
209
|
+
|
|
210
|
+
const pool = createPool({
|
|
211
|
+
create: () => connect(),
|
|
212
|
+
on: {
|
|
213
|
+
create: () => metrics.increment('pool.create'),
|
|
214
|
+
destroy: () => metrics.increment('pool.destroy'),
|
|
215
|
+
},
|
|
216
|
+
error: (error, event) => report(error, event),
|
|
217
|
+
})
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Patterns
|
|
221
|
+
|
|
222
|
+
### Validate public boundaries
|
|
223
|
+
|
|
224
|
+
Check a candidate value or error against the public boundary guards before acting on it:
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
import { PoolError, isPoolError, isPoolMax, isPoolSignal } from '@orkestrel/pool'
|
|
228
|
+
|
|
229
|
+
isPoolMax(4) // true
|
|
230
|
+
isPoolMax(Infinity) // false: omit max for unbounded capacity
|
|
231
|
+
isPoolSignal(new AbortController().signal) // true
|
|
232
|
+
|
|
233
|
+
const failure = new PoolError({ code: 'destroyed' })
|
|
234
|
+
if (isPoolError(failure)) console.error(failure.code)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Always release and explicitly tear down
|
|
238
|
+
|
|
239
|
+
Release every acquired token and call `destroy()` explicitly after work finishes:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import { Pool } from '@orkestrel/pool'
|
|
243
|
+
|
|
244
|
+
const pool = new Pool({ create: () => connect(), max: 4 })
|
|
245
|
+
const controller = new AbortController()
|
|
246
|
+
const token = await pool.acquire(controller.signal)
|
|
247
|
+
try {
|
|
248
|
+
await use(token.value)
|
|
249
|
+
} finally {
|
|
250
|
+
token.release()
|
|
251
|
+
}
|
|
252
|
+
await pool.clear()
|
|
253
|
+
await pool.destroy()
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Tests
|
|
257
|
+
|
|
258
|
+
- [`tests/src/core/Pool.test.ts`](../tests/src/core/Pool.test.ts) — canonical behavior:
|
|
259
|
+
validation, hostile errors, duplicate ownership, transitional counts, overlapping FIFO
|
|
260
|
+
hooks, create continuation, abort boundaries, abort-listener detachment, exclusive
|
|
261
|
+
invalid-cleanup waiter ownership, bounded and unbounded replacement, destroy-observer
|
|
262
|
+
reentry ordering, concurrent clear, stable reentrant destruction, late resources,
|
|
263
|
+
aggregate failures, emitter ordering, and high contention.
|
|
264
|
+
- [`tests/src/core/validators.test.ts`](../tests/src/core/validators.test.ts) — the public
|
|
265
|
+
boundary guards alone: accepted and rejected maxima, and native versus hostile signals.
|
|
266
|
+
- [`tests/src/core/factories.test.ts`](../tests/src/core/factories.test.ts) — factory
|
|
267
|
+
construction and instance identity only.
|
|
268
|
+
- [`tests/guides.test.ts`](../tests/guides.test.ts) — the `## Surface` ↔ `src/core` bijection
|
|
269
|
+
over value and type exports, the `PoolInterface` ↔ `Pool` and `PoolToken` method bijections,
|
|
270
|
+
fence-import and relative-link resolution, and the equality gate: every `Summary` cell against
|
|
271
|
+
its declaration's description paragraph, the titled `Create a pool` fence against the
|
|
272
|
+
`@example` block of that title (pinned so the titled pair cannot be retired silently), and the
|
|
273
|
+
README pitch against this guide's tagline. It also runs the boundary-guard fence and asserts
|
|
274
|
+
the values its comments claim.
|
|
275
|
+
|
|
276
|
+
## See also
|
|
277
|
+
|
|
278
|
+
- [`emitter.md`](emitter.md) — the installed observation primitive.
|
|
279
|
+
- [`AGENTS.md`](../AGENTS.md) — repository coding and lifecycle rules.
|
|
280
|
+
- [`README.md`](README.md) — guide manifest.
|