@cognisos/liminal 2.5.0 → 2.5.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 (3) hide show
  1. package/dist/bin.js +566 -1120
  2. package/package.json +4 -3
  3. package/dist/bin.js.map +0 -1
package/dist/bin.js CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
6
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
7
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
8
  }) : x)(function(x) {
@@ -14,6 +16,15 @@ var __export = (target, all) => {
14
16
  for (var name in all)
15
17
  __defProp(target, name, { get: all[name], enumerable: true });
16
18
  };
19
+ var __copyProps = (to, from, except, desc) => {
20
+ if (from && typeof from === "object" || typeof from === "function") {
21
+ for (let key of __getOwnPropNames(from))
22
+ if (!__hasOwnProp.call(to, key) && key !== except)
23
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
+ }
25
+ return to;
26
+ };
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
17
28
 
18
29
  // src/ui/format.ts
19
30
  function disableColor() {
@@ -215,7 +226,7 @@ var init_version = __esm({
215
226
  "src/version.ts"() {
216
227
  "use strict";
217
228
  init_format();
218
- VERSION = true ? "2.5.0" : "2.5.0";
229
+ VERSION = true ? "2.5.1" : "2.5.0";
219
230
  BANNER_LINES = [
220
231
  " ___ ___ _____ ______ ___ ________ ________ ___",
221
232
  "|\\ \\ |\\ \\|\\ _ \\ _ \\|\\ \\|\\ ___ \\|\\ __ \\|\\ \\",
@@ -659,74 +670,6 @@ var init_prompts = __esm({
659
670
  }
660
671
  });
661
672
 
662
- // src/rsc/pipeline.ts
663
- var pipeline_exports = {};
664
- __export(pipeline_exports, {
665
- RSCPipelineWrapper: () => RSCPipelineWrapper
666
- });
667
- import {
668
- CompressionPipeline,
669
- RSCTransport,
670
- RSCEventEmitter,
671
- Session,
672
- CircuitBreaker
673
- } from "@cognisos/rsc-sdk";
674
- var RSCPipelineWrapper;
675
- var init_pipeline = __esm({
676
- "src/rsc/pipeline.ts"() {
677
- "use strict";
678
- RSCPipelineWrapper = class {
679
- pipeline;
680
- session;
681
- events;
682
- transport;
683
- circuitBreaker;
684
- constructor(config) {
685
- this.circuitBreaker = new CircuitBreaker(5, 5 * 60 * 1e3);
686
- this.transport = new RSCTransport({
687
- baseUrl: config.rscBaseUrl,
688
- apiKey: config.rscApiKey,
689
- timeout: 3e4,
690
- maxRetries: 3,
691
- circuitBreaker: this.circuitBreaker
692
- });
693
- this.events = new RSCEventEmitter();
694
- this.session = new Session(config.sessionId);
695
- this.pipeline = new CompressionPipeline(
696
- this.transport,
697
- {
698
- threshold: config.compressionThreshold,
699
- learnFromResponses: config.learnFromResponses,
700
- latencyBudgetMs: config.latencyBudgetMs,
701
- sessionId: this.session.sessionId
702
- },
703
- this.events
704
- );
705
- }
706
- async healthCheck() {
707
- try {
708
- await this.transport.get("/health");
709
- return true;
710
- } catch {
711
- return false;
712
- }
713
- }
714
- getSessionSummary() {
715
- return this.session.getSummary();
716
- }
717
- getCircuitState() {
718
- return this.circuitBreaker.getState();
719
- }
720
- isCircuitOpen() {
721
- return this.circuitBreaker.getState() === "open";
722
- }
723
- resetCircuitBreaker() {
724
- this.circuitBreaker.reset();
725
- }
726
- };
727
- }
728
- });
729
-
730
673
  // src/daemon/lifecycle.ts
731
674
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, existsSync as existsSync8 } from "fs";
732
675
  import { fork } from "child_process";
@@ -828,10 +771,35 @@ var init_aggregator = __esm({
828
771
  tools = /* @__PURE__ */ new Map();
829
772
  cursorMetrics = null;
830
773
  costPerMillionTokens;
774
+ /** Actual input_tokens from Anthropic API responses (verified ground truth) */
775
+ actualInputTokensTotal = 0;
776
+ /** Actual output_tokens from Anthropic API responses */
777
+ actualOutputTokensTotal = 0;
778
+ /** Pre-compression input token count from tokenizer */
779
+ originalInputEstimateTotal = 0;
780
+ /** Verified tokens saved: countTokens(pre) - countTokens(post) */
781
+ verifiedSavedTotal = 0;
782
+ /** Number of API responses with verified usage data */
783
+ verifiedRequestCount = 0;
831
784
  constructor(costPerMillionTokens = DEFAULT_COST_PER_MILLION_TOKENS) {
832
785
  this.costPerMillionTokens = costPerMillionTokens;
833
786
  }
834
787
  // ── Recording events ──────────────────────────────────────────────
788
+ /**
789
+ * Record verified token counts from an Anthropic API response.
790
+ *
791
+ * @param actualInput - usage.input_tokens from Anthropic (post-compression ground truth)
792
+ * @param actualOutput - usage.output_tokens from Anthropic (generated tokens ground truth)
793
+ * @param verifiedSaved - tokens saved, computed as countTokens(pre) - countTokens(post) using real tokenizer
794
+ * @param originalInputTokens - token count of full request before compression
795
+ */
796
+ recordApiUsage(actualInput, actualOutput, verifiedSaved, originalInputTokens) {
797
+ this.actualInputTokensTotal += actualInput;
798
+ this.actualOutputTokensTotal += actualOutput;
799
+ this.originalInputEstimateTotal += originalInputTokens;
800
+ this.verifiedSavedTotal += verifiedSaved;
801
+ this.verifiedRequestCount++;
802
+ }
835
803
  recordCompression(toolId, tokensProcessed, tokensSaved, latencyMs) {
836
804
  const m = this.getOrCreateTool(toolId);
837
805
  m.calls++;
@@ -899,10 +867,18 @@ var init_aggregator = __esm({
899
867
  for (const [id, m] of this.tools) {
900
868
  byTool[id] = { ...m };
901
869
  }
870
+ const verifiedInputSaved = this.verifiedSavedTotal;
871
+ const verifiedSavingsRate = this.originalInputEstimateTotal > 0 ? verifiedInputSaved / this.originalInputEstimateTotal : 0;
902
872
  return {
903
873
  sessionStartedAt: this.startedAt.toISOString(),
904
874
  uptimeMs,
905
875
  ...totals,
876
+ actualInputTokens: this.actualInputTokensTotal,
877
+ actualOutputTokens: this.actualOutputTokensTotal,
878
+ originalInputEstimate: this.originalInputEstimateTotal,
879
+ verifiedInputSaved,
880
+ verifiedSavingsRate,
881
+ verifiedRequestCount: this.verifiedRequestCount,
906
882
  savingsRate: rate,
907
883
  contextExtension: this.contextExtension(rate),
908
884
  estimatedCostSavedUsd: this.estimatedCostSaved(totals.tokensSaved),
@@ -1007,6 +983,101 @@ var init_store = __esm({
1007
983
  }
1008
984
  });
1009
985
 
986
+ // src/cursor/stats.ts
987
+ var stats_exports = {};
988
+ __export(stats_exports, {
989
+ parseCursorHookStats: () => parseCursorHookStats,
990
+ readCursorLogEntries: () => readCursorLogEntries
991
+ });
992
+ import { existsSync as existsSync10, readFileSync as readFileSync8, readdirSync } from "fs";
993
+ import { join as join7 } from "path";
994
+ function parseCursorHookStats(cwd = process.cwd()) {
995
+ const logPath = join7(cwd, ".fabric", "compress.log");
996
+ if (!existsSync10(logPath)) return null;
997
+ let compressions = 0, errors = 0;
998
+ let tokensProcessed = 0, tokensSaved = 0;
999
+ let apiMsSumMs = 0;
1000
+ const files = /* @__PURE__ */ new Set();
1001
+ const content = readFileSync8(logPath, "utf-8").trim();
1002
+ if (!content) return null;
1003
+ for (const line of content.split("\n")) {
1004
+ try {
1005
+ const entry = JSON.parse(line);
1006
+ if (entry.type === "compressed") {
1007
+ compressions++;
1008
+ tokensProcessed += entry.inputTokens ?? Math.ceil((entry.inputSize ?? 0) / 3);
1009
+ tokensSaved += entry.tokensSaved ?? 0;
1010
+ apiMsSumMs += entry.apiMs ?? 0;
1011
+ files.add(entry.file);
1012
+ } else if (entry.type === "error") {
1013
+ errors++;
1014
+ }
1015
+ } catch {
1016
+ }
1017
+ }
1018
+ let cacheCount = 0;
1019
+ try {
1020
+ cacheCount = countFilesRecursive(join7(cwd, ".fabric", "cache"));
1021
+ } catch {
1022
+ }
1023
+ return {
1024
+ files: files.size,
1025
+ compressions,
1026
+ errors,
1027
+ tokensProcessed,
1028
+ tokensSaved,
1029
+ apiMsSumMs,
1030
+ cacheCount
1031
+ };
1032
+ }
1033
+ function readCursorLogEntries(maxEntries = 50, cwd = process.cwd()) {
1034
+ const logPath = join7(cwd, ".fabric", "compress.log");
1035
+ if (!existsSync10(logPath)) return [];
1036
+ const content = readFileSync8(logPath, "utf-8").trim();
1037
+ if (!content) return [];
1038
+ const lines = content.split("\n");
1039
+ const recent = lines.slice(-maxEntries);
1040
+ const entries = [];
1041
+ for (const line of recent) {
1042
+ try {
1043
+ const entry = JSON.parse(line);
1044
+ const ts = entry.ts ? new Date(entry.ts) : /* @__PURE__ */ new Date();
1045
+ const time = ts.toTimeString().slice(0, 8);
1046
+ if (entry.type === "compressed") {
1047
+ const pct = entry.savedPct ?? (entry.inputTokens && entry.tokensSaved ? +(entry.tokensSaved / entry.inputTokens * 100).toFixed(1) : 0);
1048
+ entries.push({
1049
+ ts: entry.ts,
1050
+ line: `[${time}] [CURSOR] ${entry.file} \u2192 ${entry.tokensSaved} tok saved (${pct}%) ${entry.apiMs}ms`
1051
+ });
1052
+ } else if (entry.type === "error") {
1053
+ entries.push({
1054
+ ts: entry.ts,
1055
+ line: `[${time}] [CURSOR] ${entry.file} \u2192 ERROR: ${entry.error ?? "unknown"}`
1056
+ });
1057
+ }
1058
+ } catch {
1059
+ }
1060
+ }
1061
+ return entries;
1062
+ }
1063
+ function countFilesRecursive(dir) {
1064
+ if (!existsSync10(dir)) return 0;
1065
+ let count = 0;
1066
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
1067
+ if (entry.isDirectory()) {
1068
+ count += countFilesRecursive(join7(dir, entry.name));
1069
+ } else {
1070
+ count++;
1071
+ }
1072
+ }
1073
+ return count;
1074
+ }
1075
+ var init_stats = __esm({
1076
+ "src/cursor/stats.ts"() {
1077
+ "use strict";
1078
+ }
1079
+ });
1080
+
1010
1081
  // src/ui/screen.ts
1011
1082
  var SEQ, Screen;
1012
1083
  var init_screen = __esm({
@@ -1402,15 +1473,39 @@ var init_stats_view = __esm({
1402
1473
  lines.push(formatRow("Savings Rate", sRate, aRate, colW));
1403
1474
  lines.push(formatRow("Context Extension", sExt, aExt, colW));
1404
1475
  lines.push(blank());
1476
+ lines.push(divider("Verified (Anthropic API)", w));
1477
+ lines.push(blank());
1478
+ if (health && health.verifiedRequestCount && health.verifiedRequestCount > 0) {
1479
+ const actualIn = health.actualInputTokens ?? 0;
1480
+ const actualOut = health.actualOutputTokens ?? 0;
1481
+ const origEst = health.originalInputEstimate ?? 0;
1482
+ const saved = health.verifiedInputSaved ?? 0;
1483
+ const rate = health.verifiedSavingsRate ?? 0;
1484
+ const reqs = health.verifiedRequestCount;
1485
+ lines.push(formatRow("Input (actual)", formatNum(actualIn), "\u2014", colW));
1486
+ lines.push(formatRow("Input (pre-comp)", formatNum(origEst), "\u2014", colW));
1487
+ lines.push(formatRow("Input Saved", formatNum(saved), "\u2014", colW));
1488
+ lines.push(formatRow("Input Savings Rate", `${(rate * 100).toFixed(1)}%`, "\u2014", colW));
1489
+ lines.push(blank());
1490
+ lines.push(formatRow("Output (actual)", formatNum(actualOut), "\u2014", colW));
1491
+ lines.push(formatRow("Total (in + out)", formatNum(actualIn + actualOut), "\u2014", colW));
1492
+ lines.push(blank());
1493
+ lines.push(formatRow("Verified Requests", String(reqs), "\u2014", colW));
1494
+ } else {
1495
+ lines.push(` ${c.dim}No verified data yet \u2014 waiting for API responses${c.reset}`);
1496
+ }
1497
+ lines.push(blank());
1405
1498
  lines.push(divider("Cost Impact", w));
1406
1499
  lines.push(blank());
1407
1500
  lines.push(hdr);
1408
1501
  lines.push(sep);
1409
1502
  lines.push(formatRow("Est. Cost Saved", sCost, aCost, colW));
1410
1503
  lines.push(blank());
1504
+ let byToolRendered = false;
1411
1505
  if (health && health.sessions.length > 0) {
1412
1506
  lines.push(divider("By Tool", w));
1413
1507
  lines.push(blank());
1508
+ byToolRendered = true;
1414
1509
  const byTool = /* @__PURE__ */ new Map();
1415
1510
  for (const s of health.sessions) {
1416
1511
  const existing = byTool.get(s.connector) ?? { calls: 0, compressed: 0, failed: 0, processed: 0, saved: 0, p95: null };
@@ -1432,6 +1527,19 @@ var init_stats_view = __esm({
1432
1527
  lines.push(blank());
1433
1528
  }
1434
1529
  }
1530
+ if (health?.cursor) {
1531
+ const cur = health.cursor;
1532
+ if (!byToolRendered) {
1533
+ lines.push(divider("By Tool", w));
1534
+ lines.push(blank());
1535
+ }
1536
+ const curPct = cur.tokensProcessed > 0 ? `${(cur.tokensSaved / cur.tokensProcessed * 100).toFixed(1)}%` : "\u2014";
1537
+ const avgMs = cur.compressions > 0 ? Math.round(cur.apiMsSumMs / cur.compressions) : 0;
1538
+ lines.push(`${c.bold}${formatLabel("cursor")}${c.reset}`);
1539
+ lines.push(` Files: ${cur.files} unique (${cur.compressions} compressions${cur.errors > 0 ? `, ${c.red}${cur.errors} errors${c.reset}` : ""}) | Saved: ${formatNum(cur.tokensSaved)} tok (${curPct})`);
1540
+ lines.push(` Cache: ${cur.cacheCount} files | Avg API: ${avgMs}ms/file`);
1541
+ lines.push(blank());
1542
+ }
1435
1543
  if (cum.sessionCount > 0) {
1436
1544
  lines.push(`${c.dim}${cum.sessionCount} session${cum.sessionCount !== 1 ? "s" : ""} recorded${c.reset}`);
1437
1545
  }
@@ -1473,6 +1581,17 @@ var init_config_view = __esm({
1473
1581
  });
1474
1582
 
1475
1583
  // src/ui/views/logs-view.ts
1584
+ function getCursorLogs() {
1585
+ if (!_readCursorLogs) {
1586
+ try {
1587
+ const mod = (init_stats(), __toCommonJS(stats_exports));
1588
+ _readCursorLogs = () => mod.readCursorLogEntries(50);
1589
+ } catch {
1590
+ _readCursorLogs = () => [];
1591
+ }
1592
+ }
1593
+ return _readCursorLogs();
1594
+ }
1476
1595
  function colorizeLog(line, maxWidth) {
1477
1596
  const display = line.length > maxWidth ? line.slice(0, maxWidth - 1) + "\u2026" : line;
1478
1597
  const match = display.match(/^\[(\d{2}:\d{2}:\d{2}(?:\.\d+)?)\]\s*(.*)$/);
@@ -1495,21 +1614,33 @@ function colorizeLog(line, maxWidth) {
1495
1614
  }
1496
1615
  return `${c.dim}${ts} ${rest}${c.reset}`;
1497
1616
  }
1498
- var logsView;
1617
+ var _readCursorLogs, logsView;
1499
1618
  var init_logs_view = __esm({
1500
1619
  "src/ui/views/logs-view.ts"() {
1501
1620
  "use strict";
1502
1621
  init_format();
1503
1622
  init_layout();
1623
+ _readCursorLogs = null;
1504
1624
  logsView = {
1505
1625
  id: "logs",
1506
1626
  label: "Logs",
1507
1627
  render(state, size) {
1508
1628
  const lines = [];
1509
1629
  const w = Math.max(40, size.cols - 6);
1510
- lines.push(divider("Daemon Logs", w));
1630
+ lines.push(divider("All Logs", w));
1511
1631
  lines.push(blank());
1512
- if (state.recentLogs.length === 0) {
1632
+ const cursorEntries = getCursorLogs();
1633
+ const allLogs = [];
1634
+ for (const line of state.recentLogs) {
1635
+ const match = line.match(/^\[(\d{2}:\d{2}:\d{2}(?:\.\d+)?)\]/);
1636
+ allLogs.push({ ts: match?.[1] ?? "99:99:99", line, source: "daemon" });
1637
+ }
1638
+ for (const entry of cursorEntries) {
1639
+ allLogs.push({ ts: entry.ts, line: entry.line, source: "cursor" });
1640
+ }
1641
+ const daemonLogs = state.recentLogs;
1642
+ const combined = [...daemonLogs, ...cursorEntries.map((e) => e.line)];
1643
+ if (combined.length === 0) {
1513
1644
  if (!state.daemonRunning) {
1514
1645
  lines.push(`${c.dim}Daemon not running \u2014 no logs to show.${c.reset}`);
1515
1646
  } else {
@@ -1519,12 +1650,12 @@ var init_logs_view = __esm({
1519
1650
  return lines;
1520
1651
  }
1521
1652
  const maxLines = Math.max(5, size.rows - 7);
1522
- const tail = state.recentLogs.slice(-maxLines);
1653
+ const tail = combined.slice(-maxLines);
1523
1654
  for (const line of tail) {
1524
1655
  lines.push(colorizeLog(line, w));
1525
1656
  }
1526
1657
  lines.push(blank());
1527
- lines.push(`${c.dim}Showing last ${tail.length} lines \u2014 refreshes every 2s${c.reset}`);
1658
+ lines.push(`${c.dim}Showing last ${tail.length} lines (daemon + cursor) \u2014 refreshes every 2s${c.reset}`);
1528
1659
  return lines;
1529
1660
  }
1530
1661
  };
@@ -1536,7 +1667,7 @@ var hub_exports = {};
1536
1667
  __export(hub_exports, {
1537
1668
  runHub: () => runHub
1538
1669
  });
1539
- import { existsSync as existsSync15, statSync as statSync3 } from "fs";
1670
+ import { existsSync as existsSync16, statSync as statSync3 } from "fs";
1540
1671
  function createInitialState() {
1541
1672
  const state = {
1542
1673
  health: null,
@@ -1597,7 +1728,7 @@ async function refreshState(state) {
1597
1728
  }
1598
1729
  function tailLogFile(maxLines) {
1599
1730
  try {
1600
- if (!existsSync15(LOG_FILE)) return [];
1731
+ if (!existsSync16(LOG_FILE)) return [];
1601
1732
  const stat = statSync3(LOG_FILE);
1602
1733
  const readSize = Math.min(stat.size, 32 * 1024);
1603
1734
  if (readSize === 0) return [];
@@ -1823,8 +1954,8 @@ import { stdin, stdout } from "process";
1823
1954
 
1824
1955
  // src/auth/supabase.ts
1825
1956
  import { randomBytes, createHash } from "crypto";
1826
- var SUPABASE_URL = "https://nzcneiyymvgxvttbenhp.supabase.co";
1827
- var SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im56Y25laXl5bXZneHZ0dGJlbmhwIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQwNjQ0MjcsImV4cCI6MjA2OTY0MDQyN30.x3E-zGRadbPMmxRqT_PB_KOi00htKpgeb8GiQa4g2z0";
1957
+ var SUPABASE_URL = process.env.LIMINAL_SUPABASE_URL || "https://nzcneiyymvgxvttbenhp.supabase.co";
1958
+ var SUPABASE_ANON_KEY = process.env.LIMINAL_SUPABASE_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im56Y25laXl5bXZneHZ0dGJlbmhwIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQwNjQ0MjcsImV4cCI6MjA2OTY0MDQyN30.x3E-zGRadbPMmxRqT_PB_KOi00htKpgeb8GiQa4g2z0";
1828
1959
  function supabaseHeaders(accessToken) {
1829
1960
  const headers = {
1830
1961
  "Content-Type": "application/json",
@@ -1907,18 +2038,37 @@ async function createApiKey(accessToken, userId, source = "cli") {
1907
2038
  );
1908
2039
  const apiKey = `${prefix}${randomBytes(32).toString("hex")}`;
1909
2040
  const keyHash = createHash("sha256").update(apiKey).digest("hex");
2041
+ let projectId;
2042
+ let orgId;
2043
+ try {
2044
+ const projRes = await fetch(
2045
+ `${SUPABASE_URL}/rest/v1/projects?id=eq.${userId}&select=id,org_id&limit=1`,
2046
+ { headers: supabaseHeaders(accessToken), signal: AbortSignal.timeout(1e4) }
2047
+ );
2048
+ if (projRes.ok) {
2049
+ const rows = await projRes.json();
2050
+ if (Array.isArray(rows) && rows.length > 0) {
2051
+ projectId = rows[0].id;
2052
+ orgId = rows[0].org_id;
2053
+ }
2054
+ }
2055
+ } catch {
2056
+ }
2057
+ const insertPayload = {
2058
+ user_id: userId,
2059
+ key_name: keyName,
2060
+ key_hash: keyHash,
2061
+ is_active: true
2062
+ };
2063
+ if (projectId) insertPayload.project_id = projectId;
2064
+ if (orgId) insertPayload.organization_id = orgId;
1910
2065
  const res = await fetch(`${SUPABASE_URL}/rest/v1/user_api_keys`, {
1911
2066
  method: "POST",
1912
2067
  headers: {
1913
2068
  ...supabaseHeaders(accessToken),
1914
2069
  "Prefer": "return=representation"
1915
2070
  },
1916
- body: JSON.stringify({
1917
- user_id: userId,
1918
- key_name: keyName,
1919
- key_hash: keyHash,
1920
- is_active: true
1921
- })
2071
+ body: JSON.stringify(insertPayload)
1922
2072
  });
1923
2073
  if (!res.ok) {
1924
2074
  const body = await res.json().catch(() => ({}));
@@ -2413,7 +2563,7 @@ import forge from "node-forge";
2413
2563
  var CA_CERT_PATH = join5(LIMINAL_DIR, "ca.pem");
2414
2564
  var CA_KEY_PATH = join5(LIMINAL_DIR, "ca-key.pem");
2415
2565
  function generateCA() {
2416
- const keys = forge.pki.rsa.generateKeyPair(2048);
2566
+ const keys = forge.pki.rsa.generateKeyPair(4096);
2417
2567
  const cert = forge.pki.createCertificate();
2418
2568
  cert.publicKey = keys.publicKey;
2419
2569
  cert.serialNumber = generateSerialNumber();
@@ -2814,7 +2964,7 @@ var verificationStep = {
2814
2964
  async execute(ctx) {
2815
2965
  console.log(` Running health checks...`);
2816
2966
  console.log();
2817
- const { RSCPipelineWrapper: RSCPipelineWrapper2 } = await Promise.resolve().then(() => (init_pipeline(), pipeline_exports));
2967
+ const { RSCPipelineWrapper: RSCPipelineWrapper2 } = await import("@cognisos/proxy-core");
2818
2968
  const config = loadConfig();
2819
2969
  const probe = new RSCPipelineWrapper2({
2820
2970
  rscApiKey: config.apiKey,
@@ -2899,9 +3049,9 @@ async function initCommand() {
2899
3049
  console.log();
2900
3050
  }
2901
3051
  async function checkPort(port) {
2902
- const { createServer: createServer2 } = await import("net");
3052
+ const { createServer } = await import("net");
2903
3053
  return new Promise((resolve) => {
2904
- const server = createServer2();
3054
+ const server = createServer();
2905
3055
  server.once("error", () => resolve(false));
2906
3056
  server.once("listening", () => {
2907
3057
  server.close(() => resolve(true));
@@ -2924,632 +3074,18 @@ async function logoutCommand() {
2924
3074
 
2925
3075
  // src/commands/start.ts
2926
3076
  init_loader();
3077
+ import { writeFileSync as writeFileSync6 } from "fs";
3078
+ import { join as join8 } from "path";
3079
+ import { homedir as homedir5 } from "os";
2927
3080
 
2928
3081
  // src/proxy/completions.ts
2929
- import { RSCCircuitOpenError as RSCCircuitOpenError2 } from "@cognisos/rsc-sdk";
2930
-
2931
- // src/rsc/message-compressor.ts
2932
3082
  import { RSCCircuitOpenError } from "@cognisos/rsc-sdk";
2933
-
2934
- // src/rsc/content-segmenter.ts
2935
- function segmentContent(text) {
2936
- if (text.length === 0) return [{ type: "prose", text: "" }];
2937
- const segments = [];
2938
- const lines = text.split("\n");
2939
- let i = 0;
2940
- let proseBuf = [];
2941
- function flushProse() {
2942
- if (proseBuf.length > 0) {
2943
- segments.push({ type: "prose", text: proseBuf.join("\n") });
2944
- proseBuf = [];
2945
- }
2946
- }
2947
- while (i < lines.length) {
2948
- const line = lines[i];
2949
- const fenceMatch = matchFenceOpen(line);
2950
- if (fenceMatch) {
2951
- if (proseBuf.length > 0) {
2952
- flushProse();
2953
- segments[segments.length - 1].text += "\n";
2954
- }
2955
- const codeBuf = [line];
2956
- i++;
2957
- let closed = false;
2958
- while (i < lines.length) {
2959
- codeBuf.push(lines[i]);
2960
- if (matchFenceClose(lines[i], fenceMatch.char, fenceMatch.length)) {
2961
- closed = true;
2962
- i++;
2963
- break;
2964
- }
2965
- i++;
2966
- }
2967
- let codeText = codeBuf.join("\n");
2968
- if (i < lines.length) {
2969
- codeText += "\n";
2970
- }
2971
- segments.push({ type: "code", text: codeText });
2972
- continue;
2973
- }
2974
- if (isIndentedCodeLine(line)) {
2975
- if (proseBuf.length > 0) {
2976
- flushProse();
2977
- segments[segments.length - 1].text += "\n";
2978
- }
2979
- const codeBuf = [line];
2980
- i++;
2981
- while (i < lines.length) {
2982
- if (isIndentedCodeLine(lines[i])) {
2983
- codeBuf.push(lines[i]);
2984
- i++;
2985
- } else if (lines[i].trim() === "" && i + 1 < lines.length && isIndentedCodeLine(lines[i + 1])) {
2986
- codeBuf.push(lines[i]);
2987
- i++;
2988
- } else {
2989
- break;
2990
- }
2991
- }
2992
- let codeText = codeBuf.join("\n");
2993
- if (i < lines.length) {
2994
- codeText += "\n";
2995
- }
2996
- segments.push({ type: "code", text: codeText });
2997
- continue;
2998
- }
2999
- if (proseBuf.length > 0) {
3000
- proseBuf.push(line);
3001
- } else {
3002
- proseBuf.push(line);
3003
- }
3004
- i++;
3005
- }
3006
- if (proseBuf.length > 0) {
3007
- flushProse();
3008
- }
3009
- if (segments.length === 0) {
3010
- return [{ type: "prose", text }];
3011
- }
3012
- return segments;
3013
- }
3014
- function matchFenceOpen(line) {
3015
- const match = line.match(/^( {0,3})((`{3,})|~{3,})(.*)$/);
3016
- if (!match) return null;
3017
- const fenceStr = match[2];
3018
- const char = fenceStr[0];
3019
- if (char === "`" && match[4] && match[4].includes("`")) return null;
3020
- return { char, length: fenceStr.length };
3021
- }
3022
- function matchFenceClose(line, char, minLength) {
3023
- const match = line.match(/^( {0,3})((`{3,})|(~{3,}))\s*$/);
3024
- if (!match) return false;
3025
- const fenceStr = match[2];
3026
- return fenceStr[0] === char && fenceStr.length >= minLength;
3027
- }
3028
- function isIndentedCodeLine(line) {
3029
- return (line.startsWith(" ") || line.startsWith(" ")) && line.trim().length > 0;
3030
- }
3031
-
3032
- // src/rsc/message-compressor.ts
3033
- var PASSTHROUGH_BLOCK_TYPES = /* @__PURE__ */ new Set(["thinking", "tool_use", "image"]);
3034
- function sanitizeCompressedText(text) {
3035
- return text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
3036
- }
3037
- async function compressMessages(messages, pipeline, session, compressRoles) {
3038
- let anyCompressed = false;
3039
- let totalTokensSaved = 0;
3040
- const compressed = await Promise.all(
3041
- messages.map(async (msg) => {
3042
- if (!compressRoles.has(msg.role)) return msg;
3043
- return compressMessage(msg, pipeline, session, (c2, saved) => {
3044
- anyCompressed = anyCompressed || c2;
3045
- totalTokensSaved += saved;
3046
- });
3047
- })
3048
- );
3049
- return { messages: compressed, anyCompressed, totalTokensSaved };
3050
- }
3051
- async function compressConversation(pipeline, session, plan, options = { compressToolResults: true }) {
3052
- if (!plan.shouldCompress) {
3053
- return {
3054
- messages: plan.messages.map((tm) => tm.message),
3055
- anyCompressed: false,
3056
- totalTokensSaved: 0
3057
- };
3058
- }
3059
- const log = options.logFn;
3060
- const threshold = options.compressionThreshold ?? 100;
3061
- const results = new Array(plan.messages.length);
3062
- const compressible = [];
3063
- for (let i = 0; i < plan.messages.length; i++) {
3064
- const tm = plan.messages[i];
3065
- const role = tm.message.role;
3066
- const blockTypes = Array.isArray(tm.message.content) ? tm.message.content.map((b) => b.type).join(",") : "string";
3067
- if (tm.tier === "hot") {
3068
- log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] \u2192 HOT (verbatim)`);
3069
- results[i] = tm.message;
3070
- continue;
3071
- }
3072
- if (tm.eligibleTokens === 0) {
3073
- log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] \u2192 ${tm.tier.toUpperCase()} (0 eligible tok, skip)`);
3074
- results[i] = tm.message;
3075
- continue;
3076
- }
3077
- const proseEstimate = estimateProseTokens(tm.message, options.compressToolResults);
3078
- if (proseEstimate < threshold) {
3079
- log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] \u2192 ${tm.tier.toUpperCase()} (${proseEstimate} prose tok after segmentation < ${threshold} threshold, skip)`);
3080
- results[i] = tm.message;
3081
- continue;
3082
- }
3083
- const { batchText, batchedIndices } = extractBatchableText(tm.message, options.compressToolResults);
3084
- if (!batchText) {
3085
- results[i] = tm.message;
3086
- continue;
3087
- }
3088
- log?.(`[BLOCK] #${tm.index} ${role} [${blockTypes}] \u2192 ${tm.tier.toUpperCase()} (${tm.eligibleTokens} eligible tok, ~${proseEstimate} prose tok, batching)`);
3089
- compressible.push({ planIdx: i, tm, batchText, batchedIndices });
3090
- }
3091
- if (compressible.length === 0) {
3092
- return {
3093
- messages: results,
3094
- anyCompressed: false,
3095
- totalTokensSaved: 0
3096
- };
3097
- }
3098
- let anyCompressed = false;
3099
- let totalTokensSaved = 0;
3100
- if (options.semaphore) await options.semaphore.acquire(options.semaphoreTimeoutMs);
3101
- try {
3102
- const batchSegments = compressible.map((entry) => ({
3103
- index: entry.planIdx,
3104
- text: entry.batchText
3105
- }));
3106
- const batchResults = await pipeline.normalizeBatch(batchSegments);
3107
- for (const entry of compressible) {
3108
- const result = batchResults.get(entry.planIdx);
3109
- if (!result || result.metrics.skipped) {
3110
- results[entry.planIdx] = entry.tm.message;
3111
- continue;
3112
- }
3113
- const compressed = sanitizeCompressedText(result.text);
3114
- const saved = Math.max(0, result.metrics.tokensSaved);
3115
- if (saved > 0) {
3116
- anyCompressed = true;
3117
- totalTokensSaved += saved;
3118
- }
3119
- session.recordCompression(result.metrics);
3120
- results[entry.planIdx] = reassembleMessage(entry.tm.message, compressed, entry.batchedIndices);
3121
- }
3122
- } catch (err) {
3123
- const errMsg = err instanceof Error ? err.message : String(err);
3124
- if (err instanceof RSCCircuitOpenError) {
3125
- session.recordFailure();
3126
- log?.(`[COMPRESS-ERROR] Circuit open \u2014 passing through (${errMsg})`);
3127
- } else {
3128
- log?.(`[COMPRESS-ERROR] ${errMsg}`);
3129
- }
3130
- for (const entry of compressible) {
3131
- if (!results[entry.planIdx]) {
3132
- results[entry.planIdx] = entry.tm.message;
3133
- }
3134
- }
3135
- } finally {
3136
- if (options.semaphore) options.semaphore.release();
3137
- }
3138
- return { messages: results, anyCompressed, totalTokensSaved };
3139
- }
3140
- function extractBatchableText(msg, compressToolResults) {
3141
- const batchedIndices = /* @__PURE__ */ new Set();
3142
- if (typeof msg.content === "string") {
3143
- if (msg.content.trim()) {
3144
- return { batchText: msg.content, batchedIndices };
3145
- }
3146
- return { batchText: null, batchedIndices };
3147
- }
3148
- if (!Array.isArray(msg.content)) return { batchText: null, batchedIndices };
3149
- const parts = msg.content;
3150
- const textSegments = [];
3151
- for (let i = 0; i < parts.length; i++) {
3152
- const part = parts[i];
3153
- if (PASSTHROUGH_BLOCK_TYPES.has(part.type)) continue;
3154
- if (part.type === "text" && typeof part.text === "string" && part.text.trim()) {
3155
- textSegments.push(part.text);
3156
- batchedIndices.add(i);
3157
- }
3158
- if (part.type === "tool_result" && compressToolResults) {
3159
- const extracted = extractToolResultText(part);
3160
- if (extracted) {
3161
- textSegments.push(extracted);
3162
- batchedIndices.add(i);
3163
- }
3164
- }
3165
- }
3166
- return {
3167
- batchText: textSegments.length > 0 ? textSegments.join("\n\n") : null,
3168
- batchedIndices
3169
- };
3170
- }
3171
- function reassembleMessage(msg, compressedText, batchedIndices) {
3172
- if (typeof msg.content === "string") {
3173
- return { ...msg, content: compressedText };
3174
- }
3175
- if (!Array.isArray(msg.content)) return msg;
3176
- const parts = msg.content;
3177
- const newParts = [];
3178
- let isFirstEligible = true;
3179
- for (let i = 0; i < parts.length; i++) {
3180
- if (!batchedIndices.has(i)) {
3181
- newParts.push(parts[i]);
3182
- continue;
3183
- }
3184
- if (isFirstEligible) {
3185
- if (parts[i].type === "text") {
3186
- newParts.push({ ...parts[i], text: compressedText });
3187
- } else if (parts[i].type === "tool_result") {
3188
- newParts.push({ ...parts[i], content: compressedText });
3189
- }
3190
- isFirstEligible = false;
3191
- } else {
3192
- if (parts[i].type === "tool_result") {
3193
- newParts.push({ ...parts[i], content: "" });
3194
- }
3195
- }
3196
- }
3197
- return { ...msg, content: newParts };
3198
- }
3199
- function estimateProseTokens(msg, compressToolResults) {
3200
- const text = extractCompressibleText(msg, compressToolResults);
3201
- if (!text) return 0;
3202
- const segments = segmentContent(text);
3203
- return segments.filter((s) => s.type === "prose").reduce((sum, s) => sum + Math.ceil(s.text.length / 4), 0);
3204
- }
3205
- function extractCompressibleText(msg, compressToolResults) {
3206
- if (typeof msg.content === "string") {
3207
- return msg.content.trim() ? msg.content : null;
3208
- }
3209
- if (!Array.isArray(msg.content)) return null;
3210
- const parts = msg.content;
3211
- const textSegments = [];
3212
- for (const part of parts) {
3213
- if (PASSTHROUGH_BLOCK_TYPES.has(part.type)) continue;
3214
- if (part.type === "text" && typeof part.text === "string" && part.text.trim()) {
3215
- textSegments.push(part.text);
3216
- }
3217
- if (part.type === "tool_result" && compressToolResults) {
3218
- const extracted = extractToolResultText(part);
3219
- if (extracted) textSegments.push(extracted);
3220
- }
3221
- }
3222
- return textSegments.length > 0 ? textSegments.join("\n\n") : null;
3223
- }
3224
- function extractToolResultText(part) {
3225
- if (typeof part.content === "string" && part.content.trim()) {
3226
- return part.content;
3227
- }
3228
- if (Array.isArray(part.content)) {
3229
- const texts = part.content.filter((inner) => inner.type === "text" && typeof inner.text === "string" && inner.text.trim()).map((inner) => inner.text);
3230
- return texts.length > 0 ? texts.join("\n") : null;
3231
- }
3232
- return null;
3233
- }
3234
- async function compressMessage(msg, pipeline, session, record, options = { compressToolResults: true }) {
3235
- if (typeof msg.content === "string") {
3236
- return compressStringContent(msg, pipeline, session, record);
3237
- }
3238
- if (Array.isArray(msg.content)) {
3239
- return compressArrayContent(msg, pipeline, session, record, options);
3240
- }
3241
- return msg;
3242
- }
3243
- async function compressStringContent(msg, pipeline, session, record, semaphore, semaphoreTimeoutMs) {
3244
- const text = msg.content;
3245
- try {
3246
- const compressed = await compressTextWithSegmentation(text, pipeline, session, record, semaphore, semaphoreTimeoutMs);
3247
- return { ...msg, content: compressed };
3248
- } catch (err) {
3249
- if (err instanceof RSCCircuitOpenError) {
3250
- session.recordFailure();
3251
- throw err;
3252
- }
3253
- session.recordFailure();
3254
- return msg;
3255
- }
3256
- }
3257
- async function compressArrayContent(msg, pipeline, session, record, options = { compressToolResults: true }) {
3258
- const parts = msg.content;
3259
- const compressedParts = await Promise.all(
3260
- parts.map(async (part) => {
3261
- if (PASSTHROUGH_BLOCK_TYPES.has(part.type)) return part;
3262
- if (part.type === "text" && typeof part.text === "string") {
3263
- try {
3264
- const compressed = await compressTextWithSegmentation(part.text, pipeline, session, record);
3265
- return { ...part, text: compressed };
3266
- } catch (err) {
3267
- if (err instanceof RSCCircuitOpenError) {
3268
- session.recordFailure();
3269
- throw err;
3270
- }
3271
- session.recordFailure();
3272
- return part;
3273
- }
3274
- }
3275
- if (part.type === "tool_result" && options.compressToolResults) {
3276
- return compressToolResult(part, pipeline, session, record);
3277
- }
3278
- return part;
3279
- })
3280
- );
3281
- return { ...msg, content: compressedParts };
3282
- }
3283
- async function compressToolResult(part, pipeline, session, record) {
3284
- const content = part.content;
3285
- if (typeof content === "string") {
3286
- try {
3287
- const compressed = await compressTextWithSegmentation(content, pipeline, session, record);
3288
- return { ...part, content: compressed };
3289
- } catch (err) {
3290
- if (err instanceof RSCCircuitOpenError) {
3291
- session.recordFailure();
3292
- throw err;
3293
- }
3294
- session.recordFailure();
3295
- return part;
3296
- }
3297
- }
3298
- if (Array.isArray(content)) {
3299
- try {
3300
- const compressedInner = await Promise.all(
3301
- content.map(async (inner) => {
3302
- if (inner.type === "text" && typeof inner.text === "string") {
3303
- try {
3304
- const compressed = await compressTextWithSegmentation(inner.text, pipeline, session, record);
3305
- return { ...inner, text: compressed };
3306
- } catch (err) {
3307
- if (err instanceof RSCCircuitOpenError) throw err;
3308
- session.recordFailure();
3309
- return inner;
3310
- }
3311
- }
3312
- return inner;
3313
- })
3314
- );
3315
- return { ...part, content: compressedInner };
3316
- } catch (err) {
3317
- if (err instanceof RSCCircuitOpenError) {
3318
- session.recordFailure();
3319
- throw err;
3320
- }
3321
- session.recordFailure();
3322
- return part;
3323
- }
3324
- }
3325
- return part;
3326
- }
3327
- async function compressTextWithSegmentation(text, pipeline, session, record, semaphore, semaphoreTimeoutMs) {
3328
- const segments = segmentContent(text);
3329
- const hasCode = segments.some((s) => s.type === "code");
3330
- if (!hasCode) {
3331
- if (semaphore) await semaphore.acquire(semaphoreTimeoutMs);
3332
- try {
3333
- const result = await pipeline.compressForLLM(text);
3334
- session.recordCompression(result.metrics);
3335
- const saved = Math.max(0, result.metrics.tokensSaved);
3336
- record(!result.metrics.skipped, saved);
3337
- return sanitizeCompressedText(result.text);
3338
- } finally {
3339
- if (semaphore) semaphore.release();
3340
- }
3341
- }
3342
- const parts = await Promise.all(
3343
- segments.map(async (seg) => {
3344
- if (seg.type === "code") return seg.text;
3345
- if (seg.text.trim().length === 0) return seg.text;
3346
- if (semaphore) await semaphore.acquire(semaphoreTimeoutMs);
3347
- try {
3348
- const result = await pipeline.compressForLLM(seg.text);
3349
- session.recordCompression(result.metrics);
3350
- const saved = Math.max(0, result.metrics.tokensSaved);
3351
- record(!result.metrics.skipped, saved);
3352
- return sanitizeCompressedText(result.text);
3353
- } catch (err) {
3354
- if (err instanceof RSCCircuitOpenError) throw err;
3355
- session.recordFailure();
3356
- return seg.text;
3357
- } finally {
3358
- if (semaphore) semaphore.release();
3359
- }
3360
- })
3361
- );
3362
- return parts.join("");
3363
- }
3364
-
3365
- // src/rsc/conversation-analyzer.ts
3366
- var SKIP_BLOCK_TYPES = /* @__PURE__ */ new Set(["thinking", "tool_use", "image"]);
3367
- function estimateTokens(text) {
3368
- return Math.ceil(text.length / 4);
3369
- }
3370
- function estimateBlockTokens(block, compressToolResults) {
3371
- if (SKIP_BLOCK_TYPES.has(block.type)) return 0;
3372
- if (block.type === "text" && typeof block.text === "string") {
3373
- return estimateTokens(block.text);
3374
- }
3375
- if (block.type === "tool_result" && compressToolResults) {
3376
- if (typeof block.content === "string") {
3377
- return estimateTokens(block.content);
3378
- }
3379
- if (Array.isArray(block.content)) {
3380
- return block.content.reduce(
3381
- (sum, inner) => sum + estimateBlockTokens(inner, compressToolResults),
3382
- 0
3383
- );
3384
- }
3385
- }
3386
- return 0;
3387
- }
3388
- function estimateMessageTokens(msg, config) {
3389
- if (!config.compressRoles.has(msg.role)) return 0;
3390
- if (typeof msg.content === "string") {
3391
- return estimateTokens(msg.content);
3392
- }
3393
- if (Array.isArray(msg.content)) {
3394
- return msg.content.reduce(
3395
- (sum, part) => sum + estimateBlockTokens(part, config.compressToolResults),
3396
- 0
3397
- );
3398
- }
3399
- return 0;
3400
- }
3401
- function analyzeConversation(messages, config) {
3402
- const n = messages.length;
3403
- if (n < 5) {
3404
- const tiered2 = messages.map((msg, i) => ({
3405
- index: i,
3406
- message: msg,
3407
- tier: "hot",
3408
- eligibleTokens: estimateMessageTokens(msg, config)
3409
- }));
3410
- return {
3411
- messages: tiered2,
3412
- totalEligibleTokens: 0,
3413
- shouldCompress: false,
3414
- hotCount: n,
3415
- warmCount: 0,
3416
- coldCount: 0
3417
- };
3418
- }
3419
- const coldEnd = Math.floor(n * config.coldFraction);
3420
- const hotStart = n - Math.floor(n * config.hotFraction);
3421
- let totalEligibleTokens = 0;
3422
- let hotCount = 0;
3423
- let warmCount = 0;
3424
- let coldCount = 0;
3425
- const tiered = messages.map((msg, i) => {
3426
- let tier;
3427
- if (i >= hotStart) {
3428
- tier = "hot";
3429
- hotCount++;
3430
- } else if (i < coldEnd) {
3431
- tier = "cold";
3432
- coldCount++;
3433
- } else {
3434
- tier = "warm";
3435
- warmCount++;
3436
- }
3437
- const eligibleTokens = estimateMessageTokens(msg, config);
3438
- if (tier !== "hot") {
3439
- totalEligibleTokens += eligibleTokens;
3440
- }
3441
- return { index: i, message: msg, tier, eligibleTokens };
3442
- });
3443
- return {
3444
- messages: tiered,
3445
- totalEligibleTokens,
3446
- shouldCompress: totalEligibleTokens >= config.aggregateThreshold,
3447
- hotCount,
3448
- warmCount,
3449
- coldCount
3450
- };
3451
- }
3452
-
3453
- // src/rsc/learning.ts
3454
- function createStreamLearningBuffer(pipeline) {
3455
- let buffer = "";
3456
- return {
3457
- /** Append a text delta from an SSE chunk */
3458
- append(text) {
3459
- buffer += text;
3460
- },
3461
- /** Flush the buffer — triggers fire-and-forget learning */
3462
- flush() {
3463
- if (buffer.length > 0) {
3464
- pipeline.triggerLearning(buffer);
3465
- buffer = "";
3466
- }
3467
- },
3468
- /** Get current buffer contents (for testing) */
3469
- getBuffer() {
3470
- return buffer;
3471
- }
3472
- };
3473
- }
3474
-
3475
- // src/proxy/streaming.ts
3476
- async function pipeSSEResponse(upstreamResponse, clientRes, onContentDelta, onComplete, totalTokensSaved = 0) {
3477
- clientRes.writeHead(200, {
3478
- "Content-Type": "text/event-stream",
3479
- "Cache-Control": "no-cache",
3480
- "Connection": "keep-alive",
3481
- "Access-Control-Allow-Origin": "*"
3482
- });
3483
- const reader = upstreamResponse.body.getReader();
3484
- const decoder = new TextDecoder();
3485
- let lineBuf = "";
3486
- const needsAdjustment = totalTokensSaved > 0;
3487
- try {
3488
- while (true) {
3489
- const { done, value } = await reader.read();
3490
- if (done) break;
3491
- const chunk = decoder.decode(value, { stream: true });
3492
- if (!needsAdjustment) {
3493
- clientRes.write(chunk);
3494
- lineBuf += chunk;
3495
- const lines2 = lineBuf.split("\n");
3496
- lineBuf = lines2.pop() || "";
3497
- for (const line of lines2) {
3498
- if (line.startsWith("data: ") && line !== "data: [DONE]") {
3499
- try {
3500
- const json = JSON.parse(line.slice(6));
3501
- const content = json?.choices?.[0]?.delta?.content;
3502
- if (typeof content === "string") {
3503
- onContentDelta(content);
3504
- }
3505
- } catch {
3506
- }
3507
- }
3508
- }
3509
- continue;
3510
- }
3511
- lineBuf += chunk;
3512
- const lines = lineBuf.split("\n");
3513
- lineBuf = lines.pop() || "";
3514
- let adjusted = false;
3515
- const outputLines = [];
3516
- for (const line of lines) {
3517
- if (line.startsWith("data: ") && line !== "data: [DONE]") {
3518
- try {
3519
- const json = JSON.parse(line.slice(6));
3520
- if (json?.usage?.prompt_tokens != null) {
3521
- json.usage.prompt_tokens += totalTokensSaved;
3522
- if (json.usage.total_tokens != null) {
3523
- json.usage.total_tokens += totalTokensSaved;
3524
- }
3525
- outputLines.push(`data: ${JSON.stringify(json)}`);
3526
- adjusted = true;
3527
- } else {
3528
- outputLines.push(line);
3529
- }
3530
- const content = json?.choices?.[0]?.delta?.content;
3531
- if (typeof content === "string") {
3532
- onContentDelta(content);
3533
- }
3534
- } catch {
3535
- outputLines.push(line);
3536
- }
3537
- } else {
3538
- outputLines.push(line);
3539
- }
3540
- }
3541
- if (adjusted) {
3542
- const reconstructed = outputLines.join("\n") + "\n";
3543
- clientRes.write(reconstructed);
3544
- } else {
3545
- clientRes.write(chunk);
3546
- }
3547
- }
3548
- } finally {
3549
- clientRes.end();
3550
- onComplete();
3551
- }
3552
- }
3083
+ import {
3084
+ compressConversation,
3085
+ analyzeConversation,
3086
+ createStreamLearningBuffer,
3087
+ pipeSSEResponse
3088
+ } from "@cognisos/proxy-core";
3553
3089
 
3554
3090
  // src/terminology.ts
3555
3091
  var TIER_LABELS = {
@@ -3586,7 +3122,7 @@ function extractBearerToken(req) {
3586
3122
  if (!auth || !auth.startsWith("Bearer ")) return null;
3587
3123
  return auth.slice(7);
3588
3124
  }
3589
- async function handleChatCompletions(req, res, body, pipeline, config, logger, semaphore, latencyMonitor, sessionKey) {
3125
+ async function handleChatCompletions(req, res, body, pipeline, config, logger, semaphore, latencyMonitor, sessionKey, stickyCache) {
3590
3126
  const request = body;
3591
3127
  if (!request.messages || !Array.isArray(request.messages)) {
3592
3128
  sendJSON(res, 400, {
@@ -3645,7 +3181,8 @@ async function handleChatCompletions(req, res, body, pipeline, config, logger, s
3645
3181
  compressionThreshold: config.compressionThreshold,
3646
3182
  logFn: blockLogFn,
3647
3183
  semaphore,
3648
- semaphoreTimeoutMs: config.concurrencyTimeoutMs
3184
+ semaphoreTimeoutMs: config.concurrencyTimeoutMs,
3185
+ stickyCache
3649
3186
  }
3650
3187
  );
3651
3188
  const totalBlocks = batchedCount + skippedCount + hotCount;
@@ -3663,7 +3200,7 @@ async function handleChatCompletions(req, res, body, pipeline, config, logger, s
3663
3200
  logger.log(formatSavedLog(result.totalTokensSaved, latencyMs));
3664
3201
  }
3665
3202
  } catch (err) {
3666
- if (err instanceof RSCCircuitOpenError2) {
3203
+ if (err instanceof RSCCircuitOpenError) {
3667
3204
  logger.log(formatDegradeLog());
3668
3205
  } else {
3669
3206
  logger.log(`[ERROR] Compression failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -3696,7 +3233,7 @@ async function handleChatCompletions(req, res, body, pipeline, config, logger, s
3696
3233
  return;
3697
3234
  }
3698
3235
  if (request.stream && upstreamResponse.body) {
3699
- const learningBuffer = anyCompressed ? createStreamLearningBuffer(pipeline.pipeline) : null;
3236
+ const learningBuffer = createStreamLearningBuffer(pipeline.pipeline);
3700
3237
  logger.log(formatResponseLog(request.model, totalTokensSaved, true));
3701
3238
  await pipeSSEResponse(
3702
3239
  upstreamResponse,
@@ -3727,7 +3264,7 @@ async function handleChatCompletions(req, res, body, pipeline, config, logger, s
3727
3264
  setCORSHeaders(res);
3728
3265
  res.writeHead(200, { "Content-Type": "application/json" });
3729
3266
  res.end(finalBody);
3730
- if (anyCompressed) {
3267
+ {
3731
3268
  try {
3732
3269
  const parsed = JSON.parse(responseBody);
3733
3270
  const content = parsed?.choices?.[0]?.message?.content;
@@ -3749,103 +3286,13 @@ async function handleChatCompletions(req, res, body, pipeline, config, logger, s
3749
3286
  }
3750
3287
 
3751
3288
  // src/proxy/messages.ts
3752
- import { RSCCircuitOpenError as RSCCircuitOpenError3 } from "@cognisos/rsc-sdk";
3753
-
3754
- // src/proxy/anthropic-streaming.ts
3755
- function adjustMessageStartLine(dataLine, tokensSaved) {
3756
- try {
3757
- const json = JSON.parse(dataLine.slice(6));
3758
- if (json?.message?.usage?.input_tokens != null) {
3759
- json.message.usage.input_tokens += tokensSaved;
3760
- return `data: ${JSON.stringify(json)}`;
3761
- }
3762
- } catch {
3763
- }
3764
- return null;
3765
- }
3766
- async function pipeAnthropicSSEResponse(upstreamResponse, clientRes, onContentDelta, onComplete, totalTokensSaved = 0) {
3767
- clientRes.writeHead(200, {
3768
- "Content-Type": "text/event-stream",
3769
- "Cache-Control": "no-cache",
3770
- "Connection": "keep-alive",
3771
- "Access-Control-Allow-Origin": "*"
3772
- });
3773
- const reader = upstreamResponse.body.getReader();
3774
- const decoder = new TextDecoder();
3775
- let lineBuf = "";
3776
- let currentEvent = "";
3777
- let usageAdjusted = false;
3778
- const needsAdjustment = totalTokensSaved > 0;
3779
- try {
3780
- while (true) {
3781
- const { done, value } = await reader.read();
3782
- if (done) break;
3783
- const chunk = decoder.decode(value, { stream: true });
3784
- if (!needsAdjustment || usageAdjusted) {
3785
- clientRes.write(chunk);
3786
- lineBuf += chunk;
3787
- const lines2 = lineBuf.split("\n");
3788
- lineBuf = lines2.pop() || "";
3789
- for (const line of lines2) {
3790
- if (line.startsWith("event: ")) {
3791
- currentEvent = line.slice(7).trim();
3792
- } else if (line.startsWith("data: ") && currentEvent === "content_block_delta") {
3793
- try {
3794
- const json = JSON.parse(line.slice(6));
3795
- if (json?.delta?.type === "text_delta" && typeof json.delta.text === "string") {
3796
- onContentDelta(json.delta.text);
3797
- }
3798
- } catch {
3799
- }
3800
- }
3801
- }
3802
- continue;
3803
- }
3804
- lineBuf += chunk;
3805
- const lines = lineBuf.split("\n");
3806
- lineBuf = lines.pop() || "";
3807
- let adjusted = false;
3808
- const outputLines = [];
3809
- for (const line of lines) {
3810
- if (line.startsWith("event: ")) {
3811
- currentEvent = line.slice(7).trim();
3812
- outputLines.push(line);
3813
- } else if (line.startsWith("data: ") && currentEvent === "message_start" && !usageAdjusted) {
3814
- const adjustedLine = adjustMessageStartLine(line, totalTokensSaved);
3815
- if (adjustedLine) {
3816
- outputLines.push(adjustedLine);
3817
- usageAdjusted = true;
3818
- adjusted = true;
3819
- } else {
3820
- outputLines.push(line);
3821
- }
3822
- } else {
3823
- outputLines.push(line);
3824
- if (line.startsWith("data: ") && currentEvent === "content_block_delta") {
3825
- try {
3826
- const json = JSON.parse(line.slice(6));
3827
- if (json?.delta?.type === "text_delta" && typeof json.delta.text === "string") {
3828
- onContentDelta(json.delta.text);
3829
- }
3830
- } catch {
3831
- }
3832
- }
3833
- }
3834
- }
3835
- if (adjusted) {
3836
- const reconstructed = outputLines.join("\n") + "\n" + (lineBuf ? "" : "");
3837
- clientRes.write(reconstructed);
3838
- } else {
3839
- clientRes.write(chunk);
3840
- }
3841
- }
3842
- } finally {
3843
- clientRes.end();
3844
- onComplete();
3845
- }
3846
- }
3847
-
3848
- // src/proxy/messages.ts
3289
+ import { RSCCircuitOpenError as RSCCircuitOpenError2 } from "@cognisos/rsc-sdk";
3290
+ import {
3291
+ compressConversation as compressConversation2,
3292
+ analyzeConversation as analyzeConversation2,
3293
+ createStreamLearningBuffer as createStreamLearningBuffer2,
3294
+ pipeAnthropicSSEResponse
3295
+ } from "@cognisos/proxy-core";
3849
3296
  function setCORSHeaders2(res) {
3850
3297
  res.setHeader("Access-Control-Allow-Origin", "*");
3851
3298
  res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
@@ -3880,7 +3327,7 @@ function convertCompressedToAnthropic(messages) {
3880
3327
  content: msg.content
3881
3328
  }));
3882
3329
  }
3883
- async function handleAnthropicMessages(req, res, body, pipeline, config, logger, semaphore, latencyMonitor, sessionKey) {
3330
+ async function handleAnthropicMessages(req, res, body, pipeline, config, logger, semaphore, latencyMonitor, sessionKey, onUsage, stickyCache) {
3884
3331
  const request = body;
3885
3332
  if (!request.messages || !Array.isArray(request.messages)) {
3886
3333
  sendAnthropicError(res, 400, "invalid_request_error", "messages is required and must be an array");
@@ -3895,6 +3342,8 @@ async function handleAnthropicMessages(req, res, body, pipeline, config, logger,
3895
3342
  sendAnthropicError(res, 401, "authentication_error", "Authentication required (x-api-key or Authorization header)");
3896
3343
  return;
3897
3344
  }
3345
+ const { countTokens: countTok } = await import("@cognisos/proxy-core");
3346
+ const originalInputTokens = countTok(JSON.stringify(request));
3898
3347
  let messages = request.messages;
3899
3348
  let anyCompressed = false;
3900
3349
  let totalTokensSaved = 0;
@@ -3903,7 +3352,7 @@ async function handleAnthropicMessages(req, res, body, pipeline, config, logger,
3903
3352
  try {
3904
3353
  const compressRoles = new Set(config.compressRoles);
3905
3354
  const compressible = convertAnthropicToCompressible(request.messages);
3906
- const plan = analyzeConversation(compressible, {
3355
+ const plan = analyzeConversation2(compressible, {
3907
3356
  hotFraction: config.hotFraction,
3908
3357
  coldFraction: config.coldFraction,
3909
3358
  aggregateThreshold: config.aggregateThreshold,
@@ -3931,7 +3380,7 @@ async function handleAnthropicMessages(req, res, body, pipeline, config, logger,
3931
3380
  hotCount++;
3932
3381
  }
3933
3382
  };
3934
- const result = await compressConversation(
3383
+ const result = await compressConversation2(
3935
3384
  pipeline.pipeline,
3936
3385
  pipeline.session,
3937
3386
  plan,
@@ -3940,7 +3389,8 @@ async function handleAnthropicMessages(req, res, body, pipeline, config, logger,
3940
3389
  compressionThreshold: config.compressionThreshold,
3941
3390
  logFn: blockLogFn,
3942
3391
  semaphore,
3943
- semaphoreTimeoutMs: config.concurrencyTimeoutMs
3392
+ semaphoreTimeoutMs: config.concurrencyTimeoutMs,
3393
+ stickyCache
3944
3394
  }
3945
3395
  );
3946
3396
  const totalBlocks = batchedCount + skippedCount + hotCount;
@@ -3958,7 +3408,7 @@ async function handleAnthropicMessages(req, res, body, pipeline, config, logger,
3958
3408
  logger.log(formatSavedLog(result.totalTokensSaved, latencyMs));
3959
3409
  }
3960
3410
  } catch (err) {
3961
- if (err instanceof RSCCircuitOpenError3) {
3411
+ if (err instanceof RSCCircuitOpenError2) {
3962
3412
  logger.log(formatDegradeLog());
3963
3413
  } else {
3964
3414
  logger.log(`[ERROR] Compression failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -3968,6 +3418,8 @@ async function handleAnthropicMessages(req, res, body, pipeline, config, logger,
3968
3418
  }
3969
3419
  const upstreamUrl = `${config.anthropicUpstreamUrl}/v1/messages`;
3970
3420
  const upstreamBody = { ...request, messages };
3421
+ const compressedInputTokens = countTok(JSON.stringify(upstreamBody));
3422
+ const verifiedTokensSaved = Math.max(0, originalInputTokens - compressedInputTokens);
3971
3423
  const upstreamHeaders = {
3972
3424
  ...authHeaders,
3973
3425
  "anthropic-version": req.headers["anthropic-version"] || "2023-06-01",
@@ -3996,35 +3448,44 @@ async function handleAnthropicMessages(req, res, body, pipeline, config, logger,
3996
3448
  return;
3997
3449
  }
3998
3450
  if (request.stream && upstreamResponse.body) {
3999
- const learningBuffer = anyCompressed ? createStreamLearningBuffer(pipeline.pipeline) : null;
3451
+ const learningBuffer = createStreamLearningBuffer2(pipeline.pipeline);
4000
3452
  logger.log(formatResponseLog(request.model, totalTokensSaved, true));
4001
3453
  await pipeAnthropicSSEResponse(
4002
3454
  upstreamResponse,
4003
3455
  res,
4004
3456
  (text) => learningBuffer?.append(text),
4005
3457
  () => learningBuffer?.flush(),
4006
- totalTokensSaved
3458
+ totalTokensSaved,
3459
+ onUsage ? (usage2) => {
3460
+ onUsage(usage2, verifiedTokensSaved, originalInputTokens);
3461
+ logger.log(`[TOKENS] input: ${usage2.inputTokens} | output: ${usage2.outputTokens} | verified_saved: ${verifiedTokensSaved} | orig_tok: ${originalInputTokens} | comp_tok: ${compressedInputTokens}`);
3462
+ } : void 0
4007
3463
  );
4008
3464
  return;
4009
3465
  }
4010
3466
  const responseBody = await upstreamResponse.text();
4011
3467
  logger.log(formatResponseLog(request.model, totalTokensSaved));
4012
3468
  let finalBody = responseBody;
4013
- if (totalTokensSaved > 0) {
4014
- try {
4015
- const parsed = JSON.parse(responseBody);
4016
- if (parsed?.usage?.input_tokens != null) {
3469
+ try {
3470
+ const parsed = JSON.parse(responseBody);
3471
+ if (parsed?.usage) {
3472
+ const actualInput = (parsed.usage.input_tokens ?? 0) + (parsed.usage.cache_creation_input_tokens ?? 0) + (parsed.usage.cache_read_input_tokens ?? 0);
3473
+ const actualOutput = parsed.usage.output_tokens ?? 0;
3474
+ if (onUsage) {
3475
+ onUsage({ inputTokens: actualInput, outputTokens: actualOutput }, verifiedTokensSaved, originalInputTokens);
3476
+ logger.log(`[TOKENS] input: ${actualInput} | output: ${actualOutput} | verified_saved: ${verifiedTokensSaved} | orig_tok: ${originalInputTokens} | comp_tok: ${compressedInputTokens}`);
3477
+ }
3478
+ if (totalTokensSaved > 0 && parsed.usage.input_tokens != null) {
4017
3479
  parsed.usage.input_tokens += totalTokensSaved;
4018
3480
  finalBody = JSON.stringify(parsed);
4019
- logger.log(`[TOKENS] Adjusted input_tokens by +${totalTokensSaved}`);
4020
3481
  }
4021
- } catch {
4022
3482
  }
3483
+ } catch {
4023
3484
  }
4024
3485
  setCORSHeaders2(res);
4025
3486
  res.writeHead(200, { "Content-Type": "application/json" });
4026
3487
  res.end(finalBody);
4027
- if (anyCompressed) {
3488
+ {
4028
3489
  try {
4029
3490
  const parsed = JSON.parse(responseBody);
4030
3491
  const textBlocks = parsed?.content?.filter(
@@ -4047,100 +3508,12 @@ async function handleAnthropicMessages(req, res, body, pipeline, config, logger,
4047
3508
  }
4048
3509
 
4049
3510
  // src/proxy/responses.ts
4050
- import { RSCCircuitOpenError as RSCCircuitOpenError4 } from "@cognisos/rsc-sdk";
4051
-
4052
- // src/proxy/responses-streaming.ts
4053
- async function pipeResponsesSSE(upstreamResponse, clientRes, onContentDelta, onComplete, totalTokensSaved = 0) {
4054
- clientRes.writeHead(200, {
4055
- "Content-Type": "text/event-stream",
4056
- "Cache-Control": "no-cache",
4057
- "Connection": "keep-alive",
4058
- "Access-Control-Allow-Origin": "*"
4059
- });
4060
- const reader = upstreamResponse.body.getReader();
4061
- const decoder = new TextDecoder();
4062
- let lineBuf = "";
4063
- let currentEvent = "";
4064
- let usageAdjusted = false;
4065
- const needsAdjustment = totalTokensSaved > 0;
4066
- try {
4067
- while (true) {
4068
- const { done, value } = await reader.read();
4069
- if (done) break;
4070
- const chunk = decoder.decode(value, { stream: true });
4071
- if (!needsAdjustment || usageAdjusted) {
4072
- clientRes.write(chunk);
4073
- lineBuf += chunk;
4074
- const lines2 = lineBuf.split("\n");
4075
- lineBuf = lines2.pop() || "";
4076
- for (const line of lines2) {
4077
- if (line.startsWith("event: ")) {
4078
- currentEvent = line.slice(7).trim();
4079
- } else if (line.startsWith("data: ") && currentEvent === "response.output_text.delta") {
4080
- try {
4081
- const json = JSON.parse(line.slice(6));
4082
- if (typeof json?.delta === "string") {
4083
- onContentDelta(json.delta);
4084
- }
4085
- } catch {
4086
- }
4087
- }
4088
- }
4089
- continue;
4090
- }
4091
- lineBuf += chunk;
4092
- const lines = lineBuf.split("\n");
4093
- lineBuf = lines.pop() || "";
4094
- let adjusted = false;
4095
- const outputLines = [];
4096
- for (const line of lines) {
4097
- if (line.startsWith("event: ")) {
4098
- currentEvent = line.slice(7).trim();
4099
- outputLines.push(line);
4100
- } else if (line.startsWith("data: ") && currentEvent === "response.completed" && !usageAdjusted) {
4101
- try {
4102
- const json = JSON.parse(line.slice(6));
4103
- if (json?.response?.usage?.input_tokens != null) {
4104
- json.response.usage.input_tokens += totalTokensSaved;
4105
- if (json.response.usage.total_tokens != null) {
4106
- json.response.usage.total_tokens += totalTokensSaved;
4107
- }
4108
- outputLines.push(`data: ${JSON.stringify(json)}`);
4109
- usageAdjusted = true;
4110
- adjusted = true;
4111
- } else {
4112
- outputLines.push(line);
4113
- }
4114
- } catch {
4115
- outputLines.push(line);
4116
- }
4117
- } else {
4118
- outputLines.push(line);
4119
- if (line.startsWith("data: ") && currentEvent === "response.output_text.delta") {
4120
- try {
4121
- const json = JSON.parse(line.slice(6));
4122
- if (typeof json?.delta === "string") {
4123
- onContentDelta(json.delta);
4124
- }
4125
- } catch {
4126
- }
4127
- }
4128
- }
4129
- }
4130
- if (adjusted) {
4131
- const reconstructed = outputLines.join("\n") + "\n";
4132
- clientRes.write(reconstructed);
4133
- } else {
4134
- clientRes.write(chunk);
4135
- }
4136
- }
4137
- } finally {
4138
- clientRes.end();
4139
- onComplete();
4140
- }
4141
- }
4142
-
4143
- // src/proxy/responses.ts
3511
+ import { RSCCircuitOpenError as RSCCircuitOpenError3 } from "@cognisos/rsc-sdk";
3512
+ import {
3513
+ compressMessages,
3514
+ createStreamLearningBuffer as createStreamLearningBuffer3,
3515
+ pipeResponsesSSE
3516
+ } from "@cognisos/proxy-core";
4144
3517
  function setCORSHeaders3(res) {
4145
3518
  res.setHeader("Access-Control-Allow-Origin", "*");
4146
3519
  res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
@@ -4282,7 +3655,7 @@ async function handleResponses(req, res, body, pipeline, config, logger, semapho
4282
3655
  }
4283
3656
  }
4284
3657
  } catch (err) {
4285
- if (err instanceof RSCCircuitOpenError4) {
3658
+ if (err instanceof RSCCircuitOpenError3) {
4286
3659
  logger.log(formatDegradeLog());
4287
3660
  } else {
4288
3661
  logger.log(`[ERROR] Compression failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -4317,7 +3690,7 @@ async function handleResponses(req, res, body, pipeline, config, logger, semapho
4317
3690
  return;
4318
3691
  }
4319
3692
  if (request.stream && upstreamResponse.body) {
4320
- const learningBuffer = anyCompressed ? createStreamLearningBuffer(pipeline.pipeline) : null;
3693
+ const learningBuffer = createStreamLearningBuffer3(pipeline.pipeline);
4321
3694
  logger.log(formatResponseLog(request.model, totalTokensSaved, true));
4322
3695
  await pipeResponsesSSE(
4323
3696
  upstreamResponse,
@@ -4348,7 +3721,7 @@ async function handleResponses(req, res, body, pipeline, config, logger, semapho
4348
3721
  setCORSHeaders3(res);
4349
3722
  res.writeHead(200, { "Content-Type": "application/json" });
4350
3723
  res.end(finalBody);
4351
- if (anyCompressed) {
3724
+ {
4352
3725
  try {
4353
3726
  const parsed = JSON.parse(responseBody);
4354
3727
  if (parsed?.output) {
@@ -4577,6 +3950,11 @@ function createRequestHandler(deps) {
4577
3950
  }
4578
3951
  return;
4579
3952
  }
3953
+ if (req.headers["x-liminal-bypass"] === "true") {
3954
+ logger.log(`[PROXY] Bypass: ${method} ${fullUrl}`);
3955
+ await passthroughToUpstream(req, res, fullUrl, config, logger);
3956
+ return;
3957
+ }
4580
3958
  if (method === "GET" && (url === "/health" || url === "/") && !getMitmUpstreamBase(req)) {
4581
3959
  const sessionSummaries = sessions.getAllSummaries();
4582
3960
  sendJSON3(res, 200, {
@@ -4604,12 +3982,14 @@ function createRequestHandler(deps) {
4604
3982
  calls_failed: s.failedCalls,
4605
3983
  p95_latency_ms: latencyMonitor.getSessionP95(s.key),
4606
3984
  last_active_ago_ms: Date.now() - s.lastAccessedAt
4607
- }))
3985
+ })),
3986
+ ...deps.getVerifiedTokens ? deps.getVerifiedTokens() : {},
3987
+ ...deps.getCursorMetrics ? { cursor: deps.getCursorMetrics() } : {}
4608
3988
  });
4609
3989
  return;
4610
3990
  }
4611
3991
  const sessionKey = identifySession(req, url);
4612
- const pipeline = sessions.getOrCreate(sessionKey);
3992
+ const { pipeline, stickyCache } = sessions.getOrCreate(sessionKey);
4613
3993
  if (method === "POST" && (url === "/v1/chat/completions" || url === "/chat/completions")) {
4614
3994
  const body = await readBody(req);
4615
3995
  let parsed;
@@ -4621,7 +4001,7 @@ function createRequestHandler(deps) {
4621
4001
  });
4622
4002
  return;
4623
4003
  }
4624
- await handleChatCompletions(req, res, parsed, pipeline, config, logger, semaphore, latencyMonitor, sessionKey.raw);
4004
+ await handleChatCompletions(req, res, parsed, pipeline, config, logger, semaphore, latencyMonitor, sessionKey.raw, stickyCache);
4625
4005
  return;
4626
4006
  }
4627
4007
  if (method === "POST" && (url === "/v1/responses" || url === "/responses")) {
@@ -4650,7 +4030,7 @@ function createRequestHandler(deps) {
4650
4030
  });
4651
4031
  return;
4652
4032
  }
4653
- await handleAnthropicMessages(req, res, parsed, pipeline, config, logger, semaphore, latencyMonitor, sessionKey.raw);
4033
+ await handleAnthropicMessages(req, res, parsed, pipeline, config, logger, semaphore, latencyMonitor, sessionKey.raw, deps.onUsage, stickyCache);
4654
4034
  return;
4655
4035
  }
4656
4036
  await passthroughToUpstream(req, res, fullUrl, config, logger);
@@ -4666,72 +4046,8 @@ function createRequestHandler(deps) {
4666
4046
  };
4667
4047
  }
4668
4048
 
4669
- // src/proxy/server.ts
4670
- import * as http from "http";
4671
- var MAX_PORT_RETRIES = 5;
4672
- var ProxyServer = class {
4673
- server = null;
4674
- activePort = null;
4675
- requestedPort;
4676
- handler;
4677
- connectHandler;
4678
- constructor(port, handler, connectHandler) {
4679
- this.requestedPort = port;
4680
- this.handler = handler;
4681
- this.connectHandler = connectHandler ?? null;
4682
- }
4683
- async start() {
4684
- let lastError = null;
4685
- for (let attempt = 0; attempt < MAX_PORT_RETRIES; attempt++) {
4686
- const port = this.requestedPort + attempt;
4687
- try {
4688
- await this.listen(port);
4689
- this.activePort = port;
4690
- return port;
4691
- } catch (err) {
4692
- lastError = err instanceof Error ? err : new Error(String(err));
4693
- if (err.code !== "EADDRINUSE") {
4694
- throw lastError;
4695
- }
4696
- }
4697
- }
4698
- throw lastError ?? new Error(`All ports ${this.requestedPort}-${this.requestedPort + MAX_PORT_RETRIES - 1} in use`);
4699
- }
4700
- listen(port) {
4701
- return new Promise((resolve, reject) => {
4702
- const server = http.createServer(this.handler);
4703
- if (this.connectHandler) {
4704
- server.on("connect", this.connectHandler);
4705
- }
4706
- server.on("error", reject);
4707
- server.listen(port, "127.0.0.1", () => {
4708
- server.removeListener("error", reject);
4709
- this.server = server;
4710
- resolve();
4711
- });
4712
- });
4713
- }
4714
- async stop() {
4715
- if (!this.server) return;
4716
- return new Promise((resolve) => {
4717
- this.server.close(() => {
4718
- this.server = null;
4719
- this.activePort = null;
4720
- resolve();
4721
- });
4722
- });
4723
- }
4724
- isRunning() {
4725
- return this.server !== null && this.server.listening;
4726
- }
4727
- getPort() {
4728
- return this.activePort;
4729
- }
4730
- /** Expose internal HTTP server for MITM bridge socket injection */
4731
- getHttpServer() {
4732
- return this.server;
4733
- }
4734
- };
4049
+ // src/commands/start.ts
4050
+ import { ProxyServer } from "@cognisos/proxy-core";
4735
4051
 
4736
4052
  // src/daemon/logger.ts
4737
4053
  init_paths();
@@ -4789,7 +4105,7 @@ var FileLogger = class {
4789
4105
  };
4790
4106
 
4791
4107
  // src/rsc/session-manager.ts
4792
- init_pipeline();
4108
+ import { RSCPipelineWrapper } from "@cognisos/proxy-core";
4793
4109
  var DEFAULT_MAX_SESSIONS = 10;
4794
4110
  var DEFAULT_SESSION_TTL_MS = 30 * 60 * 1e3;
4795
4111
  var EVICTION_INTERVAL_MS = 6e4;
@@ -4814,7 +4130,7 @@ var SessionManager = class {
4814
4130
  if (existing) {
4815
4131
  existing.lastAccessedAt = Date.now();
4816
4132
  existing.requestCount++;
4817
- return existing.pipeline;
4133
+ return { pipeline: existing.pipeline, stickyCache: existing.stickyCache };
4818
4134
  }
4819
4135
  if (this.sessions.size >= this.config.maxSessions) {
4820
4136
  this.evictLRU();
@@ -4823,14 +4139,16 @@ var SessionManager = class {
4823
4139
  ...this.config.pipelineConfig,
4824
4140
  sessionId: key.raw
4825
4141
  });
4142
+ const stickyCache = /* @__PURE__ */ new Map();
4826
4143
  this.sessions.set(key.raw, {
4827
4144
  pipeline,
4145
+ stickyCache,
4828
4146
  lastAccessedAt: Date.now(),
4829
4147
  requestCount: 1,
4830
4148
  connector: key.connector
4831
4149
  });
4832
4150
  this.config.onSessionCreated?.(key.raw, pipeline);
4833
- return pipeline;
4151
+ return { pipeline, stickyCache };
4834
4152
  }
4835
4153
  getAllSummaries() {
4836
4154
  const entries = [];
@@ -4895,59 +4213,8 @@ var SessionManager = class {
4895
4213
  }
4896
4214
  };
4897
4215
 
4898
- // src/rsc/semaphore.ts
4899
- var SemaphoreTimeoutError = class extends Error {
4900
- constructor(timeoutMs) {
4901
- super(`Semaphore acquire timed out after ${timeoutMs}ms`);
4902
- this.name = "SemaphoreTimeoutError";
4903
- }
4904
- };
4905
- var Semaphore = class {
4906
- permits;
4907
- queue = [];
4908
- constructor(maxPermits) {
4909
- if (maxPermits < 1) throw new RangeError("maxPermits must be >= 1");
4910
- this.permits = maxPermits;
4911
- }
4912
- get available() {
4913
- return this.permits;
4914
- }
4915
- get waiting() {
4916
- return this.queue.length;
4917
- }
4918
- acquire(timeoutMs) {
4919
- if (this.permits > 0) {
4920
- this.permits--;
4921
- return Promise.resolve();
4922
- }
4923
- return new Promise((resolve, reject) => {
4924
- const waiter = { resolve, reject };
4925
- this.queue.push(waiter);
4926
- if (timeoutMs !== void 0 && timeoutMs >= 0) {
4927
- const timer = setTimeout(() => {
4928
- const idx = this.queue.indexOf(waiter);
4929
- if (idx !== -1) {
4930
- this.queue.splice(idx, 1);
4931
- reject(new SemaphoreTimeoutError(timeoutMs));
4932
- }
4933
- }, timeoutMs);
4934
- const originalResolve = waiter.resolve;
4935
- waiter.resolve = () => {
4936
- clearTimeout(timer);
4937
- originalResolve();
4938
- };
4939
- }
4940
- });
4941
- }
4942
- release() {
4943
- const next = this.queue.shift();
4944
- if (next) {
4945
- next.resolve();
4946
- } else {
4947
- this.permits++;
4948
- }
4949
- }
4950
- };
4216
+ // src/commands/start.ts
4217
+ import { Semaphore } from "@cognisos/proxy-core";
4951
4218
 
4952
4219
  // src/rsc/latency-monitor.ts
4953
4220
  var DEFAULT_CONFIG = {
@@ -5399,15 +4666,36 @@ async function startCommand(flags) {
5399
4666
  event.tokensSaved,
5400
4667
  event.processingTimeMs ?? 0
5401
4668
  );
4669
+ pipeline.session.recordCompression(event);
5402
4670
  });
5403
4671
  pipeline.events.on("compression_skipped", (event) => {
5404
4672
  const detail = event.reason === "latency_budget" ? `${event.reason} (${event.estimatedTokens}tok, budget:${event.budgetMs}ms, elapsed:${event.elapsedMs}ms)` : event.reason === "below_threshold" ? `${event.reason} (${event.estimatedTokens}tok < ${config.compressionThreshold}tok threshold)` : `${event.reason} (${event.estimatedTokens}tok)`;
5405
4673
  logger.log(`[LIMINAL] [${key}] Skipped: ${detail}`);
5406
4674
  statsAggregator.recordSkipped(connector, event.estimatedTokens ?? 0);
4675
+ pipeline.session.recordCompression({
4676
+ ...event,
4677
+ inputTokens: event.estimatedTokens ?? 0,
4678
+ outputTokens: event.estimatedTokens ?? 0,
4679
+ tokensSaved: 0,
4680
+ ratio: 1,
4681
+ deltaMdlBits: 0,
4682
+ processingTimeMs: 0,
4683
+ skipped: true,
4684
+ fabricHits: 0,
4685
+ fabricMisses: 0
4686
+ });
5407
4687
  });
5408
4688
  pipeline.events.on("error", (event) => {
5409
4689
  logger.log(`[LIMINAL] [${key}] Error: ${event.error.message}`);
5410
4690
  statsAggregator.recordFailure(connector);
4691
+ pipeline.session.recordFailure();
4692
+ });
4693
+ pipeline.events.on("learning", (event) => {
4694
+ if (event.error) {
4695
+ logger.log(`[LIMINAL] [${key}] Learning error: ${event.error}`);
4696
+ } else if (event.tokensIngested > 0) {
4697
+ logger.log(`[LIMINAL] [${key}] Learning: ${event.tokensIngested} tokens ingested (deferred:${event.deferred})`);
4698
+ }
5411
4699
  });
5412
4700
  pipeline.events.on("degradation", (event) => {
5413
4701
  logger.log(`[LIMINAL] [${key}] Circuit ${event.circuitState}: ${event.reason}`);
@@ -5435,7 +4723,50 @@ async function startCommand(flags) {
5435
4723
  logger.log(`[LATENCY] ${alert.type.toUpperCase()}: ${alert.message} (${alert.activeSessions} sessions) \u2014 ${alert.suggestion}`);
5436
4724
  });
5437
4725
  const mitmStats = new MitmStats();
5438
- const deps = { sessions, semaphore, latencyMonitor, mitmStats, config: resolvedConfig, logger };
4726
+ const deps = {
4727
+ sessions,
4728
+ semaphore,
4729
+ latencyMonitor,
4730
+ mitmStats,
4731
+ config: resolvedConfig,
4732
+ logger,
4733
+ onUsage: (usage2, verifiedSaved, originalInputTokens) => {
4734
+ statsAggregator.recordApiUsage(usage2.inputTokens, usage2.outputTokens, verifiedSaved, originalInputTokens);
4735
+ if (resolvedConfig.rscApiKey && resolvedConfig.rscBaseUrl) {
4736
+ const body = JSON.stringify({
4737
+ model: "cli",
4738
+ actual_input_tokens: usage2.inputTokens,
4739
+ actual_output_tokens: usage2.outputTokens,
4740
+ original_input_bytes: originalInputTokens * 4
4741
+ });
4742
+ fetch(`${resolvedConfig.rscBaseUrl}/api/v1/usage/verified`, {
4743
+ method: "POST",
4744
+ headers: {
4745
+ "Content-Type": "application/json",
4746
+ "Authorization": `Bearer ${resolvedConfig.rscApiKey}`
4747
+ },
4748
+ body,
4749
+ signal: AbortSignal.timeout(5e3)
4750
+ }).catch(() => {
4751
+ });
4752
+ }
4753
+ },
4754
+ getVerifiedTokens: () => {
4755
+ const snap = statsAggregator.snapshot();
4756
+ return {
4757
+ actualInputTokens: snap.actualInputTokens,
4758
+ actualOutputTokens: snap.actualOutputTokens,
4759
+ originalInputEstimate: snap.originalInputEstimate,
4760
+ verifiedInputSaved: snap.verifiedInputSaved,
4761
+ verifiedSavingsRate: snap.verifiedSavingsRate,
4762
+ verifiedRequestCount: snap.verifiedRequestCount
4763
+ };
4764
+ },
4765
+ getCursorMetrics: () => {
4766
+ const { parseCursorHookStats: parseCursorHookStats3 } = (init_stats(), __toCommonJS(stats_exports));
4767
+ return parseCursorHookStats3();
4768
+ }
4769
+ };
5439
4770
  const handler = createRequestHandler(deps);
5440
4771
  let mitmHandler;
5441
4772
  const connectHandler = createConnectHandler({
@@ -5458,6 +4789,11 @@ async function startCommand(flags) {
5458
4789
  try {
5459
4790
  const actualPort = await server.start();
5460
4791
  writePidFile(process.pid);
4792
+ try {
4793
+ const portFilePath = join8(homedir5(), ".liminal", ".port");
4794
+ writeFileSync6(portFilePath, String(actualPort), "utf-8");
4795
+ } catch {
4796
+ }
5461
4797
  logger.log(`[DAEMON] Liminal proxy started on http://127.0.0.1:${actualPort}`);
5462
4798
  logger.log(`[DAEMON] Upstream (OpenAI): ${config.upstreamBaseUrl}`);
5463
4799
  logger.log(`[DAEMON] Upstream (Anthropic): ${config.anthropicUpstreamUrl}`);
@@ -5486,7 +4822,7 @@ async function startCommand(flags) {
5486
4822
  if (caReady) {
5487
4823
  console.log(success("MITM bridge active", "CA trusted"));
5488
4824
  }
5489
- const { RSCPipelineWrapper: RSCPipelineWrapper3 } = await Promise.resolve().then(() => (init_pipeline(), pipeline_exports));
4825
+ const { RSCPipelineWrapper: RSCPipelineWrapper3 } = await import("@cognisos/proxy-core");
5490
4826
  const probe2 = new RSCPipelineWrapper3({
5491
4827
  rscApiKey: config.apiKey,
5492
4828
  rscBaseUrl: config.apiBaseUrl,
@@ -5524,7 +4860,7 @@ async function startCommand(flags) {
5524
4860
  console.log();
5525
4861
  return;
5526
4862
  }
5527
- const { RSCPipelineWrapper: RSCPipelineWrapper2 } = await Promise.resolve().then(() => (init_pipeline(), pipeline_exports));
4863
+ const { RSCPipelineWrapper: RSCPipelineWrapper2 } = await import("@cognisos/proxy-core");
5528
4864
  const probe = new RSCPipelineWrapper2({
5529
4865
  rscApiKey: config.apiKey,
5530
4866
  rscBaseUrl: config.apiBaseUrl,
@@ -5640,8 +4976,9 @@ async function stopCommand() {
5640
4976
  init_lifecycle();
5641
4977
  init_loader();
5642
4978
  init_format();
5643
- import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
5644
- import { join as join7 } from "path";
4979
+ import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
4980
+ import { homedir as homedir6 } from "os";
4981
+ import { join as join9 } from "path";
5645
4982
  async function statusCommand() {
5646
4983
  if (!isConfigured()) {
5647
4984
  console.log(error(
@@ -5660,7 +4997,13 @@ async function statusCommand() {
5660
4997
  return;
5661
4998
  }
5662
4999
  const config = loadConfig();
5663
- const port = config.port;
5000
+ let port = config.port;
5001
+ try {
5002
+ const portFilePath = join9(homedir6(), ".liminal", ".port");
5003
+ const actualPort = parseInt(readFileSync9(portFilePath, "utf-8").trim(), 10);
5004
+ if (!isNaN(actualPort)) port = actualPort;
5005
+ } catch {
5006
+ }
5664
5007
  try {
5665
5008
  const res = await fetch(`http://127.0.0.1:${port}/health`, {
5666
5009
  signal: AbortSignal.timeout(3e3)
@@ -5709,27 +5052,27 @@ async function statusCommand() {
5709
5052
  }
5710
5053
  }
5711
5054
  function printCursorHookStats() {
5712
- const logPath = join7(process.cwd(), ".fabric", "compress.log");
5713
- const hooksPath = join7(process.cwd(), ".cursor", "hooks.json");
5055
+ const logPath = join9(process.cwd(), ".fabric", "compress.log");
5056
+ const hooksPath = join9(process.cwd(), ".cursor", "hooks.json");
5714
5057
  let hooksActive = false;
5715
5058
  try {
5716
- if (existsSync10(hooksPath)) {
5717
- const data = JSON.parse(readFileSync8(hooksPath, "utf-8"));
5059
+ if (existsSync11(hooksPath)) {
5060
+ const data = JSON.parse(readFileSync9(hooksPath, "utf-8"));
5718
5061
  const entries = data?.hooks?.preToolUse ?? [];
5719
5062
  hooksActive = entries.some((e) => e.command?.includes("fabric-compress"));
5720
5063
  }
5721
5064
  } catch {
5722
5065
  }
5723
- if (!hooksActive && !existsSync10(logPath)) return;
5066
+ if (!hooksActive && !existsSync11(logPath)) return;
5724
5067
  console.log(sectionHeader("Cursor Hooks"));
5725
5068
  console.log();
5726
5069
  console.log(label("Status", hooksActive ? `${c.green}active${c.reset}` : `${c.dim}not installed${c.reset}`));
5727
- if (!existsSync10(logPath)) {
5070
+ if (!existsSync11(logPath)) {
5728
5071
  console.log(label("Stats", `${c.dim}no compression data yet${c.reset}`));
5729
5072
  console.log();
5730
5073
  return;
5731
5074
  }
5732
- const lines = readFileSync8(logPath, "utf-8").trim().split("\n");
5075
+ const lines = readFileSync9(logPath, "utf-8").trim().split("\n");
5733
5076
  let compressed = 0;
5734
5077
  let errors = 0;
5735
5078
  let totalInputSize = 0;
@@ -5763,7 +5106,7 @@ function printCursorHookStats() {
5763
5106
  const avgApiMs = compressed > 0 ? Math.round(totalApiMs / compressed) : 0;
5764
5107
  let cacheCount = 0;
5765
5108
  try {
5766
- cacheCount = countFiles(join7(process.cwd(), ".fabric", "cache"));
5109
+ cacheCount = countFiles(join9(process.cwd(), ".fabric", "cache"));
5767
5110
  } catch {
5768
5111
  }
5769
5112
  console.log(label("Files", `${files.size} unique ${c.dim}(${compressed} compressions${errors > 0 ? `, ${c.red}${errors} errors${c.reset}${c.dim}` : ""})${c.reset}`));
@@ -5776,12 +5119,12 @@ function printCursorHookStats() {
5776
5119
  console.log();
5777
5120
  }
5778
5121
  function countFiles(dir) {
5779
- if (!existsSync10(dir)) return 0;
5780
- const { readdirSync: readdirSync2, statSync: statSync4 } = __require("fs");
5122
+ if (!existsSync11(dir)) return 0;
5123
+ const { readdirSync: readdirSync3, statSync: statSync4 } = __require("fs");
5781
5124
  let count = 0;
5782
- for (const entry of readdirSync2(dir, { withFileTypes: true })) {
5125
+ for (const entry of readdirSync3(dir, { withFileTypes: true })) {
5783
5126
  if (entry.isDirectory()) {
5784
- count += countFiles(join7(dir, entry.name));
5127
+ count += countFiles(join9(dir, entry.name));
5785
5128
  } else {
5786
5129
  count++;
5787
5130
  }
@@ -5864,17 +5207,17 @@ async function configCommand(flags) {
5864
5207
 
5865
5208
  // src/commands/logs.ts
5866
5209
  init_paths();
5867
- import { readFileSync as readFileSync9, existsSync as existsSync11, statSync as statSync2, createReadStream } from "fs";
5210
+ import { readFileSync as readFileSync10, existsSync as existsSync12, statSync as statSync2, createReadStream } from "fs";
5868
5211
  import { watchFile, unwatchFile } from "fs";
5869
5212
  async function logsCommand(flags) {
5870
5213
  const follow = flags.has("follow") || flags.has("f");
5871
5214
  const linesFlag = flags.get("lines") ?? flags.get("n");
5872
5215
  const lines = typeof linesFlag === "string" ? parseInt(linesFlag, 10) : 50;
5873
- if (!existsSync11(LOG_FILE)) {
5216
+ if (!existsSync12(LOG_FILE)) {
5874
5217
  console.log('No log file found. Start the daemon with "liminal start" to generate logs.');
5875
5218
  return;
5876
5219
  }
5877
- const content = readFileSync9(LOG_FILE, "utf-8");
5220
+ const content = readFileSync10(LOG_FILE, "utf-8");
5878
5221
  const allLines = content.split("\n");
5879
5222
  const tail = allLines.slice(-lines - 1);
5880
5223
  process.stdout.write(tail.join("\n"));
@@ -5900,7 +5243,7 @@ async function logsCommand(flags) {
5900
5243
  }
5901
5244
 
5902
5245
  // src/commands/uninstall.ts
5903
- import { existsSync as existsSync12, rmSync, readFileSync as readFileSync10 } from "fs";
5246
+ import { existsSync as existsSync13, rmSync, readFileSync as readFileSync11 } from "fs";
5904
5247
  init_paths();
5905
5248
  init_lifecycle();
5906
5249
  init_prompts();
@@ -5910,9 +5253,9 @@ var GREEN = "\x1B[32m";
5910
5253
  var YELLOW = "\x1B[33m";
5911
5254
  var RESET = "\x1B[0m";
5912
5255
  function loadConfiguredTools() {
5913
- if (!existsSync12(CONFIG_FILE)) return [];
5256
+ if (!existsSync13(CONFIG_FILE)) return [];
5914
5257
  try {
5915
- const raw = readFileSync10(CONFIG_FILE, "utf-8");
5258
+ const raw = readFileSync11(CONFIG_FILE, "utf-8");
5916
5259
  const config = JSON.parse(raw);
5917
5260
  if (Array.isArray(config.tools)) return config.tools;
5918
5261
  } catch {
@@ -6000,7 +5343,7 @@ async function uninstallCommand() {
6000
5343
  }
6001
5344
  }
6002
5345
  }
6003
- if (existsSync12(LIMINAL_DIR)) {
5346
+ if (existsSync13(LIMINAL_DIR)) {
6004
5347
  console.log();
6005
5348
  const removeData = await selectPrompt({
6006
5349
  message: "Remove ~/.liminal/ directory? (config, logs, PID file)",
@@ -6120,9 +5463,10 @@ async function untrustCACommand() {
6120
5463
  // src/commands/setup-cursor.ts
6121
5464
  init_loader();
6122
5465
  init_version();
6123
- import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4, readdirSync, rmdirSync, appendFileSync as appendFileSync3 } from "fs";
6124
- import { homedir as homedir5 } from "os";
6125
- import { join as join8 } from "path";
5466
+ import { existsSync as existsSync14, readFileSync as readFileSync12, writeFileSync as writeFileSync7, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4, readdirSync as readdirSync2, rmdirSync, appendFileSync as appendFileSync3 } from "fs";
5467
+ import { createHash as createHash3 } from "crypto";
5468
+ import { homedir as homedir7 } from "os";
5469
+ import { join as join10 } from "path";
6126
5470
 
6127
5471
  // src/cursor/hook-template.ts
6128
5472
  function getHookScript() {
@@ -6375,10 +5719,11 @@ async function main() {
6375
5719
  if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true });
6376
5720
  fs.writeFileSync(cachePath, result.text, "utf-8");
6377
5721
 
6378
- // Use server-side token counts (actual tokenizer, not byte estimate)
6379
- // Fall back to ~4 chars/token estimate if server doesn't return counts
6380
- const inputTokens = result.inputTokens || Math.ceil(result.inputSize / 4);
6381
- const outputTokens = result.outputTokens || Math.ceil(result.outputSize / 4);
5722
+ // Use server-side token counts from tiktoken-rs (cl100k_base BPE tokenizer)
5723
+ // Fall back to ~3 chars/token estimate if server doesn't return counts
5724
+ const inputTokens = result.inputTokens || Math.ceil(result.inputSize / 3);
5725
+ const outputTokens = result.outputTokens || Math.ceil(result.outputSize / 3);
5726
+ const tokensSaved = Math.max(0, inputTokens - outputTokens);
6382
5727
  logEntry({
6383
5728
  type: "compressed",
6384
5729
  file: relativePath,
@@ -6386,8 +5731,8 @@ async function main() {
6386
5731
  outputSize: result.outputSize,
6387
5732
  inputTokens: inputTokens,
6388
5733
  outputTokens: outputTokens,
6389
- tokensSaved: inputTokens - outputTokens,
6390
- savedPct: +((1 - result.outputSize / result.inputSize) * 100).toFixed(1),
5734
+ tokensSaved: tokensSaved,
5735
+ savedPct: inputTokens > 0 ? +((tokensSaved / inputTokens) * 100).toFixed(1) : 0,
6391
5736
  apiMs: elapsed,
6392
5737
  });
6393
5738
 
@@ -6408,28 +5753,36 @@ main().catch(() => passthrough());
6408
5753
  init_format();
6409
5754
  var HOOK_SCRIPT_NAME = "fabric-compress.js";
6410
5755
  var HOOK_COMMAND = `node .cursor/hooks/${HOOK_SCRIPT_NAME}`;
5756
+ function sha256(content) {
5757
+ return createHash3("sha256").update(content, "utf-8").digest("hex");
5758
+ }
5759
+ function verifyHookIntegrity(scriptPath) {
5760
+ if (!existsSync14(scriptPath)) return false;
5761
+ const onDisk = readFileSync12(scriptPath, "utf-8");
5762
+ return sha256(onDisk) === sha256(getHookScript());
5763
+ }
6411
5764
  function isCursorInstalled2() {
6412
5765
  if (process.platform === "darwin") {
6413
- return existsSync13("/Applications/Cursor.app");
5766
+ return existsSync14("/Applications/Cursor.app");
6414
5767
  }
6415
5768
  if (process.platform === "win32") {
6416
- const localAppData = process.env.LOCALAPPDATA || join8(homedir5(), "AppData", "Local");
6417
- return existsSync13(join8(localAppData, "Programs", "Cursor", "Cursor.exe"));
5769
+ const localAppData = process.env.LOCALAPPDATA || join10(homedir7(), "AppData", "Local");
5770
+ return existsSync14(join10(localAppData, "Programs", "Cursor", "Cursor.exe"));
6418
5771
  }
6419
- return existsSync13("/usr/bin/cursor");
5772
+ return existsSync14("/usr/bin/cursor");
6420
5773
  }
6421
5774
  function readHooksJson(workspaceRoot) {
6422
- const hooksPath = join8(workspaceRoot, ".cursor", "hooks.json");
5775
+ const hooksPath = join10(workspaceRoot, ".cursor", "hooks.json");
6423
5776
  try {
6424
- return JSON.parse(readFileSync11(hooksPath, "utf-8"));
5777
+ return JSON.parse(readFileSync12(hooksPath, "utf-8"));
6425
5778
  } catch {
6426
5779
  return {};
6427
5780
  }
6428
5781
  }
6429
5782
  function writeHooksJson(workspaceRoot, data) {
6430
- const dir = join8(workspaceRoot, ".cursor");
6431
- if (!existsSync13(dir)) mkdirSync5(dir, { recursive: true });
6432
- writeFileSync6(join8(dir, "hooks.json"), JSON.stringify(data, null, 2) + "\n");
5783
+ const dir = join10(workspaceRoot, ".cursor");
5784
+ if (!existsSync14(dir)) mkdirSync5(dir, { recursive: true });
5785
+ writeFileSync7(join10(dir, "hooks.json"), JSON.stringify(data, null, 2) + "\n");
6433
5786
  }
6434
5787
  function hasOurHook(hooks) {
6435
5788
  const entries = hooks.hooks?.preToolUse ?? [];
@@ -6462,24 +5815,24 @@ function removeOurHook(hooks) {
6462
5815
  return hooks;
6463
5816
  }
6464
5817
  function ensureGitignore(workspaceRoot) {
6465
- const gitignorePath = join8(workspaceRoot, ".gitignore");
5818
+ const gitignorePath = join10(workspaceRoot, ".gitignore");
6466
5819
  const entry = ".fabric/";
6467
- if (existsSync13(gitignorePath)) {
6468
- const content = readFileSync11(gitignorePath, "utf-8");
5820
+ if (existsSync14(gitignorePath)) {
5821
+ const content = readFileSync12(gitignorePath, "utf-8");
6469
5822
  if (content.includes(entry)) return;
6470
5823
  appendFileSync3(gitignorePath, `
6471
5824
  # Liminal compression cache
6472
5825
  ${entry}
6473
5826
  `);
6474
5827
  } else {
6475
- writeFileSync6(gitignorePath, `# Liminal compression cache
5828
+ writeFileSync7(gitignorePath, `# Liminal compression cache
6476
5829
  ${entry}
6477
5830
  `);
6478
5831
  }
6479
5832
  }
6480
5833
  function rmdirIfEmpty(dir) {
6481
5834
  try {
6482
- if (existsSync13(dir) && readdirSync(dir).length === 0) {
5835
+ if (existsSync14(dir) && readdirSync2(dir).length === 0) {
6483
5836
  rmdirSync(dir);
6484
5837
  }
6485
5838
  } catch {
@@ -6502,20 +5855,20 @@ async function setupCursorCommand(flags) {
6502
5855
  writeHooksJson(workspaceRoot, updated2);
6503
5856
  console.log(success("Removed hook entry from .cursor/hooks.json"));
6504
5857
  } else {
6505
- const hooksJsonPath = join8(workspaceRoot, ".cursor", "hooks.json");
5858
+ const hooksJsonPath = join10(workspaceRoot, ".cursor", "hooks.json");
6506
5859
  try {
6507
5860
  unlinkSync4(hooksJsonPath);
6508
5861
  } catch {
6509
5862
  }
6510
5863
  console.log(success("Deleted .cursor/hooks.json", "no remaining hooks"));
6511
5864
  }
6512
- const scriptPath2 = join8(workspaceRoot, ".cursor", "hooks", HOOK_SCRIPT_NAME);
5865
+ const scriptPath2 = join10(workspaceRoot, ".cursor", "hooks", HOOK_SCRIPT_NAME);
6513
5866
  try {
6514
5867
  unlinkSync4(scriptPath2);
6515
5868
  console.log(success(`Deleted .cursor/hooks/${HOOK_SCRIPT_NAME}`));
6516
5869
  } catch {
6517
5870
  }
6518
- rmdirIfEmpty(join8(workspaceRoot, ".cursor", "hooks"));
5871
+ rmdirIfEmpty(join10(workspaceRoot, ".cursor", "hooks"));
6519
5872
  console.log();
6520
5873
  console.log(success("Hooks removed. Reload Cursor to deactivate."));
6521
5874
  console.log();
@@ -6530,6 +5883,11 @@ async function setupCursorCommand(flags) {
6530
5883
  }
6531
5884
  console.log(success("Cursor found"));
6532
5885
  console.log();
5886
+ const existingScript = join10(workspaceRoot, ".cursor", "hooks", HOOK_SCRIPT_NAME);
5887
+ if (existsSync14(existingScript) && !verifyHookIntegrity(existingScript)) {
5888
+ console.log(warn(`Existing hook script has been modified externally \u2014 it will be overwritten`));
5889
+ console.log();
5890
+ }
6533
5891
  console.log(` ${c.dim}[2/4]${c.reset} Checking Liminal configuration...`);
6534
5892
  if (!isConfigured()) {
6535
5893
  console.error(error("Liminal is not configured", `Run ${c.bold}liminal init${c.reset}${c.dim} first`));
@@ -6538,11 +5896,15 @@ async function setupCursorCommand(flags) {
6538
5896
  console.log(success("API key configured"));
6539
5897
  console.log();
6540
5898
  console.log(` ${c.dim}[3/4]${c.reset} Installing compression hooks...`);
6541
- const hooksDir = join8(workspaceRoot, ".cursor", "hooks");
6542
- if (!existsSync13(hooksDir)) mkdirSync5(hooksDir, { recursive: true });
6543
- const scriptPath = join8(hooksDir, HOOK_SCRIPT_NAME);
6544
- writeFileSync6(scriptPath, getHookScript(), { mode: 493 });
6545
- console.log(success(`Wrote .cursor/hooks/${HOOK_SCRIPT_NAME}`));
5899
+ const hooksDir = join10(workspaceRoot, ".cursor", "hooks");
5900
+ if (!existsSync14(hooksDir)) mkdirSync5(hooksDir, { recursive: true });
5901
+ const scriptPath = join10(hooksDir, HOOK_SCRIPT_NAME);
5902
+ writeFileSync7(scriptPath, getHookScript(), { mode: 493 });
5903
+ if (!verifyHookIntegrity(scriptPath)) {
5904
+ console.error(error("Hook script integrity check failed", "File may have been modified after write"));
5905
+ process.exit(1);
5906
+ }
5907
+ console.log(success(`Wrote .cursor/hooks/${HOOK_SCRIPT_NAME}`, "integrity verified"));
6546
5908
  const hooks = readHooksJson(workspaceRoot);
6547
5909
  const updated = addOurHook(hooks);
6548
5910
  writeHooksJson(workspaceRoot, updated);
@@ -6569,8 +5931,8 @@ init_loader();
6569
5931
  init_store();
6570
5932
  init_aggregator();
6571
5933
  init_format();
6572
- import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
6573
- import { join as join9 } from "path";
5934
+ import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
5935
+ import { join as join11 } from "path";
6574
5936
  async function statsCommand(flags) {
6575
5937
  if (!isConfigured()) {
6576
5938
  console.log(error(
@@ -6606,7 +5968,7 @@ async function statsCommand(flags) {
6606
5968
  agg.recordSkipped(s.connector, 0);
6607
5969
  }
6608
5970
  }
6609
- const cursorMetrics = parseCursorHookStats();
5971
+ const cursorMetrics = parseCursorHookStats2();
6610
5972
  if (cursorMetrics) {
6611
5973
  agg.setCursorMetrics(cursorMetrics);
6612
5974
  }
@@ -6759,14 +6121,14 @@ async function statsCommand(flags) {
6759
6121
  console.log(` ${c.dim}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${c.reset}`);
6760
6122
  console.log();
6761
6123
  }
6762
- function parseCursorHookStats() {
6763
- const logPath = join9(process.cwd(), ".fabric", "compress.log");
6764
- if (!existsSync14(logPath)) return null;
6124
+ function parseCursorHookStats2() {
6125
+ const logPath = join11(process.cwd(), ".fabric", "compress.log");
6126
+ if (!existsSync15(logPath)) return null;
6765
6127
  let compressions = 0, errors = 0;
6766
6128
  let tokensProcessed = 0, tokensSaved = 0;
6767
6129
  let apiMsSumMs = 0;
6768
6130
  const files = /* @__PURE__ */ new Set();
6769
- const lines = readFileSync12(logPath, "utf-8").trim().split("\n");
6131
+ const lines = readFileSync13(logPath, "utf-8").trim().split("\n");
6770
6132
  for (const line of lines) {
6771
6133
  try {
6772
6134
  const entry = JSON.parse(line);
@@ -6786,7 +6148,7 @@ function parseCursorHookStats() {
6786
6148
  }
6787
6149
  let cacheCount = 0;
6788
6150
  try {
6789
- cacheCount = countFilesRecursive(join9(process.cwd(), ".fabric", "cache"));
6151
+ cacheCount = countFilesRecursive2(join11(process.cwd(), ".fabric", "cache"));
6790
6152
  } catch {
6791
6153
  }
6792
6154
  return {
@@ -6799,13 +6161,13 @@ function parseCursorHookStats() {
6799
6161
  cacheCount
6800
6162
  };
6801
6163
  }
6802
- function countFilesRecursive(dir) {
6803
- if (!existsSync14(dir)) return 0;
6804
- const { readdirSync: readdirSync2 } = __require("fs");
6164
+ function countFilesRecursive2(dir) {
6165
+ if (!existsSync15(dir)) return 0;
6166
+ const { readdirSync: readdirSync3 } = __require("fs");
6805
6167
  let count = 0;
6806
- for (const entry of readdirSync2(dir, { withFileTypes: true })) {
6168
+ for (const entry of readdirSync3(dir, { withFileTypes: true })) {
6807
6169
  if (entry.isDirectory()) {
6808
- count += countFilesRecursive(join9(dir, entry.name));
6170
+ count += countFilesRecursive2(join11(dir, entry.name));
6809
6171
  } else {
6810
6172
  count++;
6811
6173
  }
@@ -6885,9 +6247,94 @@ function parseArgs(argv) {
6885
6247
  }
6886
6248
  return { command, flags };
6887
6249
  }
6250
+ function getCommandHelp(cmd) {
6251
+ const helps = {
6252
+ start: `
6253
+ \${c.bold}liminal start\${c.reset} \u2014 Start the compression proxy
6254
+
6255
+ \${c.bold}Usage:\${c.reset}
6256
+ liminal start [options]
6257
+
6258
+ \${c.bold}Options:\${c.reset}
6259
+ -d, --daemon Run in background (daemon mode)
6260
+ --port PORT Override proxy port (default: from config)
6261
+ --upstream URL Override upstream API base URL
6262
+
6263
+ \${c.bold}Examples:\${c.reset}
6264
+ \${c.dim}$\${c.reset} liminal start \${c.dim}# Foreground mode\${c.reset}
6265
+ \${c.dim}$\${c.reset} liminal start -d \${c.dim}# Background daemon\${c.reset}
6266
+ \${c.dim}$\${c.reset} liminal start --port 3142 \${c.dim}# Custom port\${c.reset}
6267
+ `,
6268
+ stop: `
6269
+ \${c.bold}liminal stop\${c.reset} \u2014 Stop the running proxy
6270
+
6271
+ \${c.bold}Usage:\${c.reset}
6272
+ liminal stop
6273
+ `,
6274
+ status: `
6275
+ \${c.bold}liminal status\${c.reset} \u2014 Show proxy health check
6276
+
6277
+ \${c.bold}Usage:\${c.reset}
6278
+ liminal status
6279
+ `,
6280
+ stats: `
6281
+ \${c.bold}liminal stats\${c.reset} \u2014 Compression metrics & savings
6282
+
6283
+ \${c.bold}Usage:\${c.reset}
6284
+ liminal stats [options]
6285
+
6286
+ \${c.bold}Options:\${c.reset}
6287
+ --json Output as JSON
6288
+ `,
6289
+ config: `
6290
+ \${c.bold}liminal config\${c.reset} \u2014 View or edit configuration
6291
+
6292
+ \${c.bold}Usage:\${c.reset}
6293
+ liminal config \${c.dim}# Show all config\${c.reset}
6294
+ liminal config --get KEY \${c.dim}# Get a specific value\${c.reset}
6295
+ liminal config --set KEY=VALUE \${c.dim}# Set a value\${c.reset}
6296
+ `,
6297
+ logs: `
6298
+ \${c.bold}liminal logs\${c.reset} \u2014 View proxy logs
6299
+
6300
+ \${c.bold}Usage:\${c.reset}
6301
+ liminal logs [options]
6302
+
6303
+ \${c.bold}Options:\${c.reset}
6304
+ --follow, -f Follow log output (tail -f style)
6305
+ --lines N Number of lines to show (default: 50)
6306
+ `,
6307
+ init: `
6308
+ \${c.bold}liminal init\${c.reset} \u2014 Set up Liminal (login, config)
6309
+
6310
+ \${c.bold}Usage:\${c.reset}
6311
+ liminal init
6312
+ `,
6313
+ login: `
6314
+ \${c.bold}liminal login\${c.reset} \u2014 Log in or create an account
6315
+
6316
+ \${c.bold}Usage:\${c.reset}
6317
+ liminal login
6318
+ `,
6319
+ logout: `
6320
+ \${c.bold}liminal logout\${c.reset} \u2014 Log out of your account
6321
+
6322
+ \${c.bold}Usage:\${c.reset}
6323
+ liminal logout
6324
+ `
6325
+ };
6326
+ return helps[cmd] ?? null;
6327
+ }
6888
6328
  async function main() {
6889
6329
  const { command, flags } = parseArgs(process.argv);
6890
6330
  if (flags.has("h") || flags.has("help") || command === "help" || command === "--help" || command === "-h") {
6331
+ if (command && command !== "help" && command !== "--help" && command !== "-h") {
6332
+ const helpText = getCommandHelp(command);
6333
+ if (helpText) {
6334
+ console.log(helpText);
6335
+ process.exit(0);
6336
+ }
6337
+ }
6891
6338
  console.log(usage());
6892
6339
  process.exit(0);
6893
6340
  }
@@ -6974,4 +6421,3 @@ async function main() {
6974
6421
  }
6975
6422
  }
6976
6423
  main();
6977
- //# sourceMappingURL=bin.js.map