@warmdrift/kgauto-compiler 2.0.0-alpha.7 → 2.0.0-alpha.71

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 (55) hide show
  1. package/README.md +176 -46
  2. package/dist/brain-proxy.d.mts +113 -0
  3. package/dist/brain-proxy.d.ts +113 -0
  4. package/dist/brain-proxy.js +193 -0
  5. package/dist/brain-proxy.mjs +6 -0
  6. package/dist/chunk-4UO4CCSP.mjs +1620 -0
  7. package/dist/chunk-65ZMX5OT.mjs +169 -0
  8. package/dist/{chunk-5TI6PNSK.mjs → chunk-BVEXV5KC.mjs} +11 -0
  9. package/dist/chunk-NBO4R5PC.mjs +313 -0
  10. package/dist/chunk-P3TOAEG4.mjs +56 -0
  11. package/dist/chunk-RO22VFIF.mjs +29 -0
  12. package/dist/chunk-SBFSYCQG.mjs +719 -0
  13. package/dist/chunk-URFQR3SB.mjs +203 -0
  14. package/dist/dialect.d.mts +41 -3
  15. package/dist/dialect.d.ts +41 -3
  16. package/dist/dialect.js +14 -2
  17. package/dist/dialect.mjs +5 -3
  18. package/dist/glassbox/index.d.mts +59 -0
  19. package/dist/glassbox/index.d.ts +59 -0
  20. package/dist/glassbox/index.js +312 -0
  21. package/dist/glassbox/index.mjs +12 -0
  22. package/dist/glassbox-routes/format.d.mts +24 -0
  23. package/dist/glassbox-routes/format.d.ts +24 -0
  24. package/dist/glassbox-routes/format.js +86 -0
  25. package/dist/glassbox-routes/format.mjs +18 -0
  26. package/dist/glassbox-routes/index.d.mts +191 -0
  27. package/dist/glassbox-routes/index.d.ts +191 -0
  28. package/dist/glassbox-routes/index.js +2888 -0
  29. package/dist/glassbox-routes/index.mjs +667 -0
  30. package/dist/glassbox-routes/react/index.d.mts +74 -0
  31. package/dist/glassbox-routes/react/index.d.ts +74 -0
  32. package/dist/glassbox-routes/react/index.js +819 -0
  33. package/dist/glassbox-routes/react/index.mjs +754 -0
  34. package/dist/index.d.mts +2745 -17
  35. package/dist/index.d.ts +2745 -17
  36. package/dist/index.js +9006 -1651
  37. package/dist/index.mjs +5103 -367
  38. package/dist/ir-BEQ28muo.d.ts +1608 -0
  39. package/dist/ir-CnnJST_N.d.mts +1608 -0
  40. package/dist/key-health.d.mts +131 -0
  41. package/dist/key-health.d.ts +131 -0
  42. package/dist/key-health.js +228 -0
  43. package/dist/key-health.mjs +6 -0
  44. package/dist/profiles.d.mts +292 -2
  45. package/dist/profiles.d.ts +292 -2
  46. package/dist/profiles.js +1231 -16
  47. package/dist/profiles.mjs +9 -1
  48. package/dist/types-B--CYzMo.d.ts +131 -0
  49. package/dist/types-BDFrJkma.d.mts +131 -0
  50. package/dist/types-DSeJJ6tt.d.ts +149 -0
  51. package/dist/types-DeGRCTlJ.d.mts +149 -0
  52. package/package.json +54 -8
  53. package/dist/chunk-MBEI5UOM.mjs +0 -409
  54. package/dist/profiles-B3eNQ2py.d.ts +0 -619
  55. package/dist/profiles-Py8c7zjJ.d.mts +0 -619
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/glassbox/index.ts
21
+ var glassbox_exports = {};
22
+ __export(glassbox_exports, {
23
+ GLASSBOX_STREAM_TTL_MS: () => GLASSBOX_STREAM_TTL_MS,
24
+ subscribe: () => subscribe,
25
+ subscribeApp: () => subscribeApp
26
+ });
27
+ module.exports = __toCommonJS(glassbox_exports);
28
+
29
+ // src/glassbox/types.ts
30
+ var GLASSBOX_STREAM_TTL_MS = 6e4;
31
+
32
+ // src/glassbox/pubsub-memory.ts
33
+ var MemoryPubSub = class {
34
+ subscribers = /* @__PURE__ */ new Map();
35
+ async publish(channelKey, event) {
36
+ const subs = this.subscribers.get(channelKey);
37
+ if (!subs || subs.size === 0) return;
38
+ for (const sub of subs) {
39
+ if (sub.closed) continue;
40
+ try {
41
+ sub.controller.enqueue(event);
42
+ } catch {
43
+ sub.closed = true;
44
+ continue;
45
+ }
46
+ this.refreshTtl(channelKey, sub);
47
+ }
48
+ }
49
+ subscribe(channelKey) {
50
+ const self = this;
51
+ let sub;
52
+ return new ReadableStream({
53
+ start(controller) {
54
+ sub = {
55
+ controller,
56
+ ttlTimer: setTimeout(() => {
57
+ self.closeSubscriber(channelKey, sub);
58
+ }, GLASSBOX_STREAM_TTL_MS),
59
+ closed: false
60
+ };
61
+ let set = self.subscribers.get(channelKey);
62
+ if (!set) {
63
+ set = /* @__PURE__ */ new Set();
64
+ self.subscribers.set(channelKey, set);
65
+ }
66
+ set.add(sub);
67
+ },
68
+ cancel() {
69
+ if (sub) self.removeSubscriber(channelKey, sub);
70
+ }
71
+ });
72
+ }
73
+ /**
74
+ * Refresh the rolling TTL for a subscriber after an event lands. Replaces
75
+ * the existing timer with a fresh 60s one.
76
+ */
77
+ refreshTtl(channelKey, sub) {
78
+ clearTimeout(sub.ttlTimer);
79
+ sub.ttlTimer = setTimeout(() => {
80
+ this.closeSubscriber(channelKey, sub);
81
+ }, GLASSBOX_STREAM_TTL_MS);
82
+ }
83
+ /**
84
+ * Close the subscriber's stream cleanly and remove from the fan-out set.
85
+ * Idempotent — safe to call multiple times.
86
+ */
87
+ closeSubscriber(channelKey, sub) {
88
+ if (sub.closed) return;
89
+ sub.closed = true;
90
+ clearTimeout(sub.ttlTimer);
91
+ try {
92
+ sub.controller.close();
93
+ } catch {
94
+ }
95
+ this.removeSubscriber(channelKey, sub);
96
+ }
97
+ removeSubscriber(channelKey, sub) {
98
+ clearTimeout(sub.ttlTimer);
99
+ const set = this.subscribers.get(channelKey);
100
+ if (!set) return;
101
+ set.delete(sub);
102
+ if (set.size === 0) this.subscribers.delete(channelKey);
103
+ }
104
+ /**
105
+ * Test-only reset. Tears down all subscribers, clears all state. Calling
106
+ * outside of tests is harmless but cancels every active stream.
107
+ */
108
+ _reset() {
109
+ for (const [, set] of this.subscribers) {
110
+ for (const sub of set) {
111
+ this.closeSubscriber("", sub);
112
+ }
113
+ }
114
+ this.subscribers.clear();
115
+ }
116
+ };
117
+
118
+ // src/glassbox/pubsub-upstash.ts
119
+ var UpstashPubSub = class {
120
+ url;
121
+ token;
122
+ fetchImpl;
123
+ blockMs;
124
+ maxLen;
125
+ constructor(cfg) {
126
+ this.url = cfg.url.replace(/\/$/, "");
127
+ this.token = cfg.token;
128
+ this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch.bind(globalThis);
129
+ this.blockMs = cfg.blockMs ?? 100;
130
+ this.maxLen = cfg.maxLen ?? 100;
131
+ }
132
+ async publish(channelKey, event) {
133
+ const key = channelKey;
134
+ const payload = JSON.stringify(event);
135
+ await this.cmd([
136
+ "XADD",
137
+ key,
138
+ "MAXLEN",
139
+ "~",
140
+ String(this.maxLen),
141
+ "*",
142
+ "event",
143
+ payload
144
+ ]);
145
+ await this.cmd(["EXPIRE", key, String(Math.ceil(GLASSBOX_STREAM_TTL_MS / 1e3))]);
146
+ }
147
+ subscribe(channelKey) {
148
+ const key = channelKey;
149
+ const self = this;
150
+ let cursor = "$";
151
+ let cancelled = false;
152
+ let ttlDeadline = Date.now() + GLASSBOX_STREAM_TTL_MS;
153
+ return new ReadableStream({
154
+ async start(controller) {
155
+ try {
156
+ while (!cancelled && Date.now() < ttlDeadline) {
157
+ const resp = await self.cmd([
158
+ "XREAD",
159
+ "BLOCK",
160
+ String(self.blockMs),
161
+ "STREAMS",
162
+ key,
163
+ cursor
164
+ ]);
165
+ if (cancelled) break;
166
+ const parsed = parseXReadResult(resp.result);
167
+ if (parsed.entries.length === 0) {
168
+ continue;
169
+ }
170
+ for (const entry of parsed.entries) {
171
+ const evt = decodeEvent(entry.fields);
172
+ if (evt) {
173
+ try {
174
+ controller.enqueue(evt);
175
+ } catch {
176
+ cancelled = true;
177
+ break;
178
+ }
179
+ }
180
+ cursor = entry.id;
181
+ }
182
+ ttlDeadline = Date.now() + GLASSBOX_STREAM_TTL_MS;
183
+ }
184
+ } catch (err) {
185
+ if (!cancelled) {
186
+ try {
187
+ controller.error(err);
188
+ } catch {
189
+ }
190
+ return;
191
+ }
192
+ }
193
+ try {
194
+ controller.close();
195
+ } catch {
196
+ }
197
+ },
198
+ cancel() {
199
+ cancelled = true;
200
+ }
201
+ });
202
+ }
203
+ async cmd(args) {
204
+ const res = await this.fetchImpl(this.url, {
205
+ method: "POST",
206
+ headers: {
207
+ Authorization: `Bearer ${this.token}`,
208
+ "Content-Type": "application/json"
209
+ },
210
+ body: JSON.stringify(args)
211
+ });
212
+ if (!res.ok) {
213
+ throw new Error(`Upstash ${args[0]} failed: HTTP ${res.status}`);
214
+ }
215
+ const json = await res.json();
216
+ if (json.error) {
217
+ throw new Error(`Upstash ${args[0]} failed: ${json.error}`);
218
+ }
219
+ return json;
220
+ }
221
+ };
222
+ function traceChannel(traceId) {
223
+ return `glassbox:trace:${traceId}`;
224
+ }
225
+ function appChannel(appId) {
226
+ return `glassbox:app:${appId}`;
227
+ }
228
+ function decodeEvent(fields) {
229
+ const raw = fields["event"];
230
+ if (!raw) return void 0;
231
+ try {
232
+ const parsed = JSON.parse(raw);
233
+ if (typeof parsed.kind === "string" && typeof parsed.at === "number") {
234
+ return parsed;
235
+ }
236
+ return void 0;
237
+ } catch {
238
+ return void 0;
239
+ }
240
+ }
241
+ function parseXReadResult(raw) {
242
+ if (!Array.isArray(raw)) return { entries: [] };
243
+ const entries = [];
244
+ for (const stream of raw) {
245
+ if (!Array.isArray(stream) || stream.length < 2) continue;
246
+ const streamEntries = stream[1];
247
+ if (!Array.isArray(streamEntries)) continue;
248
+ for (const entry of streamEntries) {
249
+ if (!Array.isArray(entry) || entry.length < 2) continue;
250
+ const id = String(entry[0]);
251
+ const flat = entry[1];
252
+ if (!Array.isArray(flat)) continue;
253
+ const fields = {};
254
+ for (let i = 0; i < flat.length; i += 2) {
255
+ const k = flat[i];
256
+ const v = flat[i + 1];
257
+ if (typeof k === "string") fields[k] = String(v ?? "");
258
+ }
259
+ entries.push({ id, fields });
260
+ }
261
+ }
262
+ return { entries };
263
+ }
264
+
265
+ // src/glassbox/emit.ts
266
+ var activePubSub;
267
+ function getPubSub() {
268
+ if (activePubSub) return activePubSub;
269
+ const url = readEnv("UPSTASH_REDIS_URL");
270
+ const token = readEnv("UPSTASH_REDIS_TOKEN");
271
+ if (url && token) {
272
+ activePubSub = new UpstashPubSub({ url, token });
273
+ } else {
274
+ activePubSub = new MemoryPubSub();
275
+ }
276
+ return activePubSub;
277
+ }
278
+ function readEnv(key) {
279
+ try {
280
+ if (typeof process !== "undefined" && process.env) {
281
+ const v = process.env[key];
282
+ return v && v.trim() !== "" ? v : void 0;
283
+ }
284
+ } catch {
285
+ }
286
+ return void 0;
287
+ }
288
+
289
+ // src/glassbox/subscribe.ts
290
+ function emptyStream() {
291
+ return new ReadableStream({
292
+ start(controller) {
293
+ controller.close();
294
+ }
295
+ });
296
+ }
297
+ function subscribe(traceId) {
298
+ if (!traceId) return emptyStream();
299
+ return getPubSub().subscribe(traceChannel(traceId));
300
+ }
301
+ function subscribeApp({
302
+ appId
303
+ }) {
304
+ if (!appId) return emptyStream();
305
+ return getPubSub().subscribe(appChannel(appId));
306
+ }
307
+ // Annotate the CommonJS export names for ESM import in node:
308
+ 0 && (module.exports = {
309
+ GLASSBOX_STREAM_TTL_MS,
310
+ subscribe,
311
+ subscribeApp
312
+ });
@@ -0,0 +1,12 @@
1
+ import {
2
+ subscribe,
3
+ subscribeApp
4
+ } from "../chunk-RO22VFIF.mjs";
5
+ import {
6
+ GLASSBOX_STREAM_TTL_MS
7
+ } from "../chunk-NBO4R5PC.mjs";
8
+ export {
9
+ GLASSBOX_STREAM_TTL_MS,
10
+ subscribe,
11
+ subscribeApp
12
+ };
@@ -0,0 +1,24 @@
1
+ import { T as TraceHealth } from '../types-DeGRCTlJ.mjs';
2
+ import '../ir-CnnJST_N.mjs';
3
+ import '../dialect.mjs';
4
+
5
+ /**
6
+ * Pure formatting helpers for Glass-Box trace display.
7
+ *
8
+ * Zero deps, no React, no design tokens. Safe to import from any consumer
9
+ * (React component, server route, CLI, Edge worker).
10
+ *
11
+ * Extracted from the alpha.32 tt-intelligence reference component port in
12
+ * alpha.35 so multiple consumer dashboards can render trace data with
13
+ * matching formatting without re-implementing each helper.
14
+ */
15
+
16
+ declare function formatAgo(iso: string, now?: number): string;
17
+ declare function shortTraceId(traceId: string): string;
18
+ declare function formatCost(usd: number | undefined | null): string;
19
+ declare function formatMs(ms: number | undefined | null): string;
20
+ declare function formatOrDash(v: number | string | undefined | null): string;
21
+ declare function inputRatioLabel(status: TraceHealth['inputRatioStatus']): string;
22
+ declare function formatMutation(mutation: string): string;
23
+
24
+ export { formatAgo, formatCost, formatMs, formatMutation, formatOrDash, inputRatioLabel, shortTraceId };
@@ -0,0 +1,24 @@
1
+ import { T as TraceHealth } from '../types-DSeJJ6tt.js';
2
+ import '../ir-BEQ28muo.js';
3
+ import '../dialect.js';
4
+
5
+ /**
6
+ * Pure formatting helpers for Glass-Box trace display.
7
+ *
8
+ * Zero deps, no React, no design tokens. Safe to import from any consumer
9
+ * (React component, server route, CLI, Edge worker).
10
+ *
11
+ * Extracted from the alpha.32 tt-intelligence reference component port in
12
+ * alpha.35 so multiple consumer dashboards can render trace data with
13
+ * matching formatting without re-implementing each helper.
14
+ */
15
+
16
+ declare function formatAgo(iso: string, now?: number): string;
17
+ declare function shortTraceId(traceId: string): string;
18
+ declare function formatCost(usd: number | undefined | null): string;
19
+ declare function formatMs(ms: number | undefined | null): string;
20
+ declare function formatOrDash(v: number | string | undefined | null): string;
21
+ declare function inputRatioLabel(status: TraceHealth['inputRatioStatus']): string;
22
+ declare function formatMutation(mutation: string): string;
23
+
24
+ export { formatAgo, formatCost, formatMs, formatMutation, formatOrDash, inputRatioLabel, shortTraceId };
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/glassbox-routes/format.ts
21
+ var format_exports = {};
22
+ __export(format_exports, {
23
+ formatAgo: () => formatAgo,
24
+ formatCost: () => formatCost,
25
+ formatMs: () => formatMs,
26
+ formatMutation: () => formatMutation,
27
+ formatOrDash: () => formatOrDash,
28
+ inputRatioLabel: () => inputRatioLabel,
29
+ shortTraceId: () => shortTraceId
30
+ });
31
+ module.exports = __toCommonJS(format_exports);
32
+ function formatAgo(iso, now = Date.now()) {
33
+ const t = Date.parse(iso);
34
+ if (Number.isNaN(t)) return iso;
35
+ const sec = Math.max(0, Math.floor((now - t) / 1e3));
36
+ if (sec < 60) return `${sec}s ago`;
37
+ if (sec < 3600) return `${Math.floor(sec / 60)}m ago`;
38
+ if (sec < 86400) return `${Math.floor(sec / 3600)}h ago`;
39
+ return `${Math.floor(sec / 86400)}d ago`;
40
+ }
41
+ function shortTraceId(traceId) {
42
+ return traceId.slice(-6);
43
+ }
44
+ function formatCost(usd) {
45
+ if (usd === void 0 || usd === null || Number.isNaN(usd)) return "\u2014";
46
+ if (usd === 0) return "$0.0000";
47
+ if (usd < 0.01) return `$${usd.toFixed(4)}`;
48
+ return `$${usd.toFixed(3)}`;
49
+ }
50
+ function formatMs(ms) {
51
+ if (ms === void 0 || ms === null) return "\u2014";
52
+ if (ms < 1e3) return `${ms}ms`;
53
+ return `${(ms / 1e3).toFixed(1)}s`;
54
+ }
55
+ function formatOrDash(v) {
56
+ if (v === void 0 || v === null) return "\u2014";
57
+ if (typeof v === "number") return v.toLocaleString();
58
+ return v;
59
+ }
60
+ function inputRatioLabel(status) {
61
+ switch (status) {
62
+ case "green":
63
+ return "healthy";
64
+ case "yellow":
65
+ return "borderline";
66
+ case "red":
67
+ return "input-heavy";
68
+ }
69
+ }
70
+ function formatMutation(mutation) {
71
+ const m = /^(.*)-(\d+)-to-(\d+)$/.exec(mutation);
72
+ if (m) {
73
+ return `${m[1]} (${m[2]} \u2192 ${m[3]})`;
74
+ }
75
+ return mutation;
76
+ }
77
+ // Annotate the CommonJS export names for ESM import in node:
78
+ 0 && (module.exports = {
79
+ formatAgo,
80
+ formatCost,
81
+ formatMs,
82
+ formatMutation,
83
+ formatOrDash,
84
+ inputRatioLabel,
85
+ shortTraceId
86
+ });
@@ -0,0 +1,18 @@
1
+ import {
2
+ formatAgo,
3
+ formatCost,
4
+ formatMs,
5
+ formatMutation,
6
+ formatOrDash,
7
+ inputRatioLabel,
8
+ shortTraceId
9
+ } from "../chunk-P3TOAEG4.mjs";
10
+ export {
11
+ formatAgo,
12
+ formatCost,
13
+ formatMs,
14
+ formatMutation,
15
+ formatOrDash,
16
+ inputRatioLabel,
17
+ shortTraceId
18
+ };
@@ -0,0 +1,191 @@
1
+ import { G as GlassboxEvent } from '../types-BDFrJkma.mjs';
2
+ import { a as TraceDetail, b as TraceSummary, c as TraceCounterfactual } from '../types-DeGRCTlJ.mjs';
3
+ export { A as AdvisoryRecord, T as TraceHealth, d as TraceSectionRewrite } from '../types-DeGRCTlJ.mjs';
4
+ import '../ir-CnnJST_N.mjs';
5
+ import '../dialect.mjs';
6
+
7
+ /**
8
+ * proxy(req) — Glass-Box replay query handler.
9
+ *
10
+ * GET /api/glassbox/proxy?traceId=<id> → single compile_outcomes row for trace
11
+ * GET /api/glassbox/proxy?limit=<N> → N most-recent compile_outcomes rows
12
+ * GET /api/glassbox/proxy → defaults to limit=20
13
+ *
14
+ * Brain reads go through PostgREST on Supabase. We always filter by
15
+ * `app_id=eq.<appId>` even though the scoped JWT's RLS policy already
16
+ * enforces tenant isolation — the explicit filter trims the network payload
17
+ * and makes the query intent obvious to anyone reading logs.
18
+ *
19
+ * Scrub: the optional `scrub` hook runs on each row before responding so
20
+ * sensitive payloads (rendered prompts, tool calls) can be redacted at the
21
+ * proxy boundary. Default is identity (no-op).
22
+ */
23
+
24
+ /**
25
+ * Typed boundary transformer: compile_outcomes row (snake_case, Postgres
26
+ * native) → TraceSummary (camelCase, TypeScript native + extension wire
27
+ * contract). Single canonical mapping site — every DB-shape ↔ wire-shape
28
+ * crossing routes through here so renderer-expected fields can't silently
29
+ * go missing. See `feedback_typed_boundary_transformers.md` for the rule.
30
+ */
31
+ declare function rowToSummary(row: Record<string, unknown>): TraceSummary;
32
+ /**
33
+ * Typed boundary transformer (L-118): compile_outcomes row → TraceDetail.
34
+ * Single canonical mapping site for the detail-view wire contract. Pre-018
35
+ * brain rows return NULL for the new columns; this transformer applies
36
+ * type-safe defaults (0 for token columns, undefined for optional strings)
37
+ * so the renderer never crashes on missing fields.
38
+ *
39
+ * alpha.28 extends the field set per the renderer design contract — every
40
+ * extended field has a default. The `counterfactuals` + `projectedDailyCost`
41
+ * fields are populated by the proxy AFTER this transformer runs (they need
42
+ * profile lookup / brain query / async I/O).
43
+ */
44
+ declare function rowToDetail(row: Record<string, unknown>): TraceDetail;
45
+
46
+ /**
47
+ * computeCounterfactuals — for a served trace, compute up to 2 cheaper
48
+ * alternatives that ALSO meet the archetype quality floor.
49
+ *
50
+ * Pure function. Called at detail-view time by the proxy's `rowToDetail`
51
+ * path. The cost-equivalent answer to "what could this have run on without
52
+ * tanking quality?" lets the Glass-Box render `💰 Cheaper alternatives` so a
53
+ * founder sees the actual cost of the routing choice rather than just the
54
+ * served cost.
55
+ *
56
+ * Mechanism (per design contract Phase 0 spec):
57
+ * 1. Walk the archetype's full default fallback chain.
58
+ * 2. For each model in the chain (excluding the served model):
59
+ * - Skip if archetypePerf[archetype] < ARCHETYPE_FLOOR_DEFAULT (6).
60
+ * Matches the cliff-advisor work — never recommend a swap that
61
+ * violates the quality floor. (Composition with Builder C is
62
+ * intentional.)
63
+ * - Skip if profile missing.
64
+ * - Compute estimated cost at the OBSERVED token counts:
65
+ * non_cached_in = tokensIn - cacheReadInputTokens
66
+ * cost = (non_cached_in / 1e6) * profile.costInputPer1m
67
+ * + (cacheable_in / 1e6) * profile.costInputPer1m
68
+ * * profile.lowering.cache.discount
69
+ * + (tokensOut / 1e6) * profile.costOutputPer1m
70
+ * - Only include if estimatedCostUsd ≤ 0.9 × servedCostUsd
71
+ * (≥10% cheaper — below that's noise of token-count estimation).
72
+ * 3. Sort cheapest first.
73
+ * 4. Cap to top 2.
74
+ *
75
+ * Edge cases:
76
+ * - tokensIn === 0 → return [] (can't meaningfully estimate).
77
+ * - servedCostUsd === 0 → return [] (no baseline to beat).
78
+ * - Zero matching alternatives → return [] (renderer hides the card).
79
+ * - Served model isn't in the chain (e.g. forceModel'd off-chain) → use
80
+ * the chain for the archetype anyway.
81
+ */
82
+
83
+ /** Only surface swaps that save at least 10% vs. served. */
84
+ declare const COUNTERFACTUAL_MIN_SAVINGS_RATIO = 0.1;
85
+ /** Cap on alternatives surfaced per trace. */
86
+ declare const COUNTERFACTUAL_MAX_RESULTS = 2;
87
+ interface ComputeCounterfactualsArgs {
88
+ servedModel: string;
89
+ servedCostUsd: number;
90
+ archetype: string;
91
+ tokensIn: number;
92
+ tokensOut: number;
93
+ /** Defaults to 0 when caller doesn't know. */
94
+ cacheReadInputTokens?: number;
95
+ /** Reserved for future per-mode chain selection. */
96
+ toolOrchestration?: 'parallel' | 'sequential' | 'either';
97
+ }
98
+ declare function computeCounterfactuals(args: ComputeCounterfactualsArgs): TraceCounterfactual[];
99
+
100
+ /**
101
+ * Public entry point for `@warmdrift/kgauto-compiler/glassbox-routes`.
102
+ *
103
+ * One factory call from a Vercel Edge consumer route handler gets you both
104
+ * the replay-query (`proxy`) and live-SSE (`stream`) endpoints that the
105
+ * Glass-Box Chrome panel reads. Wiring is ~6 lines per app:
106
+ *
107
+ * // app/api/glassbox/proxy/route.ts
108
+ * import { createGlassboxRoutes } from '@warmdrift/kgauto-compiler/glassbox-routes';
109
+ * const { proxy } = createGlassboxRoutes({
110
+ * installToken: process.env.GLASSBOX_INSTALL_TOKEN!,
111
+ * extensionId: process.env.GLASSBOX_EXTENSION_ID!,
112
+ * brainEndpoint: process.env.GLASSBOX_BRAIN_ENDPOINT!,
113
+ * brainJwt: process.env.GLASSBOX_BRAIN_JWT!, // scoped JWT (RLS via app_id claim)
114
+ * brainAnonKey: process.env.GLASSBOX_BRAIN_ANON_KEY!, // project anon/publishable key (Supabase apikey header)
115
+ * appId: 'playbacksam',
116
+ * });
117
+ * export { proxy as GET };
118
+ *
119
+ * Auth model (defense in depth):
120
+ * - Bearer install token → primary, constant-time compared
121
+ * - chrome-extension Origin → secondary CSRF gate
122
+ *
123
+ * Scrub: optional sanitization runs at the proxy boundary before events or
124
+ * rows leave the consumer's infrastructure. Per pii-scrubber-call-site-not-
125
+ * package: kgauto stays naive to PII policy; consumers pass scrub hooks
126
+ * that encode their own data-handling rules.
127
+ *
128
+ * Brain reads use the scoped JWT minted via migration 013. RLS enforces
129
+ * `app_id = jwt.claim.app_id`; the proxy filter is belt-and-suspenders for
130
+ * payload size + log legibility.
131
+ */
132
+
133
+ interface GlassboxRoutesConfig {
134
+ /** Bearer token validated on every request via constant-time compare. Required. */
135
+ installToken: string;
136
+ /** chrome-extension://<id> — exact match required on Origin header. Required. */
137
+ extensionId: string;
138
+ /** Brain endpoint base (e.g. https://kgauto-brain.supabase.co). Used by `proxy` for replay queries. */
139
+ brainEndpoint: string;
140
+ /** Scoped JWT for brain reads. Use the per-consumer JWT minted via migration 013 (claim: app_id). Drives RLS via the `app_id` claim; sent as `Authorization: Bearer <jwt>` only. */
141
+ brainJwt: string;
142
+ /**
143
+ * Anon/publishable key for the Supabase `apikey` header. Supabase requires
144
+ * `apikey` to be one of the project's known keys (anon or service_role) —
145
+ * the scoped JWT in `brainJwt` doesn't qualify there. Pass the project's
146
+ * legacy `anon` key (JWT format, role=anon) or the modern `sb_publishable_...`
147
+ * key. Safe to expose at the wire (that's what "publishable" means).
148
+ *
149
+ * Pre-alpha.24 this was missing and `brainJwt` was used as apikey too — first
150
+ * real call always 401'd against real Supabase. Catching this required a
151
+ * pre-publish smoke against the real brain; unit tests with mocked fetch
152
+ * couldn't surface it. See L-117 in command-center/learnings.md.
153
+ */
154
+ brainAnonKey: string;
155
+ /** App scope filter — must match the JWT's app_id claim. */
156
+ appId: string;
157
+ /**
158
+ * Optional sanitization hook. Called with each event/trace BEFORE it leaves the consumer.
159
+ * Default: identity (no scrub). PII policy lives at the call-site, not in the package.
160
+ */
161
+ scrub?: (event: GlassboxEvent | Record<string, unknown>) => GlassboxEvent | Record<string, unknown>;
162
+ /**
163
+ * Test-only seam: override the brain fetch implementation. Production
164
+ * code never sets this; tests use it to mock PostgREST responses.
165
+ */
166
+ fetch?: typeof fetch;
167
+ /**
168
+ * Test-only seam: override the per-trace live-stream subscriber. Production
169
+ * code resolves to the alpha.17 `subscribe()` export; tests inject a fake
170
+ * source ReadableStream<GlassboxEvent>.
171
+ */
172
+ subscribe?: (traceId: string) => ReadableStream<GlassboxEvent>;
173
+ /**
174
+ * Test-only seam: override the per-app "tail-all" subscriber (alpha.26).
175
+ * Production code resolves to the `subscribeApp()` export; tests inject
176
+ * a fake source. Backs the extension's default Live tab mode when no
177
+ * traceId is supplied in the URL.
178
+ */
179
+ subscribeApp?: (args: {
180
+ appId: string;
181
+ }) => ReadableStream<GlassboxEvent>;
182
+ }
183
+ interface GlassboxRoutes {
184
+ /** GET /api/glassbox/proxy?traceId=<id> OR ?limit=20 (recent traces) */
185
+ proxy: (req: Request) => Promise<Response>;
186
+ /** GET /api/glassbox/stream?traceId=<id> (SSE) */
187
+ stream: (req: Request) => Promise<Response>;
188
+ }
189
+ declare function createGlassboxRoutes(config: GlassboxRoutesConfig): GlassboxRoutes;
190
+
191
+ export { COUNTERFACTUAL_MAX_RESULTS, COUNTERFACTUAL_MIN_SAVINGS_RATIO, type ComputeCounterfactualsArgs, type GlassboxRoutes, type GlassboxRoutesConfig, TraceCounterfactual, TraceDetail, TraceSummary, computeCounterfactuals, createGlassboxRoutes, rowToDetail, rowToSummary };