@warmdrift/kgauto-compiler 2.0.0-alpha.16 → 2.0.0-alpha.17

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.
@@ -0,0 +1,298 @@
1
+ // src/glassbox/types.ts
2
+ var GLASSBOX_STREAM_TTL_MS = 6e4;
3
+
4
+ // src/glassbox/pubsub-memory.ts
5
+ var MemoryPubSub = class {
6
+ subscribers = /* @__PURE__ */ new Map();
7
+ async publish(traceId, event) {
8
+ const subs = this.subscribers.get(traceId);
9
+ if (!subs || subs.size === 0) return;
10
+ for (const sub of subs) {
11
+ if (sub.closed) continue;
12
+ try {
13
+ sub.controller.enqueue(event);
14
+ } catch {
15
+ sub.closed = true;
16
+ continue;
17
+ }
18
+ this.refreshTtl(traceId, sub);
19
+ }
20
+ }
21
+ subscribe(traceId) {
22
+ const self = this;
23
+ let sub;
24
+ return new ReadableStream({
25
+ start(controller) {
26
+ sub = {
27
+ controller,
28
+ ttlTimer: setTimeout(() => {
29
+ self.closeSubscriber(traceId, sub);
30
+ }, GLASSBOX_STREAM_TTL_MS),
31
+ closed: false
32
+ };
33
+ let set = self.subscribers.get(traceId);
34
+ if (!set) {
35
+ set = /* @__PURE__ */ new Set();
36
+ self.subscribers.set(traceId, set);
37
+ }
38
+ set.add(sub);
39
+ },
40
+ cancel() {
41
+ if (sub) self.removeSubscriber(traceId, sub);
42
+ }
43
+ });
44
+ }
45
+ /**
46
+ * Refresh the rolling TTL for a subscriber after an event lands. Replaces
47
+ * the existing timer with a fresh 60s one.
48
+ */
49
+ refreshTtl(traceId, sub) {
50
+ clearTimeout(sub.ttlTimer);
51
+ sub.ttlTimer = setTimeout(() => {
52
+ this.closeSubscriber(traceId, sub);
53
+ }, GLASSBOX_STREAM_TTL_MS);
54
+ }
55
+ /**
56
+ * Close the subscriber's stream cleanly and remove from the fan-out set.
57
+ * Idempotent — safe to call multiple times.
58
+ */
59
+ closeSubscriber(traceId, sub) {
60
+ if (sub.closed) return;
61
+ sub.closed = true;
62
+ clearTimeout(sub.ttlTimer);
63
+ try {
64
+ sub.controller.close();
65
+ } catch {
66
+ }
67
+ this.removeSubscriber(traceId, sub);
68
+ }
69
+ removeSubscriber(traceId, sub) {
70
+ clearTimeout(sub.ttlTimer);
71
+ const set = this.subscribers.get(traceId);
72
+ if (!set) return;
73
+ set.delete(sub);
74
+ if (set.size === 0) this.subscribers.delete(traceId);
75
+ }
76
+ /**
77
+ * Test-only reset. Tears down all subscribers, clears all state. Calling
78
+ * outside of tests is harmless but cancels every active stream.
79
+ */
80
+ _reset() {
81
+ for (const [, set] of this.subscribers) {
82
+ for (const sub of set) {
83
+ this.closeSubscriber("", sub);
84
+ }
85
+ }
86
+ this.subscribers.clear();
87
+ }
88
+ };
89
+
90
+ // src/glassbox/pubsub-upstash.ts
91
+ var UpstashPubSub = class {
92
+ url;
93
+ token;
94
+ fetchImpl;
95
+ blockMs;
96
+ maxLen;
97
+ constructor(cfg) {
98
+ this.url = cfg.url.replace(/\/$/, "");
99
+ this.token = cfg.token;
100
+ this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch.bind(globalThis);
101
+ this.blockMs = cfg.blockMs ?? 100;
102
+ this.maxLen = cfg.maxLen ?? 100;
103
+ }
104
+ async publish(traceId, event) {
105
+ const key = streamKey(traceId);
106
+ const payload = JSON.stringify(event);
107
+ await this.cmd([
108
+ "XADD",
109
+ key,
110
+ "MAXLEN",
111
+ "~",
112
+ String(this.maxLen),
113
+ "*",
114
+ "event",
115
+ payload
116
+ ]);
117
+ await this.cmd(["EXPIRE", key, String(Math.ceil(GLASSBOX_STREAM_TTL_MS / 1e3))]);
118
+ }
119
+ subscribe(traceId) {
120
+ const key = streamKey(traceId);
121
+ const self = this;
122
+ let cursor = "$";
123
+ let cancelled = false;
124
+ let ttlDeadline = Date.now() + GLASSBOX_STREAM_TTL_MS;
125
+ return new ReadableStream({
126
+ async start(controller) {
127
+ try {
128
+ while (!cancelled && Date.now() < ttlDeadline) {
129
+ const resp = await self.cmd([
130
+ "XREAD",
131
+ "BLOCK",
132
+ String(self.blockMs),
133
+ "STREAMS",
134
+ key,
135
+ cursor
136
+ ]);
137
+ if (cancelled) break;
138
+ const parsed = parseXReadResult(resp.result);
139
+ if (parsed.entries.length === 0) {
140
+ continue;
141
+ }
142
+ for (const entry of parsed.entries) {
143
+ const evt = decodeEvent(entry.fields);
144
+ if (evt) {
145
+ try {
146
+ controller.enqueue(evt);
147
+ } catch {
148
+ cancelled = true;
149
+ break;
150
+ }
151
+ }
152
+ cursor = entry.id;
153
+ }
154
+ ttlDeadline = Date.now() + GLASSBOX_STREAM_TTL_MS;
155
+ }
156
+ } catch (err) {
157
+ if (!cancelled) {
158
+ try {
159
+ controller.error(err);
160
+ } catch {
161
+ }
162
+ return;
163
+ }
164
+ }
165
+ try {
166
+ controller.close();
167
+ } catch {
168
+ }
169
+ },
170
+ cancel() {
171
+ cancelled = true;
172
+ }
173
+ });
174
+ }
175
+ async cmd(args) {
176
+ const res = await this.fetchImpl(this.url, {
177
+ method: "POST",
178
+ headers: {
179
+ Authorization: `Bearer ${this.token}`,
180
+ "Content-Type": "application/json"
181
+ },
182
+ body: JSON.stringify(args)
183
+ });
184
+ if (!res.ok) {
185
+ throw new Error(`Upstash ${args[0]} failed: HTTP ${res.status}`);
186
+ }
187
+ const json = await res.json();
188
+ if (json.error) {
189
+ throw new Error(`Upstash ${args[0]} failed: ${json.error}`);
190
+ }
191
+ return json;
192
+ }
193
+ };
194
+ function streamKey(traceId) {
195
+ return `glassbox:trace:${traceId}`;
196
+ }
197
+ function decodeEvent(fields) {
198
+ const raw = fields["event"];
199
+ if (!raw) return void 0;
200
+ try {
201
+ const parsed = JSON.parse(raw);
202
+ if (typeof parsed.kind === "string" && typeof parsed.at === "number") {
203
+ return parsed;
204
+ }
205
+ return void 0;
206
+ } catch {
207
+ return void 0;
208
+ }
209
+ }
210
+ function parseXReadResult(raw) {
211
+ if (!Array.isArray(raw)) return { entries: [] };
212
+ const entries = [];
213
+ for (const stream of raw) {
214
+ if (!Array.isArray(stream) || stream.length < 2) continue;
215
+ const streamEntries = stream[1];
216
+ if (!Array.isArray(streamEntries)) continue;
217
+ for (const entry of streamEntries) {
218
+ if (!Array.isArray(entry) || entry.length < 2) continue;
219
+ const id = String(entry[0]);
220
+ const flat = entry[1];
221
+ if (!Array.isArray(flat)) continue;
222
+ const fields = {};
223
+ for (let i = 0; i < flat.length; i += 2) {
224
+ const k = flat[i];
225
+ const v = flat[i + 1];
226
+ if (typeof k === "string") fields[k] = String(v ?? "");
227
+ }
228
+ entries.push({ id, fields });
229
+ }
230
+ }
231
+ return { entries };
232
+ }
233
+
234
+ // src/glassbox/emit.ts
235
+ var activePubSub;
236
+ function getPubSub() {
237
+ if (activePubSub) return activePubSub;
238
+ const url = readEnv("UPSTASH_REDIS_URL");
239
+ const token = readEnv("UPSTASH_REDIS_TOKEN");
240
+ if (url && token) {
241
+ activePubSub = new UpstashPubSub({ url, token });
242
+ } else {
243
+ activePubSub = new MemoryPubSub();
244
+ }
245
+ return activePubSub;
246
+ }
247
+ function readEnv(key) {
248
+ try {
249
+ if (typeof process !== "undefined" && process.env) {
250
+ const v = process.env[key];
251
+ return v && v.trim() !== "" ? v : void 0;
252
+ }
253
+ } catch {
254
+ }
255
+ return void 0;
256
+ }
257
+ function emitGlassboxEvent(traceId, kind, data) {
258
+ if (!traceId) return;
259
+ const event = { kind, at: Date.now(), data };
260
+ const ps = getPubSub();
261
+ try {
262
+ const p = ps.publish(traceId, event);
263
+ if (p && typeof p.then === "function") {
264
+ p.catch(() => {
265
+ });
266
+ }
267
+ } catch {
268
+ }
269
+ }
270
+ function emitCompileStart(traceId, data) {
271
+ emitGlassboxEvent(traceId, "compile.start", data);
272
+ }
273
+ function emitCompileDone(traceId, data) {
274
+ emitGlassboxEvent(traceId, "compile.done", data);
275
+ }
276
+ function emitExecuteAttempt(traceId, data) {
277
+ emitGlassboxEvent(traceId, "execute.attempt", data);
278
+ }
279
+ function emitExecuteSuccess(traceId, data) {
280
+ emitGlassboxEvent(traceId, "execute.success", data);
281
+ }
282
+ function emitAdvisoryFired(traceId, data) {
283
+ emitGlassboxEvent(traceId, "advisory.fired", data);
284
+ }
285
+ function emitFallbackWalked(traceId, data) {
286
+ emitGlassboxEvent(traceId, "fallback.walked", data);
287
+ }
288
+
289
+ export {
290
+ GLASSBOX_STREAM_TTL_MS,
291
+ getPubSub,
292
+ emitCompileStart,
293
+ emitCompileDone,
294
+ emitExecuteAttempt,
295
+ emitExecuteSuccess,
296
+ emitAdvisoryFired,
297
+ emitFallbackWalked
298
+ };
@@ -0,0 +1,159 @@
1
+ import { j as MutationApplied, B as BestPracticeAdvisory, F as FallbackReason, g as CallAttempt } from '../ir-C3P4gDt0.mjs';
2
+ import '../dialect.mjs';
3
+
4
+ /**
5
+ * Glass-Box observability types (alpha.17).
6
+ *
7
+ * The substrate for kgauto's in-flight observability surface — a Chrome MV3
8
+ * side panel that renders compile + execute + advisor outputs in real-time.
9
+ * See design doc:
10
+ * ~/.gstack/projects/stue-kgauto/stgreen-claude-serene-williamson-51a105-design-20260518-175356.md
11
+ *
12
+ * Wire shape is intentionally minimal:
13
+ * { kind, at, data } — discriminated union by `kind`.
14
+ *
15
+ * Critical-path safety (L-086 derived): emit MUST NEVER fail the user's
16
+ * `call()` invocation. emit.ts wraps every adapter write in try/catch +
17
+ * silently drops on error. Consumers in Vercel Edge runtimes can lose one
18
+ * event without losing the response.
19
+ */
20
+
21
+ /**
22
+ * Discriminator. Six event kinds cover the v1 substrate. New kinds added
23
+ * additively; the side-panel renderer treats unknown kinds as "ignore".
24
+ */
25
+ type GlassboxEventKind = 'compile.start' | 'compile.done' | 'execute.attempt' | 'execute.success' | 'advisory.fired' | 'fallback.walked';
26
+ /**
27
+ * Wire envelope. Every emit lands as one of these.
28
+ *
29
+ * - kind: discriminator
30
+ * - at: unix milliseconds (Date.now())
31
+ * - data: kind-specific payload
32
+ *
33
+ * `data` typed loosely as Record<string, unknown> for serialization-friendliness;
34
+ * the per-kind builders below populate it with the structured shape expected
35
+ * by the renderer. We deliberately do NOT typescript-narrow `data` by kind on
36
+ * the wire type — the side panel reads JSON from SSE and only the renderer
37
+ * needs the narrowed shape. Internal callers (emit.ts) get type assistance via
38
+ * the typed factory helpers in emit.ts.
39
+ */
40
+ interface GlassboxEvent {
41
+ kind: GlassboxEventKind;
42
+ at: number;
43
+ data: Record<string, unknown>;
44
+ }
45
+ /**
46
+ * Per-kind data shapes. Surfaced as type aids; not enforced at the
47
+ * GlassboxEvent boundary (intentionally — see comment above).
48
+ */
49
+ interface CompileStartData {
50
+ appId: string;
51
+ archetype: string;
52
+ models: string[];
53
+ }
54
+ interface CompileDoneData {
55
+ target: string;
56
+ provider: string;
57
+ fallbackChain: string[];
58
+ tokensIn: number;
59
+ estimatedCostUsd: number;
60
+ mutationsApplied: MutationApplied[];
61
+ advisories: BestPracticeAdvisory[];
62
+ }
63
+ interface ExecuteAttemptData {
64
+ model: string;
65
+ attemptIndex: number;
66
+ }
67
+ interface ExecuteSuccessData {
68
+ model: string;
69
+ tokensIn: number;
70
+ tokensOut: number;
71
+ latencyMs: number;
72
+ }
73
+ interface AdvisoryFiredData {
74
+ code: string;
75
+ message: string;
76
+ }
77
+ interface FallbackWalkedData {
78
+ from: string;
79
+ to: string;
80
+ reason: FallbackReason | 'unknown';
81
+ attempt: CallAttempt;
82
+ }
83
+ /**
84
+ * Pub/sub backend interface. Two adapters implement it: in-memory (dev /
85
+ * single-process) and Upstash Redis Streams (Vercel Edge multi-instance).
86
+ *
87
+ * The choice is made at module load (NOT per-call) based on env-var presence:
88
+ * if (UPSTASH_REDIS_URL && UPSTASH_REDIS_TOKEN) → Upstash
89
+ * else → in-memory
90
+ *
91
+ * Stream TTL: 60s after last event. After that, subscriber stream closes
92
+ * cleanly. The adapter owns its own TTL clock; subscribe() is agnostic.
93
+ */
94
+ interface GlassboxPubSub {
95
+ /**
96
+ * Publish a single event for a traceId. Returns a promise that resolves
97
+ * after the event is durably appended (or rejects on adapter failure —
98
+ * callers in emit.ts always swallow rejections).
99
+ */
100
+ publish(traceId: string, event: GlassboxEvent): Promise<void>;
101
+ /**
102
+ * Subscribe to events for a traceId. Returns a ReadableStream that emits
103
+ * GlassboxEvent objects as they're published. The stream closes cleanly
104
+ * after the per-trace TTL elapses since the LAST event (rolling 60s).
105
+ *
106
+ * If the traceId has no publisher within 60s of subscription, the stream
107
+ * closes empty.
108
+ */
109
+ subscribe(traceId: string): ReadableStream<GlassboxEvent>;
110
+ /**
111
+ * Test-only escape hatch. Clears any in-memory state. Upstash adapter
112
+ * no-ops (server-side state isn't accessible from here). Tests reach for
113
+ * this between cases to keep adapters hermetic.
114
+ */
115
+ _reset?(): void;
116
+ }
117
+ /**
118
+ * TTL applied to a stream after each event. The design doc names 60s; this
119
+ * constant centralizes it so both adapters + tests agree.
120
+ */
121
+ declare const GLASSBOX_STREAM_TTL_MS = 60000;
122
+
123
+ /**
124
+ * subscribe(traceId) — public Glass-Box subscription export.
125
+ *
126
+ * Consumer route handlers (e.g. Vercel Edge `/api/glassbox/stream`) import
127
+ * this and bridge the ReadableStream to SSE. The browser-side panel then
128
+ * renders events in real time:
129
+ *
130
+ * import { subscribe } from '@warmdrift/kgauto-compiler/glassbox';
131
+ *
132
+ * export async function GET(req: Request) {
133
+ * const { searchParams } = new URL(req.url);
134
+ * const traceId = searchParams.get('traceId');
135
+ * if (!traceId) return new Response('missing traceId', { status: 400 });
136
+ * const stream = subscribe(traceId);
137
+ * // ... bridge ReadableStream<GlassboxEvent> → SSE here ...
138
+ * }
139
+ *
140
+ * Stream behavior:
141
+ * - Emits events for `traceId` as they're published.
142
+ * - Closes cleanly 60s after the last event (rolling TTL).
143
+ * - If no events arrive within 60s of subscription, closes empty.
144
+ * - Multiple subscribers on the same traceId all fan out.
145
+ *
146
+ * No replay: subscribe() picks up only events published AFTER subscription.
147
+ * Replay is the brain-poll surface's job (see design doc).
148
+ */
149
+
150
+ /**
151
+ * Subscribe to Glass-Box events for a traceId. Returns a ReadableStream
152
+ * that yields GlassboxEvent objects until the per-trace TTL elapses.
153
+ *
154
+ * Cancelling the stream (consumer disconnect, AbortController, etc.) tears
155
+ * down the subscription cleanly via the underlying adapter.
156
+ */
157
+ declare function subscribe(traceId: string): ReadableStream<GlassboxEvent>;
158
+
159
+ export { type AdvisoryFiredData, type CompileDoneData, type CompileStartData, type ExecuteAttemptData, type ExecuteSuccessData, type FallbackWalkedData, GLASSBOX_STREAM_TTL_MS, type GlassboxEvent, type GlassboxEventKind, type GlassboxPubSub, subscribe };
@@ -0,0 +1,159 @@
1
+ import { j as MutationApplied, B as BestPracticeAdvisory, F as FallbackReason, g as CallAttempt } from '../ir-CFHU3BUT.js';
2
+ import '../dialect.js';
3
+
4
+ /**
5
+ * Glass-Box observability types (alpha.17).
6
+ *
7
+ * The substrate for kgauto's in-flight observability surface — a Chrome MV3
8
+ * side panel that renders compile + execute + advisor outputs in real-time.
9
+ * See design doc:
10
+ * ~/.gstack/projects/stue-kgauto/stgreen-claude-serene-williamson-51a105-design-20260518-175356.md
11
+ *
12
+ * Wire shape is intentionally minimal:
13
+ * { kind, at, data } — discriminated union by `kind`.
14
+ *
15
+ * Critical-path safety (L-086 derived): emit MUST NEVER fail the user's
16
+ * `call()` invocation. emit.ts wraps every adapter write in try/catch +
17
+ * silently drops on error. Consumers in Vercel Edge runtimes can lose one
18
+ * event without losing the response.
19
+ */
20
+
21
+ /**
22
+ * Discriminator. Six event kinds cover the v1 substrate. New kinds added
23
+ * additively; the side-panel renderer treats unknown kinds as "ignore".
24
+ */
25
+ type GlassboxEventKind = 'compile.start' | 'compile.done' | 'execute.attempt' | 'execute.success' | 'advisory.fired' | 'fallback.walked';
26
+ /**
27
+ * Wire envelope. Every emit lands as one of these.
28
+ *
29
+ * - kind: discriminator
30
+ * - at: unix milliseconds (Date.now())
31
+ * - data: kind-specific payload
32
+ *
33
+ * `data` typed loosely as Record<string, unknown> for serialization-friendliness;
34
+ * the per-kind builders below populate it with the structured shape expected
35
+ * by the renderer. We deliberately do NOT typescript-narrow `data` by kind on
36
+ * the wire type — the side panel reads JSON from SSE and only the renderer
37
+ * needs the narrowed shape. Internal callers (emit.ts) get type assistance via
38
+ * the typed factory helpers in emit.ts.
39
+ */
40
+ interface GlassboxEvent {
41
+ kind: GlassboxEventKind;
42
+ at: number;
43
+ data: Record<string, unknown>;
44
+ }
45
+ /**
46
+ * Per-kind data shapes. Surfaced as type aids; not enforced at the
47
+ * GlassboxEvent boundary (intentionally — see comment above).
48
+ */
49
+ interface CompileStartData {
50
+ appId: string;
51
+ archetype: string;
52
+ models: string[];
53
+ }
54
+ interface CompileDoneData {
55
+ target: string;
56
+ provider: string;
57
+ fallbackChain: string[];
58
+ tokensIn: number;
59
+ estimatedCostUsd: number;
60
+ mutationsApplied: MutationApplied[];
61
+ advisories: BestPracticeAdvisory[];
62
+ }
63
+ interface ExecuteAttemptData {
64
+ model: string;
65
+ attemptIndex: number;
66
+ }
67
+ interface ExecuteSuccessData {
68
+ model: string;
69
+ tokensIn: number;
70
+ tokensOut: number;
71
+ latencyMs: number;
72
+ }
73
+ interface AdvisoryFiredData {
74
+ code: string;
75
+ message: string;
76
+ }
77
+ interface FallbackWalkedData {
78
+ from: string;
79
+ to: string;
80
+ reason: FallbackReason | 'unknown';
81
+ attempt: CallAttempt;
82
+ }
83
+ /**
84
+ * Pub/sub backend interface. Two adapters implement it: in-memory (dev /
85
+ * single-process) and Upstash Redis Streams (Vercel Edge multi-instance).
86
+ *
87
+ * The choice is made at module load (NOT per-call) based on env-var presence:
88
+ * if (UPSTASH_REDIS_URL && UPSTASH_REDIS_TOKEN) → Upstash
89
+ * else → in-memory
90
+ *
91
+ * Stream TTL: 60s after last event. After that, subscriber stream closes
92
+ * cleanly. The adapter owns its own TTL clock; subscribe() is agnostic.
93
+ */
94
+ interface GlassboxPubSub {
95
+ /**
96
+ * Publish a single event for a traceId. Returns a promise that resolves
97
+ * after the event is durably appended (or rejects on adapter failure —
98
+ * callers in emit.ts always swallow rejections).
99
+ */
100
+ publish(traceId: string, event: GlassboxEvent): Promise<void>;
101
+ /**
102
+ * Subscribe to events for a traceId. Returns a ReadableStream that emits
103
+ * GlassboxEvent objects as they're published. The stream closes cleanly
104
+ * after the per-trace TTL elapses since the LAST event (rolling 60s).
105
+ *
106
+ * If the traceId has no publisher within 60s of subscription, the stream
107
+ * closes empty.
108
+ */
109
+ subscribe(traceId: string): ReadableStream<GlassboxEvent>;
110
+ /**
111
+ * Test-only escape hatch. Clears any in-memory state. Upstash adapter
112
+ * no-ops (server-side state isn't accessible from here). Tests reach for
113
+ * this between cases to keep adapters hermetic.
114
+ */
115
+ _reset?(): void;
116
+ }
117
+ /**
118
+ * TTL applied to a stream after each event. The design doc names 60s; this
119
+ * constant centralizes it so both adapters + tests agree.
120
+ */
121
+ declare const GLASSBOX_STREAM_TTL_MS = 60000;
122
+
123
+ /**
124
+ * subscribe(traceId) — public Glass-Box subscription export.
125
+ *
126
+ * Consumer route handlers (e.g. Vercel Edge `/api/glassbox/stream`) import
127
+ * this and bridge the ReadableStream to SSE. The browser-side panel then
128
+ * renders events in real time:
129
+ *
130
+ * import { subscribe } from '@warmdrift/kgauto-compiler/glassbox';
131
+ *
132
+ * export async function GET(req: Request) {
133
+ * const { searchParams } = new URL(req.url);
134
+ * const traceId = searchParams.get('traceId');
135
+ * if (!traceId) return new Response('missing traceId', { status: 400 });
136
+ * const stream = subscribe(traceId);
137
+ * // ... bridge ReadableStream<GlassboxEvent> → SSE here ...
138
+ * }
139
+ *
140
+ * Stream behavior:
141
+ * - Emits events for `traceId` as they're published.
142
+ * - Closes cleanly 60s after the last event (rolling TTL).
143
+ * - If no events arrive within 60s of subscription, closes empty.
144
+ * - Multiple subscribers on the same traceId all fan out.
145
+ *
146
+ * No replay: subscribe() picks up only events published AFTER subscription.
147
+ * Replay is the brain-poll surface's job (see design doc).
148
+ */
149
+
150
+ /**
151
+ * Subscribe to Glass-Box events for a traceId. Returns a ReadableStream
152
+ * that yields GlassboxEvent objects until the per-trace TTL elapses.
153
+ *
154
+ * Cancelling the stream (consumer disconnect, AbortController, etc.) tears
155
+ * down the subscription cleanly via the underlying adapter.
156
+ */
157
+ declare function subscribe(traceId: string): ReadableStream<GlassboxEvent>;
158
+
159
+ export { type AdvisoryFiredData, type CompileDoneData, type CompileStartData, type ExecuteAttemptData, type ExecuteSuccessData, type FallbackWalkedData, GLASSBOX_STREAM_TTL_MS, type GlassboxEvent, type GlassboxEventKind, type GlassboxPubSub, subscribe };