brass-runtime 1.16.0 → 1.16.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.
Files changed (210) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +283 -18
  3. package/dist/agent/cli/main.cjs +38 -38
  4. package/dist/agent/cli/main.js +6 -6
  5. package/dist/agent/cli/main.mjs +6 -6
  6. package/dist/agent/index.cjs +7 -7
  7. package/dist/agent/index.d.ts +1 -1
  8. package/dist/agent/index.js +6 -6
  9. package/dist/agent/index.mjs +6 -6
  10. package/dist/chunk-2HQTDLHF.mjs +683 -0
  11. package/dist/chunk-36I3M4UC.mjs +370 -0
  12. package/dist/{chunk-QY5FKYEQ.js → chunk-3AYM6WPJ.js} +570 -51
  13. package/dist/chunk-3LOYJFRR.cjs +300 -0
  14. package/dist/chunk-3Y2RIUMM.js +300 -0
  15. package/dist/{chunk-N6VHMOWB.cjs → chunk-4ROBZFL6.cjs} +128 -128
  16. package/dist/{chunk-NC5SDRYE.js → chunk-52OB2ROS.js} +4 -4
  17. package/dist/{chunk-JX3LZQJH.cjs → chunk-52PPNNI4.cjs} +82 -20
  18. package/dist/{chunk-5YOQOXEQ.cjs → chunk-5EC274J5.cjs} +676 -293
  19. package/dist/chunk-5QC7LRZ3.js +229 -0
  20. package/dist/{chunk-7TL2LHQJ.js → chunk-5VRJNBLZ.mjs} +524 -141
  21. package/dist/chunk-62AZW6UT.cjs +313 -0
  22. package/dist/chunk-6IXXWIUM.js +683 -0
  23. package/dist/chunk-74ZTY6CP.js +2871 -0
  24. package/dist/chunk-76YMRMH2.cjs +777 -0
  25. package/dist/chunk-7CMJS3QE.mjs +2871 -0
  26. package/dist/{chunk-2WC63LJK.mjs → chunk-7JIJOVCT.js} +20 -10
  27. package/dist/{chunk-FM4W4QPL.js → chunk-A2OM6NEH.mjs} +5 -4
  28. package/dist/chunk-AGR5B2BC.cjs +683 -0
  29. package/dist/chunk-AVNQLJ5V.js +777 -0
  30. package/dist/chunk-B33ICAKP.js +313 -0
  31. package/dist/{chunk-J3H54ZRV.mjs → chunk-B5JD23U7.mjs} +1 -1
  32. package/dist/chunk-BABBZK4Y.js +2024 -0
  33. package/dist/{chunk-U5KWK3PX.mjs → chunk-C3MDXTRZ.js} +11 -0
  34. package/dist/{chunk-F5EUMJL7.mjs → chunk-CIZFIMK5.js} +55 -5
  35. package/dist/{chunk-SPUEME2B.cjs → chunk-CZIVE6NT.cjs} +12 -1
  36. package/dist/{chunk-TDVMADDN.js → chunk-DNFJLJMW.mjs} +11 -0
  37. package/dist/chunk-DNFO2EIZ.mjs +777 -0
  38. package/dist/{chunk-XDZOO4L5.js → chunk-EJ6BPYVR.mjs} +79 -17
  39. package/dist/{chunk-JNFRRJYH.cjs → chunk-ENKODRU3.cjs} +242 -192
  40. package/dist/chunk-EOC4UHBS.mjs +229 -0
  41. package/dist/{chunk-7LVI2GIN.js → chunk-FH2X7BVP.js} +507 -72
  42. package/dist/{chunk-OOGJ73B6.js → chunk-FHQGHPMO.mjs} +20 -10
  43. package/dist/{chunk-WQ5QNU5R.cjs → chunk-GLE2WY7Z.cjs} +652 -217
  44. package/dist/{chunk-G6IQOE4P.mjs → chunk-GYM3LLGS.mjs} +507 -72
  45. package/dist/chunk-HLWLMW2F.mjs +2024 -0
  46. package/dist/{chunk-TVN5I4U6.cjs → chunk-JF5WGYJJ.cjs} +25 -24
  47. package/dist/{chunk-CY33PGEX.mjs → chunk-KH4SYAOS.mjs} +570 -51
  48. package/dist/chunk-KN32XNTH.mjs +313 -0
  49. package/dist/chunk-KQLYONSE.cjs +2871 -0
  50. package/dist/{chunk-7HUOJA4W.cjs → chunk-KZJQ723N.cjs} +90 -80
  51. package/dist/{chunk-CCKHV5BT.mjs → chunk-L2SYFEBS.js} +5 -4
  52. package/dist/{chunk-IJT6RRQ5.cjs → chunk-L6VB5N7Q.cjs} +20 -9
  53. package/dist/{chunk-ZGLD4TVZ.mjs → chunk-MBEJI5HF.mjs} +4 -4
  54. package/dist/{chunk-PRWCB3QL.mjs → chunk-MIIYDLGM.js} +524 -141
  55. package/dist/{chunk-H55LI6WY.js → chunk-MOO4L7F4.mjs} +15 -4
  56. package/dist/{chunk-7XOPAB5Q.js → chunk-MT3OWDPC.mjs} +55 -5
  57. package/dist/chunk-MVGUEJ5Z.cjs +370 -0
  58. package/dist/chunk-PD4EJTQC.cjs +229 -0
  59. package/dist/chunk-PWC3RBQE.mjs +300 -0
  60. package/dist/{chunk-MWXMNYJS.cjs → chunk-Q2I37RP3.cjs} +643 -124
  61. package/dist/{chunk-VFIUZG7J.mjs → chunk-RKGKFN2A.js} +79 -17
  62. package/dist/{chunk-NYL4D7SK.cjs → chunk-SA6HUJVI.cjs} +5 -5
  63. package/dist/{chunk-K2T3DV26.mjs → chunk-TRM4JUZQ.js} +15 -4
  64. package/dist/chunk-UB4B6OFY.js +370 -0
  65. package/dist/{chunk-G3XGCZDQ.js → chunk-UCUBNWM2.js} +1 -1
  66. package/dist/chunk-VN44DYYT.cjs +2024 -0
  67. package/dist/{client-CtFmoDvM.d.ts → client-CZHU674n.d.ts} +211 -36
  68. package/dist/core/index.cjs +135 -9
  69. package/dist/core/index.d.ts +238 -33
  70. package/dist/core/index.js +155 -29
  71. package/dist/core/index.mjs +155 -29
  72. package/dist/{effect-CGNl5Rqp.d.ts → effect-DIUHZ9IN.d.ts} +89 -1
  73. package/dist/effectRunner-CFLC32IK.cjs +8 -0
  74. package/dist/{effectRunner-A4CHJXJI.js → effectRunner-L4S7IPT3.js} +2 -2
  75. package/dist/{effectRunner-OPUF6QRN.mjs → effectRunner-NNGG75QA.mjs} +2 -2
  76. package/dist/http/index.cjs +324 -2986
  77. package/dist/http/index.d.ts +54 -68
  78. package/dist/http/index.js +238 -2900
  79. package/dist/http/index.mjs +238 -2900
  80. package/dist/http/testing.cjs +14 -12
  81. package/dist/http/testing.d.ts +5 -4
  82. package/dist/http/testing.js +10 -8
  83. package/dist/http/testing.mjs +10 -8
  84. package/dist/index.cjs +423 -255
  85. package/dist/index.d.ts +87 -69
  86. package/dist/index.js +301 -133
  87. package/dist/index.mjs +301 -133
  88. package/dist/observability/index.cjs +16 -531
  89. package/dist/observability/index.d.ts +81 -8
  90. package/dist/observability/index.js +23 -538
  91. package/dist/observability/index.mjs +23 -538
  92. package/dist/perf/cli.cjs +401 -0
  93. package/dist/perf/cli.d.ts +1 -0
  94. package/dist/perf/cli.js +401 -0
  95. package/dist/perf/cli.mjs +401 -0
  96. package/dist/perf/index.cjs +141 -0
  97. package/dist/perf/index.d.ts +483 -0
  98. package/dist/perf/index.js +141 -0
  99. package/dist/perf/index.mjs +141 -0
  100. package/dist/schedule-CK3Ml_7p.d.ts +259 -0
  101. package/dist/schema/index.cjs +6 -2
  102. package/dist/schema/index.d.ts +3 -1
  103. package/dist/schema/index.js +5 -1
  104. package/dist/schema/index.mjs +5 -1
  105. package/dist/{server-C8hDXA74.d.ts → server-GJPg8ZSG.d.ts} +4 -3
  106. package/dist/{stream-dvSs0QS5.d.ts → stream-B4oK9JFP.d.ts} +1 -1
  107. package/dist/{tracer-B5tRH9H7.d.ts → tracer-Hwt1cl7h.d.ts} +13 -54
  108. package/dist/{tracing-Dt9S_6V8.d.ts → tracing-DqbTKGcf.d.ts} +1 -1
  109. package/docs/ARCHITECTURE.md +292 -0
  110. package/docs/README.md +63 -0
  111. package/docs/adr/0001-ai-context-pack.md +32 -0
  112. package/docs/agent-apply-mode.md +104 -0
  113. package/docs/agent-approvals.md +110 -0
  114. package/docs/agent-batch.md +185 -0
  115. package/docs/agent-boundaries.md +112 -0
  116. package/docs/agent-chat-sessions.md +160 -0
  117. package/docs/agent-ci.md +17 -0
  118. package/docs/agent-cli.md +405 -0
  119. package/docs/agent-config.md +480 -0
  120. package/docs/agent-context-discovery.md +159 -0
  121. package/docs/agent-copilot-like-dx.md +126 -0
  122. package/docs/agent-declarative-optimized-planning.md +138 -0
  123. package/docs/agent-dx.md +224 -0
  124. package/docs/agent-env-files.md +126 -0
  125. package/docs/agent-follow-up-context.md +43 -0
  126. package/docs/agent-global-usage.md +180 -0
  127. package/docs/agent-init.md +109 -0
  128. package/docs/agent-install-and-configure.md +516 -0
  129. package/docs/agent-language-workspace-ux.md +99 -0
  130. package/docs/agent-llm-adapters.md +123 -0
  131. package/docs/agent-local-install.md +190 -0
  132. package/docs/agent-local-tests.md +51 -0
  133. package/docs/agent-observability.md +155 -0
  134. package/docs/agent-patch-quality-loop.md +162 -0
  135. package/docs/agent-presets.md +22 -0
  136. package/docs/agent-project-commands.md +237 -0
  137. package/docs/agent-project-intelligence.md +156 -0
  138. package/docs/agent-redaction.md +18 -0
  139. package/docs/agent-release-readiness.md +76 -0
  140. package/docs/agent-rollback-safety.md +162 -0
  141. package/docs/agent-rollback.md +23 -0
  142. package/docs/agent-run-artifacts.md +16 -0
  143. package/docs/agent-vscode-auto-discovery.md +137 -0
  144. package/docs/agent-vscode-batch-runner.md +100 -0
  145. package/docs/agent-vscode-chat-layout.md +90 -0
  146. package/docs/agent-vscode-clean-install.md +147 -0
  147. package/docs/agent-vscode-code-actions.md +70 -0
  148. package/docs/agent-vscode-diff-preview.md +45 -0
  149. package/docs/agent-vscode-inline-assist.md +56 -0
  150. package/docs/agent-vscode-install.md +186 -0
  151. package/docs/agent-vscode-model-setup.md +97 -0
  152. package/docs/agent-vscode-patch-preview.md +92 -0
  153. package/docs/agent-vscode-problems.md +79 -0
  154. package/docs/agent-vscode-project-dashboard.md +106 -0
  155. package/docs/agent-vscode-run-history.md +92 -0
  156. package/docs/agent-vscode-ux.md +73 -0
  157. package/docs/ai/INVARIANTS.md +84 -0
  158. package/docs/ai/PROJECT_MAP.md +338 -0
  159. package/docs/ai/PUBLIC_API.md +336 -0
  160. package/docs/ai/VALIDATION_MATRIX.md +67 -0
  161. package/docs/api-polish.md +37 -0
  162. package/docs/cancellation.md +162 -0
  163. package/docs/coverage.md +46 -0
  164. package/docs/getting-started.md +159 -0
  165. package/docs/guides/README.md +40 -0
  166. package/docs/guides/circuit-breaker.md +89 -0
  167. package/docs/guides/error-handling.md +91 -0
  168. package/docs/guides/getting-started.md +107 -0
  169. package/docs/guides/layers.md +189 -0
  170. package/docs/guides/metrics.md +101 -0
  171. package/docs/guides/resource-management.md +141 -0
  172. package/docs/guides/retry.md +215 -0
  173. package/docs/guides/semaphore.md +66 -0
  174. package/docs/guides/streams.md +117 -0
  175. package/docs/guides/supervisors.md +98 -0
  176. package/docs/guides/testing.md +162 -0
  177. package/docs/guides/tracing.md +71 -0
  178. package/docs/http-recipes.md +399 -0
  179. package/docs/http.md +749 -0
  180. package/docs/modules.md +285 -0
  181. package/docs/observability-collector-smoke.md +31 -0
  182. package/docs/observability-framework-examples.md +98 -0
  183. package/docs/observability.md +542 -0
  184. package/docs/otel-collector-smoke.yaml +27 -0
  185. package/docs/performance-profiler.md +199 -0
  186. package/docs/production-readiness.md +73 -0
  187. package/docs/recipes/README.md +12 -0
  188. package/docs/recipes/http-server.md +45 -0
  189. package/docs/recipes/layers.md +44 -0
  190. package/docs/recipes/performance.md +47 -0
  191. package/docs/recipes/runtime.md +41 -0
  192. package/docs/recipes/testing.md +41 -0
  193. package/docs/release.md +53 -0
  194. package/docs/wasm-bounded-queues.md +44 -0
  195. package/docs/wasm-engine-observability-benchmarks.md +85 -0
  196. package/docs/wasm-fiber-engine.md +117 -0
  197. package/docs/wasm-scheduler-state-machine.md +122 -0
  198. package/docs/wasm-stream-chunks.md +54 -0
  199. package/package.json +22 -2
  200. package/dist/chunk-45F7OKGT.cjs +0 -104
  201. package/dist/chunk-7V4KY4RL.mjs +0 -104
  202. package/dist/chunk-DJQ7OMMB.cjs +0 -144
  203. package/dist/chunk-GOV47PPB.mjs +0 -552
  204. package/dist/chunk-JF4XXPZ5.cjs +0 -552
  205. package/dist/chunk-KCPT2D6G.js +0 -552
  206. package/dist/chunk-NOYZIMUJ.mjs +0 -144
  207. package/dist/chunk-PNVFW245.js +0 -144
  208. package/dist/chunk-ROJC3NBJ.js +0 -104
  209. package/dist/effectRunner-3ZHAD3LE.cjs +0 -8
  210. package/dist/schedule-Fque9Abz.d.ts +0 -70
package/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## 1.14.0 - First Public Release Candidate
4
+
5
+ - Added mature core runtime features: structured concurrency, `Cause`,
6
+ interruptibility, `FiberRef`, Layer 2.0, Schedule 2.0, TestRuntime, streams,
7
+ and runtime observability.
8
+ - Added HTTP client/server surface with schema validation, lifecycle
9
+ middleware, adaptive limiter, retry, compression, health/readiness, and
10
+ observability hooks.
11
+ - Added `brass-runtime/perf` with runtime A/B, soak profiling, HTTP memory lab,
12
+ benchmark budgets, and local perf history/baseline storage.
13
+ - Added DX helpers: `runPromise`, `runExit`, `makeRuntime`, `defineService`,
14
+ `getService`, `provide`, `formatLayerError`, `formatConfigError`, and
15
+ `HttpServer`.
16
+ - Added first-release recipes under `docs/recipes/` and release validation via
17
+ `npm run release:check`.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # brass-runtime
2
2
 
3
- A ZIO-inspired effect runtime for TypeScript with structured concurrency, pull-based streams, and a production-grade HTTP client.
3
+ A ZIO-inspired effect runtime for TypeScript with structured concurrency,
4
+ runtime diagnostics, pull-based streams, and a production-grade HTTP client.
4
5
 
5
6
  Built without `Promise`/`async`/`await` as the primary semantic primitive. Effects are values — lazy, composable, and cancelable by default.
6
7
 
@@ -12,19 +13,27 @@ npm i brass-runtime
12
13
 
13
14
  ## What it does
14
15
 
15
- **Core runtime** — algebraic effects, fibers, scopes, scheduler, layers, semaphores, circuit breakers, metrics, tracing.
16
+ **Runtime** — algebraic effects, fibers, scopes, scheduler, interruptibility
17
+ regions, fiber-local refs, typed layers, semaphores, circuit breakers, rich
18
+ `Cause<E>` failures, metrics, tracing, and an opt-in flight recorder.
16
19
 
17
- **Streams** — pull-based with backpressure, bounded buffers, queues, hubs, pipelines, fusion optimization.
20
+ **Streams** — pull-based streams with backpressure, bounded buffers, hubs,
21
+ pipelines, fusion optimization, and a small fluent DX facade.
18
22
 
19
- **HTTP client** — lazy/cancelable requests with a full middleware pipeline: adaptive concurrency, compression, batching, connection pre-warming, caching, deduplication, priority scheduling, and retry with backoff.
23
+ **HTTP** — lazy/cancelable client and server primitives with typed routing,
24
+ schema validation, health/readiness probes, adaptive concurrency, compression,
25
+ batching, prewarm, cache, dedup, priority, retry, and observability.
20
26
 
21
- **Schema validation** — dependency-free runtime schemas for JSON, config, and protocol boundaries, with typed inference and path-rich validation issues.
27
+ **Production signals** — dependency-free schemas, Prometheus/OTLP exporters,
28
+ structured logs, W3C trace propagation, sampling, redaction, bounded exporters,
29
+ and explicit flush/shutdown.
22
30
 
23
- **Observability export** — Prometheus metrics, OTLP metrics/traces/logs, structured logging, W3C trace-context propagation, request adapters, sampling, redaction, bounded exporters, and production flush/shutdown controls.
31
+ **Performance profiler** — runtime primitives, HTTP layer comparison, memory
32
+ retention reports, observability overhead, CLI/JSON output, and actionable
33
+ recommendations.
24
34
 
25
- **WASM engine** — optional Rust/WASM-backed state machines for strict scheduling and bounded queues.
26
-
27
- **Brass Agent** — experimental CLI coding agent with workspace inspection, LLM integration, and VS Code extension.
35
+ **Optional engine and tools** — Rust/WASM-backed state machines plus the
36
+ experimental Brass Agent CLI/VS Code workflow.
28
37
 
29
38
  ---
30
39
 
@@ -43,12 +52,86 @@ npm i brass-runtime
43
52
  ### Run an effect
44
53
 
45
54
  ```ts
46
- import { Runtime, succeed } from "brass-runtime";
55
+ import { runPromise, succeed } from "brass-runtime";
56
+
57
+ const value = await runPromise(succeed(42));
58
+ ```
59
+
60
+ Use `makeRuntime` when you want explicit runtime options, and `runExit` when
61
+ you want the full `Exit`/`Cause` instead of a rejected promise.
62
+
63
+ ### Inspect failure causes
64
+
65
+ ```ts
66
+ import { Cause, formatCause } from "brass-runtime";
67
+
68
+ const cause = Cause.then(
69
+ Cause.fail("database unavailable"),
70
+ Cause.both(Cause.interrupt(), Cause.die(new Error("release failed"))),
71
+ );
72
+
73
+ console.log(formatCause(cause));
74
+ ```
75
+
76
+ `Cause<E>` preserves typed failures, defects, interruptions, and sequential or
77
+ parallel composition (`Then` / `Both`) so diagnostics can explain what happened
78
+ without flattening every failure into a single thrown value.
79
+
80
+ ### Mask interruption
81
+
82
+ ```ts
83
+ import { async, flatMap, succeed, uninterruptibleMask } from "brass-runtime";
84
+
85
+ const effect = uninterruptibleMask((restore) =>
86
+ flatMap(succeed("acquired"), (resource) =>
87
+ restore(async((_env, cb) => {
88
+ setTimeout(() => cb({ _tag: "Success", value: `used:${resource}` }), 10);
89
+ })),
90
+ ),
91
+ );
92
+ ```
93
+
94
+ Use `uninterruptible(effect)` for critical regions and
95
+ `uninterruptibleMask((restore) => ...)` when only part of the region should be
96
+ interruptible again. Pending interruption is deferred until the protected region
97
+ exits; restored sub-effects remain cancelable.
98
+
99
+ ### Fiber-local context
100
+
101
+ ```ts
102
+ import { Runtime, makeFiberRef } from "brass-runtime";
47
103
 
104
+ const requestId = makeFiberRef("anonymous");
48
105
  const runtime = Runtime.make({});
49
- const value = await runtime.toPromise(succeed(42));
106
+
107
+ const result = await runtime.toPromise(
108
+ requestId.locally("req-123", requestId.get()),
109
+ );
110
+ ```
111
+
112
+ `FiberRef` values are local to the running fiber, inherited by child fibers at
113
+ fork time, isolated from child mutations, and restored after `locally` regions
114
+ even when the region fails or is interrupted.
115
+
116
+ ### Explain runtime behavior
117
+
118
+ ```ts
119
+ import { Runtime, async, makeRuntimeRecorder } from "brass-runtime";
120
+
121
+ const recorder = makeRuntimeRecorder({ maxEvents: 5000 });
122
+ const runtime = new Runtime({ env: {}, hooks: recorder.hooks });
123
+
124
+ await runtime.toPromise(async((_env, cb) => {
125
+ setTimeout(() => cb({ _tag: "Success", value: "ok" }), 10);
126
+ }));
127
+
128
+ console.log(recorder.explain());
50
129
  ```
51
130
 
131
+ The flight recorder is opt-in and keeps a bounded ring buffer of runtime events:
132
+ fiber start/end/suspend/resume, scopes, supervisor events, logs, spans, and
133
+ trace context when available.
134
+
52
135
  ### Recommended HTTP client
53
136
 
54
137
  ```ts
@@ -75,8 +158,10 @@ console.log(http.compression?.stats());
75
158
  `makeDefaultHttpClient` is the batteries-included entrypoint: timeout,
76
159
  deduplication, priority scheduling, retry, adaptive concurrency, safe-method
77
160
  response cache, decompression, stats, `cancelAll`, and JSON/text helpers. Use
161
+ `preset: "production"` when you want that production-ready shape explicitly,
78
162
  `preset: "balanced"` to skip the default cache, or `preset: "minimal"` for a
79
- cheap wire client with the same helper API.
163
+ cheap wire client with the same helper API. `preset: "default"` remains the
164
+ same full preset for compatibility.
80
165
 
81
166
  The HTTP stack is meant to replace the usual `fetch` wrapper plus Zod/Valibot
82
167
  glue: schemas are dependency-free, responses and request bodies are validated in
@@ -84,6 +169,70 @@ the same effect, config validation fails at construction time, and the client
84
169
  still owns cancellation, retries, compression, observability, and adaptive
85
170
  limits as one pipeline.
86
171
 
172
+ Custom Promise clients such as Axios can be injected without making the
173
+ consumer manage `AbortSignal` or `Async` plumbing:
174
+
175
+ ```ts
176
+ import {
177
+ defineHttpPolicyPresets,
178
+ formatHttpError,
179
+ isRetryableHttpError,
180
+ makeDefaultHttpClient,
181
+ promiseHttpTransport,
182
+ } from "brass-runtime/http";
183
+
184
+ const transport = promiseHttpTransport()
185
+ .requestConfig(({ request, url }) => ({
186
+ url: url.toString(),
187
+ method: request.method,
188
+ headers: request.headers,
189
+ data: request.body,
190
+ responseType: "json",
191
+ }))
192
+ .send((config) => axiosInstance.request(config))
193
+ .json();
194
+
195
+ const axiosHttp = makeDefaultHttpClient({
196
+ baseUrl: "https://api.example.com",
197
+ transport,
198
+ });
199
+
200
+ try {
201
+ await axiosHttp.getJson("/users/1").unsafeRunPromise();
202
+ } catch (error) {
203
+ if (isRetryableHttpError(error)) {
204
+ console.warn("transient upstream failure");
205
+ }
206
+ console.error(formatHttpError(error));
207
+ }
208
+ ```
209
+
210
+ Brass injects the runtime `AbortSignal` into object configs before `send` and
211
+ normalizes external failures with `toHttpError`, including Axios-like
212
+ `response.status`, aborts, and common timeout codes.
213
+
214
+ Repeated execution intent can be named once with policy presets:
215
+
216
+ ```ts
217
+ const policies = defineHttpPolicyPresets({
218
+ readModel: {
219
+ lane: "read-model",
220
+ poolKey: "users-api",
221
+ priority: 2,
222
+ retry: { maxRetries: 2, baseDelayMs: 50 },
223
+ },
224
+ });
225
+
226
+ const http = makeDefaultHttpClient({
227
+ baseUrl: "https://api.example.com",
228
+ policyPresets: policies,
229
+ });
230
+
231
+ await http.getJson("/users/1", {
232
+ policy: { preset: "readModel", dedupKey: "users:1" },
233
+ }).unsafeRunPromise();
234
+ ```
235
+
87
236
  The default adaptive limiter uses the `aggressive` preset: warmup sample floor,
88
237
  P5 baseline, error-rate signal, priority-aware queueing, jittered probes,
89
238
  proportional headroom, capped decreases, and TTL-evicted per-key state.
@@ -122,6 +271,45 @@ The same validation machinery checks runtime, HTTP, and observability configs
122
271
  at construction time, so invalid values fail with field paths like
123
272
  `$.otlp.pipeline.batchSize` instead of surfacing later as ambiguous behavior.
124
273
 
274
+ ### HTTP server
275
+
276
+ ```ts
277
+ import { asyncSucceed, asyncSync, runPromise, useResource } from "brass-runtime";
278
+ import { HttpServer, s } from "brass-runtime/http";
279
+
280
+ const User = s.object({
281
+ id: s.nonEmptyString(),
282
+ name: s.nonEmptyString(),
283
+ });
284
+
285
+ const router = HttpServer.router([
286
+ HttpServer.route("GET", "/users/:id", {
287
+ params: s.object({ id: s.nonEmptyString() }),
288
+ response: User,
289
+ }, (ctx) =>
290
+ asyncSucceed(HttpServer.json({
291
+ id: ctx.params.id,
292
+ name: "Ada",
293
+ })),
294
+ ),
295
+ HttpServer.healthRoute(),
296
+ HttpServer.readinessRoute(),
297
+ ]);
298
+
299
+ await runPromise(
300
+ useResource(
301
+ router.listen({ port: 3000 }),
302
+ (server) => asyncSync(() => {
303
+ console.log(server.url());
304
+ }),
305
+ ),
306
+ );
307
+ ```
308
+
309
+ Routes infer `:params` from the path, optional schemas validate
310
+ params/query/body/response, middleware is effect-based, and the Node listener is
311
+ available as a managed resource for graceful shutdown.
312
+
125
313
  ### Discoverable HTTP builder
126
314
 
127
315
  ```ts
@@ -131,7 +319,7 @@ declare const token: string;
131
319
 
132
320
  const http = httpClientBuilder()
133
321
  .baseUrl("https://api.example.com")
134
- .balanced()
322
+ .production()
135
323
  .balancedLimiter({ maxLimit: 128 })
136
324
  .header("authorization", `Bearer ${token}`)
137
325
  .cache({ ttlSeconds: 30, maxEntries: 512 })
@@ -270,6 +458,62 @@ HTTP client observability automatically reads adaptive limiter diagnostics when
270
458
  the wrapped client owns a limiter, exposing gauges for current limit, queue
271
459
  depth, utilization, error rate, request/completion rate, rejection rate, and
272
460
  state count.
461
+ It also reads `req.policy` automatically: logs and span attributes include
462
+ `preset`, `lane`, `poolKey`, `dedupKey`, `priority`, and retry overrides when present.
463
+ Metric labels stay conservative by default; opt into stable labels with
464
+ `withHttpObservability({ policy: { labelKeys: ["preset", "lane", "poolKey"] } })`.
465
+
466
+ ### Performance profiler
467
+
468
+ ```bash
469
+ npm run perf
470
+ npm run perf:json
471
+ npm run benchmark:perf
472
+ npm run perf:runtime:ab
473
+ npm run perf:runtime:soak
474
+ npm run perf:runtime:budget
475
+ npm run perf:http:memory
476
+ npm run perf:history
477
+ ```
478
+
479
+ ```ts
480
+ import { runBrassPerformanceProfile } from "brass-runtime/perf";
481
+
482
+ const report = await runBrassPerformanceProfile({
483
+ http: {
484
+ calls: 20_000,
485
+ concurrency: 512,
486
+ delayMs: 2,
487
+ forceGc: true,
488
+ variants: ["default-json", "default-json-observed"],
489
+ },
490
+ });
491
+
492
+ console.log(report.recommendations);
493
+ ```
494
+
495
+ The profiler compares runtime primitives, runtime A/B variants, runtime-only
496
+ soak behavior, `node:http`, Brass wire/default HTTP clients, HTTP long-run
497
+ memory, observability overhead, history/baseline regressions, and memory deltas. Use
498
+ [`docs/performance-profiler.md`](docs/performance-profiler.md) for focused
499
+ commands and `node --expose-gc` runs.
500
+
501
+ Perf runs can be persisted and compared locally:
502
+
503
+ ```bash
504
+ npm run perf -- --profile runtime-ab --record-history --save-baseline runtime-main
505
+ npm run perf -- --profile runtime-ab --compare-baseline runtime-main --fail-on-baseline-regression
506
+ ```
507
+
508
+ ### First-release recipes
509
+
510
+ Copyable happy paths live in [`docs/recipes`](docs/recipes/README.md):
511
+
512
+ - runtime execution
513
+ - typed layers
514
+ - HTTP server
515
+ - testing
516
+ - performance baselines
273
517
 
274
518
  ### Structured concurrency
275
519
 
@@ -289,12 +533,13 @@ await runtime.toPromise(
289
533
  ### Streams
290
534
 
291
535
  ```ts
292
- import { Runtime, collectStream, fromArray, mapP, via } from "brass-runtime";
536
+ import { Runtime, Stream } from "brass-runtime";
293
537
 
294
538
  const runtime = Runtime.make({});
295
- const numbers = fromArray([1, 2, 3, 4, 5]);
296
- const doubled = via(numbers, mapP((n: number) => n * 2));
297
- const result = await runtime.toPromise(collectStream(doubled));
539
+ const result = await Stream
540
+ .from([1, 2, 3, 4, 5])
541
+ .map((n) => n * 2)
542
+ .collect(runtime);
298
543
  // [2, 4, 6, 8, 10]
299
544
  ```
300
545
 
@@ -310,6 +555,7 @@ const result = await runtime.toPromise(collectStream(doubled));
310
555
  | `brass-runtime/http/testing` | Dependency-free mock clients, mock fetch, response factories, and effect runner helpers |
311
556
  | `brass-runtime/schema` | Dependency-free runtime schema DSL with type inference |
312
557
  | `brass-runtime/observability` | Prometheus/OTLP exporters, logs, spans, trace propagation, request adapters |
558
+ | `brass-runtime/perf` | Runtime, HTTP, observability, memory, and baseline performance profiler |
313
559
  | `brass-runtime/agent` | Brass Agent core (experimental) |
314
560
 
315
561
  CLI: `brass-agent`
@@ -346,6 +592,8 @@ All layers emit lifecycle events, track stats, and support cancellation.
346
592
  The recommended `makeDefaultHttpClient` factory wires the default preset
347
593
  for you and accepts extra middleware, so observability can be attached with
348
594
  `middleware: [withHttpObservability(obs)]` without coupling HTTP to exporters.
595
+ Per-request `policy` travels through that stack and is visible to observability
596
+ without being forwarded to the host transport.
349
597
 
350
598
  ---
351
599
 
@@ -388,7 +636,14 @@ Docs: [Install](./docs/agent-install-and-configure.md) · [CLI](./docs/agent-cli
388
636
  npm test # vitest suite
389
637
  npm run test:types # TypeScript type checking
390
638
  npm run test:coverage # coverage with baseline gate
639
+ npm run release:check # full release gate: types, tests, build, CJS, perf budgets
391
640
  npm run benchmark # runtime, HTTP lifecycle, and 100k local HTTP concurrency
641
+ npm run benchmark:runtime # Runtime Performance Track
642
+ npm run benchmark:runtime:budget # Runtime Performance Track regression budget
643
+ npm run perf:runtime:ab # Runtime A/B Performance Lab
644
+ npm run perf:runtime:soak # Runtime-only soak profile
645
+ npm run perf:runtime:budget # Runtime profiler budget
646
+ npm run perf:http:memory # HTTP long-run memory lab
392
647
  npm run benchmark -- http-concurrent # HTTP compare mode variants
393
648
  node --expose-gc --import tsx src/benchmarks/runner.ts http-concurrent # HTTP memory/limiter diagnostics
394
649
  npm run benchmark:adaptive
@@ -426,10 +681,16 @@ Property-based tests use `fast-check` with 100+ iterations per property. Each HT
426
681
 
427
682
  - [x] Sync effect values via `ZIO<R, E, A>` aliases
428
683
  - [x] Algebraic async: `Async<R, E, A>`
684
+ - [x] Rich `Cause<E>` failure trees with pretty printing
685
+ - [x] Interruptibility regions with `uninterruptible` / `uninterruptibleMask`
686
+ - [x] Fiber-local refs with fork inheritance and scoped restoration
687
+ - [x] TS TestRuntime with deterministic scheduler and virtual clock
688
+ - [x] Schedule 2.0 with drivers, runtime-clock budgets, observability, and HTTP integration
429
689
  - [x] Cooperative scheduler (observable, testable)
430
690
  - [x] Fibers with interruption & finalizers
431
691
  - [x] Structured scopes & resource safety
432
- - [x] Layers, semaphores, circuit breakers
692
+ - [x] Runtime flight recorder for bounded execution traces
693
+ - [x] Layer 2.0 typed contexts, semaphores, circuit breakers
433
694
  - [x] Metrics, tracing, runtime hooks
434
695
  - [x] Worker pools
435
696
  - [x] WASM engine (optional)
@@ -437,6 +698,7 @@ Property-based tests use `fast-check` with 100+ iterations per property. Each HT
437
698
  ### Streams
438
699
 
439
700
  - [x] Pull-based streams with backpressure
701
+ - [x] Fluent `Stream` / `Pipeline` DX facade
440
702
  - [x] Bounded buffers, queues, hubs
441
703
  - [x] Pipelines with fusion optimization
442
704
  - [x] Stream merge, zip, broadcast
@@ -445,6 +707,9 @@ Property-based tests use `fast-check` with 100+ iterations per property. Each HT
445
707
  ### HTTP
446
708
 
447
709
  - [x] Lazy, cancelable HTTP client
710
+ - [x] Effect-based Node HTTP server listener with resource lifecycle
711
+ - [x] Declarative typed routing with params/query/body/response schemas
712
+ - [x] Health/readiness routes backed by runtime health reports
448
713
  - [x] Schema-validated JSON helpers
449
714
  - [x] Discoverable builder API
450
715
  - [x] Test helper subpath
@@ -17,18 +17,18 @@
17
17
 
18
18
 
19
19
 
20
- var _chunkN6VHMOWBcjs = require('../../chunk-N6VHMOWB.cjs');
21
- require('../../chunk-NYL4D7SK.cjs');
22
- require('../../chunk-TVN5I4U6.cjs');
20
+ var _chunk4ROBZFL6cjs = require('../../chunk-4ROBZFL6.cjs');
21
+ require('../../chunk-SA6HUJVI.cjs');
22
+ require('../../chunk-JF5WGYJJ.cjs');
23
23
 
24
24
 
25
- var _chunkWQ5QNU5Rcjs = require('../../chunk-WQ5QNU5R.cjs');
25
+ var _chunkGLE2WY7Zcjs = require('../../chunk-GLE2WY7Z.cjs');
26
26
 
27
27
 
28
28
 
29
29
 
30
- var _chunkDJQ7OMMBcjs = require('../../chunk-DJQ7OMMB.cjs');
31
- require('../../chunk-SPUEME2B.cjs');
30
+ var _chunkMVGUEJ5Zcjs = require('../../chunk-MVGUEJ5Z.cjs');
31
+ require('../../chunk-CZIVE6NT.cjs');
32
32
  require('../../chunk-OBGZSXTJ.cjs');
33
33
 
34
34
  // src/agent/cli/approvals.ts
@@ -45,7 +45,7 @@ var answerToResponse = (answer, request) => {
45
45
  return { type: "rejected", reason: `Unrecognized approval answer: ${answer}` };
46
46
  };
47
47
  var makeCliApprovalService = (options = {}) => ({
48
- request: (request) => _chunkDJQ7OMMBcjs.asyncEffect.call(void 0, (_env, cb) => {
48
+ request: (request) => _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (_env, cb) => {
49
49
  let closed = false;
50
50
  let rl;
51
51
  dynamicImport("node:readline/promises").then(({ createInterface }) => {
@@ -57,7 +57,7 @@ var makeCliApprovalService = (options = {}) => ({
57
57
  _optionalChain([output, 'optionalAccess', _ => _.write, 'optionalCall', _2 => _2(`
58
58
  Approval required (${request.risk})
59
59
  `)]);
60
- _optionalChain([output, 'optionalAccess', _3 => _3.write, 'optionalCall', _4 => _4(`Action: ${_chunkN6VHMOWBcjs.summarizeAgentAction.call(void 0, request.action)}
60
+ _optionalChain([output, 'optionalAccess', _3 => _3.write, 'optionalCall', _4 => _4(`Action: ${_chunk4ROBZFL6cjs.summarizeAgentAction.call(void 0, request.action)}
61
61
  `)]);
62
62
  _optionalChain([output, 'optionalAccess', _5 => _5.write, 'optionalCall', _6 => _6(`Reason: ${request.reason}
63
63
  `)]);
@@ -66,14 +66,14 @@ Approval required (${request.risk})
66
66
  if (answer === void 0 || closed) return;
67
67
  closed = true;
68
68
  _optionalChain([rl, 'optionalAccess', _7 => _7.close, 'optionalCall', _8 => _8()]);
69
- cb(_chunkDJQ7OMMBcjs.Exit.succeed(answerToResponse(answer, request)));
69
+ cb(_chunkMVGUEJ5Zcjs.Exit.succeed(answerToResponse(answer, request)));
70
70
  }).catch((cause) => {
71
71
  if (closed) return;
72
72
  closed = true;
73
73
  _optionalChain([rl, 'optionalAccess', _9 => _9.close, 'optionalCall', _10 => _10()]);
74
74
  cb(
75
- _chunkDJQ7OMMBcjs.Exit.failCause(
76
- _chunkDJQ7OMMBcjs.Cause.fail({
75
+ _chunkMVGUEJ5Zcjs.Exit.failCause(
76
+ _chunkMVGUEJ5Zcjs.Cause.fail({
77
77
  _tag: "AgentLoopError",
78
78
  message: `Approval prompt failed: ${String(cause)}`
79
79
  })
@@ -1104,7 +1104,7 @@ var parseCliArgs = (argv) => {
1104
1104
  }
1105
1105
  if (arg === "--preset" || arg.startsWith("--preset=")) {
1106
1106
  const [value, nextIndex] = readFlagValue(argv, index, "--preset");
1107
- if (!_chunkN6VHMOWBcjs.isAgentPreset.call(void 0, value)) {
1107
+ if (!_chunk4ROBZFL6cjs.isAgentPreset.call(void 0, value)) {
1108
1108
  throw new Error("--preset requires one of: fix-tests, inspect, typecheck, lint");
1109
1109
  }
1110
1110
  preset = value;
@@ -1280,7 +1280,7 @@ var parseBatchGoal = (value, path) => {
1280
1280
  if (cwd !== void 0 && typeof cwd !== "string") throw new Error(`${path}.cwd must be a string.`);
1281
1281
  if (patchFile !== void 0 && typeof patchFile !== "string") throw new Error(`${path}.patchFile must be a string.`);
1282
1282
  if (saveRunDir !== void 0 && typeof saveRunDir !== "string") throw new Error(`${path}.saveRunDir must be a string.`);
1283
- if (preset !== void 0 && (typeof preset !== "string" || !_chunkN6VHMOWBcjs.isAgentPreset.call(void 0, preset))) {
1283
+ if (preset !== void 0 && (typeof preset !== "string" || !_chunk4ROBZFL6cjs.isAgentPreset.call(void 0, preset))) {
1284
1284
  throw new Error(`${path}.preset must be one of: fix-tests, inspect, typecheck, lint.`);
1285
1285
  }
1286
1286
  if (mode !== void 0 && (typeof mode !== "string" || !isAgentMode(mode))) {
@@ -1324,7 +1324,7 @@ var readBatchFile = async (cwd, batchFile) => {
1324
1324
  var resolveBatchGoalText = (item, fallbackPatchFile) => {
1325
1325
  if (typeof item === "string") return item;
1326
1326
  if (item.goal) return item.goal;
1327
- if (item.preset) return _chunkN6VHMOWBcjs.goalForAgentPreset.call(void 0, item.preset);
1327
+ if (item.preset) return _chunk4ROBZFL6cjs.goalForAgentPreset.call(void 0, item.preset);
1328
1328
  if (_nullishCoalesce(item.patchFile, () => ( fallbackPatchFile))) return "apply supplied patch";
1329
1329
  return "";
1330
1330
  };
@@ -1351,7 +1351,7 @@ var resolveBatchRuns = (items, parsed, config) => items.map((item, index) => {
1351
1351
  };
1352
1352
  });
1353
1353
  var resolveParsedConfig = async (parsed) => {
1354
- const workspaceDiscovery = _chunkN6VHMOWBcjs.discoverNodeWorkspaceRoot.call(void 0, parsed.cwd, {
1354
+ const workspaceDiscovery = _chunk4ROBZFL6cjs.discoverNodeWorkspaceRoot.call(void 0, parsed.cwd, {
1355
1355
  enabled: parsed.discoverWorkspace
1356
1356
  });
1357
1357
  const cwdResolved = workspaceDiscovery.cwd;
@@ -1359,7 +1359,7 @@ var resolveParsedConfig = async (parsed) => {
1359
1359
  ...parsed,
1360
1360
  cwd: cwdResolved
1361
1361
  };
1362
- const loaded = await _chunkN6VHMOWBcjs.loadNodeAgentConfig.call(void 0, {
1362
+ const loaded = await _chunk4ROBZFL6cjs.loadNodeAgentConfig.call(void 0, {
1363
1363
  cwd: cwdResolved,
1364
1364
  configPath: parsed.configPath,
1365
1365
  noConfig: parsed.noConfig
@@ -1375,7 +1375,7 @@ var resolveParsedConfig = async (parsed) => {
1375
1375
  const batchRuns = resolveBatchRuns(batchItems, parsedAtWorkspace, loaded.config);
1376
1376
  return {
1377
1377
  ...parsedAtWorkspace,
1378
- goalText: parsed.goalText || (parsed.preset ? _chunkN6VHMOWBcjs.goalForAgentPreset.call(void 0, parsed.preset) : parsed.patchFile ? "apply supplied patch" : parsed.goalText),
1378
+ goalText: parsed.goalText || (parsed.preset ? _chunk4ROBZFL6cjs.goalForAgentPreset.call(void 0, parsed.preset) : parsed.patchFile ? "apply supplied patch" : parsed.goalText),
1379
1379
  mode: parsed.modeSpecified ? parsed.mode : parsed.preset === "inspect" ? "read-only" : _nullishCoalesce(loaded.config.mode, () => ( parsed.mode)),
1380
1380
  approval: parsed.approvalSpecified ? parsed.approval : _nullishCoalesce(loaded.config.approval, () => ( parsed.approval)),
1381
1381
  config: loaded.config,
@@ -1499,7 +1499,7 @@ var envByName = (name) => name ? process.env[name] : void 0;
1499
1499
  var makeGoogleLLMFromEnv = (config) => {
1500
1500
  const apiKey = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(envByName(_optionalChain([config, 'optionalAccess', _39 => _39.apiKeyEnv])), () => ( process.env.BRASS_GOOGLE_API_KEY)), () => ( process.env.GOOGLE_API_KEY)), () => ( process.env.GEMINI_API_KEY));
1501
1501
  if (!apiKey) return void 0;
1502
- return _chunkN6VHMOWBcjs.makeGoogleGenerativeAILLM.call(void 0, {
1502
+ return _chunk4ROBZFL6cjs.makeGoogleGenerativeAILLM.call(void 0, {
1503
1503
  apiKey,
1504
1504
  model: _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(process.env.BRASS_GOOGLE_MODEL, () => ( process.env.BRASS_LLM_MODEL)), () => ( _optionalChain([config, 'optionalAccess', _40 => _40.model]))), () => ( "gemini-2.5-flash")),
1505
1505
  apiVersion: _nullishCoalesce(_nullishCoalesce(process.env.BRASS_GOOGLE_API_VERSION, () => ( _optionalChain([config, 'optionalAccess', _41 => _41.apiVersion]))), () => ( "v1beta")),
@@ -1517,12 +1517,12 @@ var makeOpenAICompatibleLLMFromEnv = (config) => {
1517
1517
  const apiKey = _nullishCoalesce(envByName(_optionalChain([config, 'optionalAccess', _50 => _50.apiKeyEnv])), () => ( process.env.BRASS_LLM_API_KEY));
1518
1518
  const model = _nullishCoalesce(_nullishCoalesce(process.env.BRASS_LLM_MODEL, () => ( _optionalChain([config, 'optionalAccess', _51 => _51.model]))), () => ( "gpt-4.1"));
1519
1519
  if (!endpoint || !apiKey) return void 0;
1520
- return _chunkN6VHMOWBcjs.makeOpenAICompatibleLLM.call(void 0, { endpoint, apiKey, model });
1520
+ return _chunk4ROBZFL6cjs.makeOpenAICompatibleLLM.call(void 0, { endpoint, apiKey, model });
1521
1521
  };
1522
1522
  var makeLLMFromEnv = (config) => {
1523
1523
  const provider = _optionalChain([(_nullishCoalesce(process.env.BRASS_LLM_PROVIDER, () => ( _optionalChain([config, 'optionalAccess', _52 => _52.provider])))), 'optionalAccess', _53 => _53.trim, 'call', _54 => _54(), 'access', _55 => _55.toLowerCase, 'call', _56 => _56()]);
1524
1524
  const fakeResponse = _nullishCoalesce(process.env.BRASS_FAKE_LLM_RESPONSE, () => ( _optionalChain([config, 'optionalAccess', _57 => _57.fakeResponse])));
1525
- if (provider === "fake") return _chunkN6VHMOWBcjs.makeFakeLLM.call(void 0, { content: fakeResponse });
1525
+ if (provider === "fake") return _chunk4ROBZFL6cjs.makeFakeLLM.call(void 0, { content: fakeResponse });
1526
1526
  if (provider === "google" || provider === "gemini") {
1527
1527
  const google = makeGoogleLLMFromEnv(config);
1528
1528
  if (!google) {
@@ -1544,7 +1544,7 @@ var makeLLMFromEnv = (config) => {
1544
1544
  if (provider) {
1545
1545
  throw new Error(`Unsupported LLM provider: ${provider}`);
1546
1546
  }
1547
- return _nullishCoalesce(_nullishCoalesce(makeGoogleLLMFromEnv(config), () => ( makeOpenAICompatibleLLMFromEnv(config))), () => ( _chunkN6VHMOWBcjs.makeFakeLLM.call(void 0, { content: fakeResponse })));
1547
+ return _nullishCoalesce(_nullishCoalesce(makeGoogleLLMFromEnv(config), () => ( makeOpenAICompatibleLLMFromEnv(config))), () => ( _chunk4ROBZFL6cjs.makeFakeLLM.call(void 0, { content: fakeResponse })));
1548
1548
  };
1549
1549
  var parseApprovalModeFromEnv = () => {
1550
1550
  const raw = _optionalChain([process, 'access', _58 => _58.env, 'access', _59 => _59.BRASS_AGENT_APPROVAL, 'optionalAccess', _60 => _60.trim, 'call', _61 => _61(), 'access', _62 => _62.toLowerCase, 'call', _63 => _63()]);
@@ -1567,9 +1567,9 @@ var makeApprovalServiceFromCli = (parsed) => {
1567
1567
  const mode = resolveApprovalMode(parsed);
1568
1568
  switch (mode) {
1569
1569
  case "approve":
1570
- return _chunkN6VHMOWBcjs.autoApproveApprovals;
1570
+ return _chunk4ROBZFL6cjs.autoApproveApprovals;
1571
1571
  case "deny":
1572
- return _chunkN6VHMOWBcjs.makeAutoDenyApprovals.call(void 0, "Approval rejected because the CLI is running without interactive input. Use --yes to auto-approve.");
1572
+ return _chunk4ROBZFL6cjs.makeAutoDenyApprovals.call(void 0, "Approval rejected because the CLI is running without interactive input. Use --yes to auto-approve.");
1573
1573
  case "interactive":
1574
1574
  return makeCliApprovalService();
1575
1575
  }
@@ -1701,32 +1701,32 @@ var createHumanEventSink = (configPath) => ({
1701
1701
  console.log("");
1702
1702
  break;
1703
1703
  case "agent.action.started":
1704
- console.log(`\u2192 ${_chunkN6VHMOWBcjs.summarizeAgentAction.call(void 0, event.action)}`);
1704
+ console.log(`\u2192 ${_chunk4ROBZFL6cjs.summarizeAgentAction.call(void 0, event.action)}`);
1705
1705
  break;
1706
1706
  case "agent.action.completed": {
1707
- const status = _chunkN6VHMOWBcjs.observationStatus.call(void 0, event.observation);
1708
- console.log(`${statusIcon2(status)} ${_chunkN6VHMOWBcjs.summarizeAgentObservation.call(void 0, event.observation)} ${formatDuration(event.durationMs)}`);
1707
+ const status = _chunk4ROBZFL6cjs.observationStatus.call(void 0, event.observation);
1708
+ console.log(`${statusIcon2(status)} ${_chunk4ROBZFL6cjs.summarizeAgentObservation.call(void 0, event.observation)} ${formatDuration(event.durationMs)}`);
1709
1709
  break;
1710
1710
  }
1711
1711
  case "agent.action.failed":
1712
1712
  if (event.error._tag !== "ToolTimeout" && event.error._tag !== "PermissionDenied" && event.error._tag !== "ApprovalRejected") {
1713
- console.log(`\u2717 ${_chunkN6VHMOWBcjs.summarizeAgentAction.call(void 0, event.action)} failed with ${event.error._tag} ${formatDuration(event.durationMs)}`);
1713
+ console.log(`\u2717 ${_chunk4ROBZFL6cjs.summarizeAgentAction.call(void 0, event.action)} failed with ${event.error._tag} ${formatDuration(event.durationMs)}`);
1714
1714
  }
1715
1715
  break;
1716
1716
  case "agent.tool.timeout":
1717
- console.log(`! ${_chunkN6VHMOWBcjs.summarizeAgentAction.call(void 0, event.action)} timed out after ${event.timeoutMs}ms`);
1717
+ console.log(`! ${_chunk4ROBZFL6cjs.summarizeAgentAction.call(void 0, event.action)} timed out after ${event.timeoutMs}ms`);
1718
1718
  break;
1719
1719
  case "agent.permission.denied":
1720
- console.log(`\u2717 ${_chunkN6VHMOWBcjs.summarizeAgentAction.call(void 0, event.action)} denied: ${event.reason}`);
1720
+ console.log(`\u2717 ${_chunk4ROBZFL6cjs.summarizeAgentAction.call(void 0, event.action)} denied: ${event.reason}`);
1721
1721
  break;
1722
1722
  case "agent.approval.requested":
1723
- console.log(`? approval required for ${_chunkN6VHMOWBcjs.summarizeAgentAction.call(void 0, event.action)} (${event.risk})`);
1723
+ console.log(`? approval required for ${_chunk4ROBZFL6cjs.summarizeAgentAction.call(void 0, event.action)} (${event.risk})`);
1724
1724
  break;
1725
1725
  case "agent.approval.resolved":
1726
1726
  if (event.approved) {
1727
- console.log(`\u2713 approval granted for ${_chunkN6VHMOWBcjs.summarizeAgentAction.call(void 0, event.action)}`);
1727
+ console.log(`\u2713 approval granted for ${_chunk4ROBZFL6cjs.summarizeAgentAction.call(void 0, event.action)}`);
1728
1728
  } else {
1729
- console.log(`\u2717 approval rejected for ${_chunkN6VHMOWBcjs.summarizeAgentAction.call(void 0, event.action)}${event.reason ? `: ${event.reason}` : ""}`);
1729
+ console.log(`\u2717 approval rejected for ${_chunk4ROBZFL6cjs.summarizeAgentAction.call(void 0, event.action)}${event.reason ? `: ${event.reason}` : ""}`);
1730
1730
  }
1731
1731
  break;
1732
1732
  case "agent.patch.applied":
@@ -1831,13 +1831,13 @@ var printHumanFinalSummary = (state) => {
1831
1831
  };
1832
1832
  var makeEventsSink = (parsed, compactOptions) => parsed.output === "human" ? createHumanEventSink(parsed.resolvedConfigPath) : parsed.output === "events-json" ? createJsonEventSink(compactOptions) : parsed.output === "protocol-json" ? createProtocolEventSink(compactOptions) : void 0;
1833
1833
  var makeAgentEnv = (parsed, events) => {
1834
- const shell = _chunkN6VHMOWBcjs.NodeShell;
1834
+ const shell = _chunk4ROBZFL6cjs.NodeShell;
1835
1835
  return {
1836
1836
  shell,
1837
- fs: _chunkN6VHMOWBcjs.makeNodeFileSystem.call(void 0, shell),
1838
- patch: _chunkN6VHMOWBcjs.makeNodePatchService.call(void 0, shell),
1837
+ fs: _chunk4ROBZFL6cjs.makeNodeFileSystem.call(void 0, shell),
1838
+ patch: _chunk4ROBZFL6cjs.makeNodePatchService.call(void 0, shell),
1839
1839
  llm: makeLLMFromEnv(parsed.config.llm),
1840
- permissions: _chunkN6VHMOWBcjs.makeConfiguredPermissions.call(void 0, parsed.config.permissions),
1840
+ permissions: _chunk4ROBZFL6cjs.makeConfiguredPermissions.call(void 0, parsed.config.permissions),
1841
1841
  approvals: makeApprovalServiceFromCli(parsed),
1842
1842
  ...events ? { events } : {},
1843
1843
  ...parsed.config.tools ? { toolPolicies: parsed.config.tools } : {}
@@ -1854,10 +1854,10 @@ var singleRunFromParsed = (parsed) => ({
1854
1854
  });
1855
1855
  var runCliAgent = async (parsed, run, compactOptions, events) => {
1856
1856
  const env = makeAgentEnv(parsed, events);
1857
- const runtime = new (0, _chunkWQ5QNU5Rcjs.Runtime)({ env });
1857
+ const runtime = new (0, _chunkGLE2WY7Zcjs.Runtime)({ env });
1858
1858
  const initialPatch = run.patchFile ? await readPatchFile(run.cwd, run.patchFile) : void 0;
1859
1859
  const state = await runtime.toPromise(
1860
- _chunkN6VHMOWBcjs.runAgent.call(void 0, runtime, {
1860
+ _chunk4ROBZFL6cjs.runAgent.call(void 0, runtime, {
1861
1861
  id: `agent-${Date.now()}-${run.index + 1}`,
1862
1862
  cwd: run.cwd,
1863
1863
  text: run.goalText,