@nxuss/lemma 1.9.1 → 1.11.0

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 (122) hide show
  1. package/README.md +24 -4
  2. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  3. package/dist/cjs/cli/lemma-proxy.js +7 -2
  4. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  5. package/dist/cjs/mcp/tool-profiles.d.ts.map +1 -1
  6. package/dist/cjs/mcp/tool-profiles.js +43 -0
  7. package/dist/cjs/mcp/tool-profiles.js.map +1 -1
  8. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  9. package/dist/cjs/mcp/tools.js +314 -146
  10. package/dist/cjs/mcp/tools.js.map +1 -1
  11. package/dist/cjs/subconscious/TheBrainV2.d.ts +27 -1
  12. package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
  13. package/dist/cjs/subconscious/TheBrainV2.js +53 -1
  14. package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
  15. package/dist/cjs/utils/AffectedTests.d.ts +54 -0
  16. package/dist/cjs/utils/AffectedTests.d.ts.map +1 -0
  17. package/dist/cjs/utils/AffectedTests.js +195 -0
  18. package/dist/cjs/utils/AffectedTests.js.map +1 -0
  19. package/dist/cjs/utils/AstSymbolCache.d.ts +29 -0
  20. package/dist/cjs/utils/AstSymbolCache.d.ts.map +1 -0
  21. package/dist/cjs/utils/AstSymbolCache.js +66 -0
  22. package/dist/cjs/utils/AstSymbolCache.js.map +1 -0
  23. package/dist/cjs/utils/ContextSqueezer.d.ts +24 -4
  24. package/dist/cjs/utils/ContextSqueezer.d.ts.map +1 -1
  25. package/dist/cjs/utils/ContextSqueezer.js +32 -3
  26. package/dist/cjs/utils/ContextSqueezer.js.map +1 -1
  27. package/dist/cjs/utils/DepGraph.d.ts +28 -0
  28. package/dist/cjs/utils/DepGraph.d.ts.map +1 -0
  29. package/dist/cjs/utils/DepGraph.js +210 -0
  30. package/dist/cjs/utils/DepGraph.js.map +1 -0
  31. package/dist/cjs/utils/LocalPrefilter.d.ts +61 -0
  32. package/dist/cjs/utils/LocalPrefilter.d.ts.map +1 -0
  33. package/dist/cjs/utils/LocalPrefilter.js +169 -0
  34. package/dist/cjs/utils/LocalPrefilter.js.map +1 -0
  35. package/dist/cjs/utils/OutputDelta.d.ts +60 -0
  36. package/dist/cjs/utils/OutputDelta.d.ts.map +1 -0
  37. package/dist/cjs/utils/OutputDelta.js +226 -0
  38. package/dist/cjs/utils/OutputDelta.js.map +1 -0
  39. package/dist/cjs/utils/OutputLedger.d.ts +60 -0
  40. package/dist/cjs/utils/OutputLedger.d.ts.map +1 -0
  41. package/dist/cjs/utils/OutputLedger.js +134 -0
  42. package/dist/cjs/utils/OutputLedger.js.map +1 -0
  43. package/dist/cjs/utils/ReadWorkspaceCache.d.ts +8 -2
  44. package/dist/cjs/utils/ReadWorkspaceCache.d.ts.map +1 -1
  45. package/dist/cjs/utils/ReadWorkspaceCache.js +82 -4
  46. package/dist/cjs/utils/ReadWorkspaceCache.js.map +1 -1
  47. package/dist/cjs/utils/RoiLedger.d.ts +31 -0
  48. package/dist/cjs/utils/RoiLedger.d.ts.map +1 -0
  49. package/dist/cjs/utils/RoiLedger.js +113 -0
  50. package/dist/cjs/utils/RoiLedger.js.map +1 -0
  51. package/dist/cjs/utils/SharedLedgerStore.d.ts +26 -0
  52. package/dist/cjs/utils/SharedLedgerStore.d.ts.map +1 -0
  53. package/dist/cjs/utils/SharedLedgerStore.js +130 -0
  54. package/dist/cjs/utils/SharedLedgerStore.js.map +1 -0
  55. package/dist/cjs/utils/SpeculativeWarmer.d.ts +24 -0
  56. package/dist/cjs/utils/SpeculativeWarmer.d.ts.map +1 -0
  57. package/dist/cjs/utils/SpeculativeWarmer.js +73 -0
  58. package/dist/cjs/utils/SpeculativeWarmer.js.map +1 -0
  59. package/dist/cjs/utils/reportSavings.d.ts.map +1 -1
  60. package/dist/cjs/utils/reportSavings.js +11 -0
  61. package/dist/cjs/utils/reportSavings.js.map +1 -1
  62. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  63. package/dist/esm/cli/lemma-proxy.js +7 -2
  64. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  65. package/dist/esm/mcp/tool-profiles.d.ts.map +1 -1
  66. package/dist/esm/mcp/tool-profiles.js +43 -0
  67. package/dist/esm/mcp/tool-profiles.js.map +1 -1
  68. package/dist/esm/mcp/tools.d.ts.map +1 -1
  69. package/dist/esm/mcp/tools.js +312 -144
  70. package/dist/esm/mcp/tools.js.map +1 -1
  71. package/dist/esm/subconscious/TheBrainV2.d.ts +27 -1
  72. package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
  73. package/dist/esm/subconscious/TheBrainV2.js +53 -1
  74. package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
  75. package/dist/esm/utils/AffectedTests.d.ts +54 -0
  76. package/dist/esm/utils/AffectedTests.d.ts.map +1 -0
  77. package/dist/esm/utils/AffectedTests.js +186 -0
  78. package/dist/esm/utils/AffectedTests.js.map +1 -0
  79. package/dist/esm/utils/AstSymbolCache.d.ts +29 -0
  80. package/dist/esm/utils/AstSymbolCache.d.ts.map +1 -0
  81. package/dist/esm/utils/AstSymbolCache.js +58 -0
  82. package/dist/esm/utils/AstSymbolCache.js.map +1 -0
  83. package/dist/esm/utils/ContextSqueezer.d.ts +24 -4
  84. package/dist/esm/utils/ContextSqueezer.d.ts.map +1 -1
  85. package/dist/esm/utils/ContextSqueezer.js +32 -3
  86. package/dist/esm/utils/ContextSqueezer.js.map +1 -1
  87. package/dist/esm/utils/DepGraph.d.ts +28 -0
  88. package/dist/esm/utils/DepGraph.d.ts.map +1 -0
  89. package/dist/esm/utils/DepGraph.js +169 -0
  90. package/dist/esm/utils/DepGraph.js.map +1 -0
  91. package/dist/esm/utils/LocalPrefilter.d.ts +61 -0
  92. package/dist/esm/utils/LocalPrefilter.d.ts.map +1 -0
  93. package/dist/esm/utils/LocalPrefilter.js +159 -0
  94. package/dist/esm/utils/LocalPrefilter.js.map +1 -0
  95. package/dist/esm/utils/OutputDelta.d.ts +60 -0
  96. package/dist/esm/utils/OutputDelta.d.ts.map +1 -0
  97. package/dist/esm/utils/OutputDelta.js +221 -0
  98. package/dist/esm/utils/OutputDelta.js.map +1 -0
  99. package/dist/esm/utils/OutputLedger.d.ts +60 -0
  100. package/dist/esm/utils/OutputLedger.d.ts.map +1 -0
  101. package/dist/esm/utils/OutputLedger.js +125 -0
  102. package/dist/esm/utils/OutputLedger.js.map +1 -0
  103. package/dist/esm/utils/ReadWorkspaceCache.d.ts +8 -2
  104. package/dist/esm/utils/ReadWorkspaceCache.d.ts.map +1 -1
  105. package/dist/esm/utils/ReadWorkspaceCache.js +81 -4
  106. package/dist/esm/utils/ReadWorkspaceCache.js.map +1 -1
  107. package/dist/esm/utils/RoiLedger.d.ts +31 -0
  108. package/dist/esm/utils/RoiLedger.d.ts.map +1 -0
  109. package/dist/esm/utils/RoiLedger.js +104 -0
  110. package/dist/esm/utils/RoiLedger.js.map +1 -0
  111. package/dist/esm/utils/SharedLedgerStore.d.ts +26 -0
  112. package/dist/esm/utils/SharedLedgerStore.d.ts.map +1 -0
  113. package/dist/esm/utils/SharedLedgerStore.js +122 -0
  114. package/dist/esm/utils/SharedLedgerStore.js.map +1 -0
  115. package/dist/esm/utils/SpeculativeWarmer.d.ts +24 -0
  116. package/dist/esm/utils/SpeculativeWarmer.d.ts.map +1 -0
  117. package/dist/esm/utils/SpeculativeWarmer.js +66 -0
  118. package/dist/esm/utils/SpeculativeWarmer.js.map +1 -0
  119. package/dist/esm/utils/reportSavings.d.ts.map +1 -1
  120. package/dist/esm/utils/reportSavings.js +11 -0
  121. package/dist/esm/utils/reportSavings.js.map +1 -1
  122. package/package.json +1 -1
@@ -0,0 +1,24 @@
1
+ /**
2
+ * SpeculativeWarmer — precomputes local caches for a file's import neighbors while the
3
+ * model is off reasoning about what it just read, so a follow-up `get_ast_hologram` or
4
+ * `depgraph`/`affected_tests` call on a neighbor is a cache hit instead of a cold parse.
5
+ *
6
+ * HARD RULE: this warms local caches only (`DepGraph`'s graph cache, `AstSymbolCache`) and
7
+ * must never touch anything that reaches the model's context. It runs after the response for
8
+ * the triggering tool call has already been returned, off the event loop's current tick, and
9
+ * every failure is swallowed — a warming run that throws or runs slow must never be visible
10
+ * to whoever is waiting on the actual tool call.
11
+ */
12
+ import { AstSymbol } from "./AstSymbolCache";
13
+ /**
14
+ * `extractSymbolsWithTsCompiler` lives in `mcp/tools.ts`, which already imports this module —
15
+ * importing it back here would be circular. The dispatcher registers it once at startup instead.
16
+ */
17
+ export declare function registerSymbolExtractor(extractor: (absPath: string, relPath: string, parseErrors?: string[]) => AstSymbol[]): void;
18
+ /**
19
+ * Fire-and-forget: warm the import-neighborhood of `filePath` after a real read. Safe to call
20
+ * unconditionally — it is a no-op (not just cheap, actually skipped) whenever the extractor
21
+ * hasn't been registered yet, since that means startup isn't finished.
22
+ */
23
+ export declare function warmNeighbors(workspaceRoot: string, filePath: string): void;
24
+ //# sourceMappingURL=SpeculativeWarmer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpeculativeWarmer.d.ts","sourceRoot":"","sources":["../../../src/utils/SpeculativeWarmer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAsC,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQjF;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,SAAS,EAAE,GACnF,IAAI,CAEN;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CA4B3E"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ /**
3
+ * SpeculativeWarmer — precomputes local caches for a file's import neighbors while the
4
+ * model is off reasoning about what it just read, so a follow-up `get_ast_hologram` or
5
+ * `depgraph`/`affected_tests` call on a neighbor is a cache hit instead of a cold parse.
6
+ *
7
+ * HARD RULE: this warms local caches only (`DepGraph`'s graph cache, `AstSymbolCache`) and
8
+ * must never touch anything that reaches the model's context. It runs after the response for
9
+ * the triggering tool call has already been returned, off the event loop's current tick, and
10
+ * every failure is swallowed — a warming run that throws or runs slow must never be visible
11
+ * to whoever is waiting on the actual tool call.
12
+ */
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.registerSymbolExtractor = registerSymbolExtractor;
18
+ exports.warmNeighbors = warmNeighbors;
19
+ const fs_1 = __importDefault(require("fs"));
20
+ const path_1 = __importDefault(require("path"));
21
+ const DepGraph_1 = require("./DepGraph");
22
+ const AstSymbolCache_1 = require("./AstSymbolCache");
23
+ /** How many neighbor files a single warm pass will touch — bounded so this stays cheap. */
24
+ const MAX_NEIGHBORS = 8;
25
+ const MAX_DEPTH = 1;
26
+ let extractorRef = null;
27
+ /**
28
+ * `extractSymbolsWithTsCompiler` lives in `mcp/tools.ts`, which already imports this module —
29
+ * importing it back here would be circular. The dispatcher registers it once at startup instead.
30
+ */
31
+ function registerSymbolExtractor(extractor) {
32
+ extractorRef = extractor;
33
+ }
34
+ /**
35
+ * Fire-and-forget: warm the import-neighborhood of `filePath` after a real read. Safe to call
36
+ * unconditionally — it is a no-op (not just cheap, actually skipped) whenever the extractor
37
+ * hasn't been registered yet, since that means startup isn't finished.
38
+ */
39
+ function warmNeighbors(workspaceRoot, filePath) {
40
+ if (!extractorRef)
41
+ return;
42
+ const extractor = extractorRef;
43
+ // Deferred and unref'd so it can never keep the process alive or delay the response that
44
+ // triggered it — this must cost the triggering call nothing.
45
+ const timer = setTimeout(() => {
46
+ try {
47
+ const rel = path_1.default.relative(workspaceRoot, filePath).split(path_1.default.sep).join("/");
48
+ const graph = (0, DepGraph_1.buildDepGraphMap)(workspaceRoot);
49
+ const node = graph.get(rel);
50
+ if (!node)
51
+ return;
52
+ const neighbors = (0, DepGraph_1.bfsDepGraph)(graph, rel, "forward", MAX_DEPTH);
53
+ let warmed = 0;
54
+ for (const [neighborRel, { node: neighborNode }] of neighbors) {
55
+ if (warmed >= MAX_NEIGHBORS)
56
+ break;
57
+ if (neighborRel === rel)
58
+ continue;
59
+ if ((0, AstSymbolCache_1.hasFreshEntry)(neighborNode.abs))
60
+ continue; // already warm — nothing to do
61
+ if (!fs_1.default.existsSync(neighborNode.abs))
62
+ continue;
63
+ (0, AstSymbolCache_1.getOrExtractSymbols)(neighborNode.abs, neighborRel, extractor);
64
+ warmed++;
65
+ }
66
+ }
67
+ catch {
68
+ // Warming must never surface an error anywhere the model or the user can see it.
69
+ }
70
+ }, 0);
71
+ timer.unref?.();
72
+ }
73
+ //# sourceMappingURL=SpeculativeWarmer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpeculativeWarmer.js","sourceRoot":"","sources":["../../../src/utils/SpeculativeWarmer.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;;;AAiBH,0DAIC;AAOD,sCA4BC;AAtDD,4CAAoB;AACpB,gDAAwB;AACxB,yCAA2D;AAC3D,qDAAiF;AAEjF,2FAA2F;AAC3F,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,SAAS,GAAG,CAAC,CAAC;AAEpB,IAAI,YAAY,GAAuF,IAAI,CAAC;AAE5G;;;GAGG;AACH,SAAgB,uBAAuB,CACrC,SAAoF;IAEpF,YAAY,GAAG,SAAS,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,SAAgB,aAAa,CAAC,aAAqB,EAAE,QAAgB;IACnE,IAAI,CAAC,YAAY;QAAE,OAAO;IAC1B,MAAM,SAAS,GAAG,YAAY,CAAC;IAE/B,yFAAyF;IACzF,6DAA6D;IAC7D,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;QAC5B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,cAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,cAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC7E,MAAM,KAAK,GAAG,IAAA,2BAAgB,EAAC,aAAa,CAAC,CAAC;YAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,IAAI;gBAAE,OAAO;YAElB,MAAM,SAAS,GAAG,IAAA,sBAAW,EAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;YAChE,IAAI,MAAM,GAAG,CAAC,CAAC;YACf,KAAK,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;gBAC9D,IAAI,MAAM,IAAI,aAAa;oBAAE,MAAM;gBACnC,IAAI,WAAW,KAAK,GAAG;oBAAE,SAAS;gBAClC,IAAI,IAAA,8BAAa,EAAC,YAAY,CAAC,GAAG,CAAC;oBAAE,SAAS,CAAC,+BAA+B;gBAC9E,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAC/C,IAAA,oCAAmB,EAAC,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;gBAC9D,MAAM,EAAE,CAAC;YACX,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,iFAAiF;QACnF,CAAC;IACH,CAAC,EAAE,CAAC,CAAC,CAAC;IACN,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;AAClB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"reportSavings.d.ts","sourceRoot":"","sources":["../../../src/utils/reportSavings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,KAAK,aAAa,GAAG,WAAW,GAAG,gBAAgB,GAAG,cAAc,GAAG,mBAAmB,GAAG,OAAO,CAAC;AAErG,UAAU,aAAa;IACrB,MAAM,EAAE,aAAa,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,cAAc;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,aAAa,GAAG,aAAa,GAAG,cAAc,CAAC;AAYpD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAE1D;AAED,KAAK,UAAU,GAAG,iBAAiB,GAAG,YAAY,GAAG,WAAW,CAAC;AAEjE,UAAU,WAAW;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAErD"}
1
+ {"version":3,"file":"reportSavings.d.ts","sourceRoot":"","sources":["../../../src/utils/reportSavings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,KAAK,aAAa,GAAG,WAAW,GAAG,gBAAgB,GAAG,cAAc,GAAG,mBAAmB,GAAG,OAAO,CAAC;AAErG,UAAU,aAAa;IACrB,MAAM,EAAE,aAAa,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,cAAc;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,aAAa,GAAG,aAAa,GAAG,cAAc,CAAC;AAYpD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAQ1D;AAED,KAAK,UAAU,GAAG,iBAAiB,GAAG,YAAY,GAAG,WAAW,CAAC;AAEjE,UAAU,WAAW;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAMrD"}
@@ -15,6 +15,7 @@ const fs_1 = __importDefault(require("fs"));
15
15
  const path_1 = __importDefault(require("path"));
16
16
  const os_1 = __importDefault(require("os"));
17
17
  const http_1 = __importDefault(require("http"));
18
+ const RoiLedger_1 = require("./RoiLedger");
18
19
  function getProxyPort() {
19
20
  try {
20
21
  const portFile = path_1.default.join(os_1.default.homedir(), '.lemma-cache/proxy.port');
@@ -31,6 +32,12 @@ function getProxyPort() {
31
32
  */
32
33
  function reportSavings(payload) {
33
34
  post('/api/savings-record', payload);
35
+ if (payload.toolName) {
36
+ const tokens = 'tokens' in payload ? payload.tokens : Math.floor(Math.max(0, payload.charsBefore - payload.charsAfter) / 4);
37
+ // Best-effort, repo-scoped: process.cwd() is the workspace root for every MCP tool
38
+ // handler, same assumption `tools.ts` already makes throughout.
39
+ (0, RoiLedger_1.recordRoiSaved)(process.cwd(), payload.toolName, tokens);
40
+ }
34
41
  }
35
42
  /**
36
43
  * Report tokens Lemma *spent* to the proxy's ledger. Same fire-and-forget contract
@@ -39,6 +46,10 @@ function reportSavings(payload) {
39
46
  */
40
47
  function reportCost(payload) {
41
48
  post('/api/cost-record', payload);
49
+ if (payload.toolName) {
50
+ const tokens = typeof payload.tokens === 'number' ? payload.tokens : Math.floor(Math.max(0, payload.chars || 0) / 4);
51
+ (0, RoiLedger_1.recordRoiSpent)(process.cwd(), payload.toolName, tokens);
52
+ }
42
53
  }
43
54
  function post(pathname, payload) {
44
55
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"reportSavings.js","sourceRoot":"","sources":["../../../src/utils/reportSavings.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;AA0CH,sCAEC;AAkBD,gCAEC;AA9DD,4CAAoB;AACpB,gDAAwB;AACxB,4CAAoB;AACpB,gDAAwB;AAuBxB,SAAS,YAAY;IACnB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,yBAAyB,CAAC,CAAC;QACpE,IAAI,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,OAAO,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAClD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAgB,aAAa,CAAC,OAAsB;IAClD,IAAI,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC;AAaD;;;;GAIG;AACH,SAAgB,UAAU,CAAC,OAAoB;IAC7C,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,IAAI,CAAC,QAAgB,EAAE,OAAgB;IAC9C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAErC,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC;YACvB,QAAQ,EAAE,WAAW;YACrB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;YACpB,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;aAC1C;SACF,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,yCAAyC;QACpE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChB,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"reportSavings.js","sourceRoot":"","sources":["../../../src/utils/reportSavings.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;AA2CH,sCAQC;AAkBD,gCAMC;AAzED,4CAAoB;AACpB,gDAAwB;AACxB,4CAAoB;AACpB,gDAAwB;AACxB,2CAA6D;AAuB7D,SAAS,YAAY;IACnB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,yBAAyB,CAAC,CAAC;QACpE,IAAI,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,OAAO,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAClD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAgB,aAAa,CAAC,OAAsB;IAClD,IAAI,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5H,mFAAmF;QACnF,gEAAgE;QAChE,IAAA,0BAAc,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAaD;;;;GAIG;AACH,SAAgB,UAAU,CAAC,OAAoB;IAC7C,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;IAClC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACrH,IAAA,0BAAc,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,QAAgB,EAAE,OAAgB;IAC9C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAErC,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC;YACvB,QAAQ,EAAE,WAAW;YACrB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;YACpB,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;aAC1C;SACF,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,yCAAyC;QACpE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChB,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AA4cA,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA4DvF;AA8lED,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6KhL"}
1
+ {"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AA4cA,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA4DvF;AAmmED,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6KhL"}
@@ -1914,8 +1914,13 @@ Adjusted Answer:`;
1914
1914
  if (provider === 'openai' || provider === 'anthropic') {
1915
1915
  if (req.body.messages && req.body.messages.length > 0) {
1916
1916
  injectSqueezedContent(req.body.messages[req.body.messages.length - 1], squeezedPrompt);
1917
- // Apply conversational history pruning
1918
- const pruneResult = pruneHistoryMessages(req.body.messages);
1917
+ // Apply conversational history pruning — off by default (T7 guard): pruning
1918
+ // invalidates the cached prompt prefix, which is usually a net loss. Set
1919
+ // LEMMA_FORCE_HISTORY_PRUNE=1 to opt back into the old unconditional behavior
1920
+ // (e.g. for a provider with no prompt caching).
1921
+ const pruneResult = pruneHistoryMessages(req.body.messages, {
1922
+ force: process.env.LEMMA_FORCE_HISTORY_PRUNE === '1',
1923
+ });
1919
1924
  req.body.messages = pruneResult.messages;
1920
1925
  historyTokensSaved = pruneResult.tokensSavedEstimate + Math.floor(compressionSavings / 4);
1921
1926
  if (pruneResult.tokensSavedEstimate > 0) {