@nxuss/lemma 1.22.1 → 1.24.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 (176) hide show
  1. package/README.md +33 -7
  2. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  3. package/dist/cjs/cli/lemma-proxy.js +15 -3
  4. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  5. package/dist/cjs/cloud/store/FileBrainStore.d.ts.map +1 -1
  6. package/dist/cjs/cloud/store/FileBrainStore.js +5 -2
  7. package/dist/cjs/cloud/store/FileBrainStore.js.map +1 -1
  8. package/dist/cjs/infra/errorCause.d.ts +36 -0
  9. package/dist/cjs/infra/errorCause.d.ts.map +1 -0
  10. package/dist/cjs/infra/errorCause.js +143 -0
  11. package/dist/cjs/infra/errorCause.js.map +1 -0
  12. package/dist/cjs/infra/providers/JenkinsProvider.d.ts.map +1 -1
  13. package/dist/cjs/infra/providers/JenkinsProvider.js +5 -0
  14. package/dist/cjs/infra/providers/JenkinsProvider.js.map +1 -1
  15. package/dist/cjs/infra/providers/OKDProvider.d.ts.map +1 -1
  16. package/dist/cjs/infra/providers/OKDProvider.js +5 -1
  17. package/dist/cjs/infra/providers/OKDProvider.js.map +1 -1
  18. package/dist/cjs/infra/providers/TerraformProvider.d.ts.map +1 -1
  19. package/dist/cjs/infra/providers/TerraformProvider.js +3 -1
  20. package/dist/cjs/infra/providers/TerraformProvider.js.map +1 -1
  21. package/dist/cjs/mcp/index.js +21 -0
  22. package/dist/cjs/mcp/index.js.map +1 -1
  23. package/dist/cjs/mcp/tool-profiles.d.ts +6 -4
  24. package/dist/cjs/mcp/tool-profiles.d.ts.map +1 -1
  25. package/dist/cjs/mcp/tool-profiles.js +3 -0
  26. package/dist/cjs/mcp/tool-profiles.js.map +1 -1
  27. package/dist/cjs/mcp/tools/context-tools.d.ts.map +1 -1
  28. package/dist/cjs/mcp/tools/context-tools.js +3 -1
  29. package/dist/cjs/mcp/tools/context-tools.js.map +1 -1
  30. package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
  31. package/dist/cjs/mcp/tools/memory.js +255 -15
  32. package/dist/cjs/mcp/tools/memory.js.map +1 -1
  33. package/dist/cjs/mcp/tools/misc.d.ts.map +1 -1
  34. package/dist/cjs/mcp/tools/misc.js +21 -9
  35. package/dist/cjs/mcp/tools/misc.js.map +1 -1
  36. package/dist/cjs/mcp/tools/squeeze-cache.d.ts +6 -0
  37. package/dist/cjs/mcp/tools/squeeze-cache.d.ts.map +1 -1
  38. package/dist/cjs/mcp/tools/squeeze-cache.js +57 -17
  39. package/dist/cjs/mcp/tools/squeeze-cache.js.map +1 -1
  40. package/dist/cjs/mcp/tools/workspace.d.ts.map +1 -1
  41. package/dist/cjs/mcp/tools/workspace.js +7 -2
  42. package/dist/cjs/mcp/tools/workspace.js.map +1 -1
  43. package/dist/cjs/mcp/tools.d.ts +18 -0
  44. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  45. package/dist/cjs/mcp/tools.js +97 -16
  46. package/dist/cjs/mcp/tools.js.map +1 -1
  47. package/dist/cjs/mcp/utils.d.ts.map +1 -1
  48. package/dist/cjs/mcp/utils.js +18 -4
  49. package/dist/cjs/mcp/utils.js.map +1 -1
  50. package/dist/cjs/mcp/workspaceShared.d.ts +1 -0
  51. package/dist/cjs/mcp/workspaceShared.d.ts.map +1 -1
  52. package/dist/cjs/mcp/workspaceShared.js +27 -0
  53. package/dist/cjs/mcp/workspaceShared.js.map +1 -1
  54. package/dist/cjs/security/scrubForStorage.d.ts +16 -0
  55. package/dist/cjs/security/scrubForStorage.d.ts.map +1 -0
  56. package/dist/cjs/security/scrubForStorage.js +35 -0
  57. package/dist/cjs/security/scrubForStorage.js.map +1 -0
  58. package/dist/cjs/subconscious/BrainEncryption.d.ts +38 -0
  59. package/dist/cjs/subconscious/BrainEncryption.d.ts.map +1 -0
  60. package/dist/cjs/subconscious/BrainEncryption.js +137 -0
  61. package/dist/cjs/subconscious/BrainEncryption.js.map +1 -0
  62. package/dist/cjs/subconscious/TheBrainV2.d.ts +337 -0
  63. package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
  64. package/dist/cjs/subconscious/TheBrainV2.js +1149 -118
  65. package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
  66. package/dist/cjs/utils/AnomalyInventory.d.ts +29 -0
  67. package/dist/cjs/utils/AnomalyInventory.d.ts.map +1 -0
  68. package/dist/cjs/utils/AnomalyInventory.js +58 -0
  69. package/dist/cjs/utils/AnomalyInventory.js.map +1 -0
  70. package/dist/cjs/utils/ExecutiveReport.d.ts +10 -0
  71. package/dist/cjs/utils/ExecutiveReport.d.ts.map +1 -1
  72. package/dist/cjs/utils/ExecutiveReport.js +17 -1
  73. package/dist/cjs/utils/ExecutiveReport.js.map +1 -1
  74. package/dist/cjs/utils/SavingsLedger.d.ts +45 -2
  75. package/dist/cjs/utils/SavingsLedger.d.ts.map +1 -1
  76. package/dist/cjs/utils/SavingsLedger.js +89 -5
  77. package/dist/cjs/utils/SavingsLedger.js.map +1 -1
  78. package/dist/cjs/utils/SessionEvidence.d.ts +28 -0
  79. package/dist/cjs/utils/SessionEvidence.d.ts.map +1 -0
  80. package/dist/cjs/utils/SessionEvidence.js +55 -0
  81. package/dist/cjs/utils/SessionEvidence.js.map +1 -0
  82. package/dist/cjs/utils/StateHashCache.d.ts +10 -0
  83. package/dist/cjs/utils/StateHashCache.d.ts.map +1 -1
  84. package/dist/cjs/utils/StateHashCache.js +15 -0
  85. package/dist/cjs/utils/StateHashCache.js.map +1 -1
  86. package/dist/cjs/utils/reportSavings.d.ts +4 -0
  87. package/dist/cjs/utils/reportSavings.d.ts.map +1 -1
  88. package/dist/cjs/utils/reportSavings.js.map +1 -1
  89. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  90. package/dist/esm/cli/lemma-proxy.js +15 -3
  91. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  92. package/dist/esm/cloud/store/FileBrainStore.d.ts.map +1 -1
  93. package/dist/esm/cloud/store/FileBrainStore.js +5 -2
  94. package/dist/esm/cloud/store/FileBrainStore.js.map +1 -1
  95. package/dist/esm/infra/errorCause.d.ts +36 -0
  96. package/dist/esm/infra/errorCause.d.ts.map +1 -0
  97. package/dist/esm/infra/errorCause.js +138 -0
  98. package/dist/esm/infra/errorCause.js.map +1 -0
  99. package/dist/esm/infra/providers/JenkinsProvider.d.ts.map +1 -1
  100. package/dist/esm/infra/providers/JenkinsProvider.js +5 -0
  101. package/dist/esm/infra/providers/JenkinsProvider.js.map +1 -1
  102. package/dist/esm/infra/providers/OKDProvider.d.ts.map +1 -1
  103. package/dist/esm/infra/providers/OKDProvider.js +5 -1
  104. package/dist/esm/infra/providers/OKDProvider.js.map +1 -1
  105. package/dist/esm/infra/providers/TerraformProvider.d.ts.map +1 -1
  106. package/dist/esm/infra/providers/TerraformProvider.js +3 -1
  107. package/dist/esm/infra/providers/TerraformProvider.js.map +1 -1
  108. package/dist/esm/mcp/index.js +21 -0
  109. package/dist/esm/mcp/index.js.map +1 -1
  110. package/dist/esm/mcp/tool-profiles.d.ts +6 -4
  111. package/dist/esm/mcp/tool-profiles.d.ts.map +1 -1
  112. package/dist/esm/mcp/tool-profiles.js +3 -0
  113. package/dist/esm/mcp/tool-profiles.js.map +1 -1
  114. package/dist/esm/mcp/tools/context-tools.d.ts.map +1 -1
  115. package/dist/esm/mcp/tools/context-tools.js +3 -1
  116. package/dist/esm/mcp/tools/context-tools.js.map +1 -1
  117. package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
  118. package/dist/esm/mcp/tools/memory.js +255 -15
  119. package/dist/esm/mcp/tools/memory.js.map +1 -1
  120. package/dist/esm/mcp/tools/misc.d.ts.map +1 -1
  121. package/dist/esm/mcp/tools/misc.js +21 -9
  122. package/dist/esm/mcp/tools/misc.js.map +1 -1
  123. package/dist/esm/mcp/tools/squeeze-cache.d.ts +6 -0
  124. package/dist/esm/mcp/tools/squeeze-cache.d.ts.map +1 -1
  125. package/dist/esm/mcp/tools/squeeze-cache.js +56 -17
  126. package/dist/esm/mcp/tools/squeeze-cache.js.map +1 -1
  127. package/dist/esm/mcp/tools/workspace.d.ts.map +1 -1
  128. package/dist/esm/mcp/tools/workspace.js +8 -3
  129. package/dist/esm/mcp/tools/workspace.js.map +1 -1
  130. package/dist/esm/mcp/tools.d.ts +18 -0
  131. package/dist/esm/mcp/tools.d.ts.map +1 -1
  132. package/dist/esm/mcp/tools.js +96 -17
  133. package/dist/esm/mcp/tools.js.map +1 -1
  134. package/dist/esm/mcp/utils.d.ts.map +1 -1
  135. package/dist/esm/mcp/utils.js +18 -4
  136. package/dist/esm/mcp/utils.js.map +1 -1
  137. package/dist/esm/mcp/workspaceShared.d.ts +1 -0
  138. package/dist/esm/mcp/workspaceShared.d.ts.map +1 -1
  139. package/dist/esm/mcp/workspaceShared.js +26 -0
  140. package/dist/esm/mcp/workspaceShared.js.map +1 -1
  141. package/dist/esm/security/scrubForStorage.d.ts +16 -0
  142. package/dist/esm/security/scrubForStorage.d.ts.map +1 -0
  143. package/dist/esm/security/scrubForStorage.js +32 -0
  144. package/dist/esm/security/scrubForStorage.js.map +1 -0
  145. package/dist/esm/subconscious/BrainEncryption.d.ts +38 -0
  146. package/dist/esm/subconscious/BrainEncryption.d.ts.map +1 -0
  147. package/dist/esm/subconscious/BrainEncryption.js +126 -0
  148. package/dist/esm/subconscious/BrainEncryption.js.map +1 -0
  149. package/dist/esm/subconscious/TheBrainV2.d.ts +337 -0
  150. package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
  151. package/dist/esm/subconscious/TheBrainV2.js +1147 -118
  152. package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
  153. package/dist/esm/utils/AnomalyInventory.d.ts +29 -0
  154. package/dist/esm/utils/AnomalyInventory.d.ts.map +1 -0
  155. package/dist/esm/utils/AnomalyInventory.js +49 -0
  156. package/dist/esm/utils/AnomalyInventory.js.map +1 -0
  157. package/dist/esm/utils/ExecutiveReport.d.ts +10 -0
  158. package/dist/esm/utils/ExecutiveReport.d.ts.map +1 -1
  159. package/dist/esm/utils/ExecutiveReport.js +17 -1
  160. package/dist/esm/utils/ExecutiveReport.js.map +1 -1
  161. package/dist/esm/utils/SavingsLedger.d.ts +45 -2
  162. package/dist/esm/utils/SavingsLedger.d.ts.map +1 -1
  163. package/dist/esm/utils/SavingsLedger.js +89 -5
  164. package/dist/esm/utils/SavingsLedger.js.map +1 -1
  165. package/dist/esm/utils/SessionEvidence.d.ts +28 -0
  166. package/dist/esm/utils/SessionEvidence.d.ts.map +1 -0
  167. package/dist/esm/utils/SessionEvidence.js +49 -0
  168. package/dist/esm/utils/SessionEvidence.js.map +1 -0
  169. package/dist/esm/utils/StateHashCache.d.ts +10 -0
  170. package/dist/esm/utils/StateHashCache.d.ts.map +1 -1
  171. package/dist/esm/utils/StateHashCache.js +14 -0
  172. package/dist/esm/utils/StateHashCache.js.map +1 -1
  173. package/dist/esm/utils/reportSavings.d.ts +4 -0
  174. package/dist/esm/utils/reportSavings.d.ts.map +1 -1
  175. package/dist/esm/utils/reportSavings.js.map +1 -1
  176. package/package.json +1 -1
package/README.md CHANGED
@@ -52,6 +52,23 @@ lemma start # gateway + dashboard on http://localhost:8081
52
52
  real usage (`hits`), explicit negative feedback (`downvote_memory`), and `cognitive_map` domain
53
53
  tags; a passing `test_oracle` run over an uncommitted diff auto-captures itself; two memories
54
54
  about the same symbol that disagree on outcome are flagged, not silently both suggested.
55
+ Every hit explains itself (`whyShown` ranking signals + cited `evidence` files/symbols), and
56
+ every reuse books its savings onto the memory itself — `brain_stats` names which memories
57
+ actually pay for the Brain (`totalTokensSaved`, top savers).
58
+ - **A memory that maintains itself** — `brain_upkeep` revalidates the most-reused memories,
59
+ surfaces exact duplicates and merge candidates, dead weight, and savings in one read-only
60
+ pass, each finding with its fix. `brain_merge` folds near-duplicate fragments into one
61
+ canonical entry (fragments survive as evidence-carrying claims). `forget_memory` moves to a
62
+ trash (`brain_trash`: list/restore/purge) instead of destroying, automatic snapshots roll
63
+ back every forget/import/clear/merge, and `brain_import dryRun:true` previews a bundle —
64
+ counts plus opposite-outcome conflicts — before a byte is written. Session onboarding
65
+ re-checks freshness of the memories it lists, so a day-one answer never starts stale.
66
+ - **Integrity and encryption at rest** — the corpus carries a sha256 sidecar with `.prev`
67
+ backup rotation: a half-written or rotted file serves its intact lines, falls back to the
68
+ backup on total loss, and quarantines (never deletes) the bad bytes, with the incident
69
+ surfaced in `brain_stats`. `LEMMA_BRAIN_ENCRYPT=1` (or `LEMMA_BRAIN_KEY`) stores the
70
+ corpus AES-256-GCM encrypted under a local 0600 key; secrets never reach disk at all —
71
+ scrub-on-store redacts credentials one-way before indexing or persisting.
55
72
  - **Verifiable caching, not marketing numbers** — `state_hash_cache` only hits when the files an
56
73
  answer depends on are byte-identical; `token_receipt` gives a real per-session breakdown of how
57
74
  each answer was produced instead of an invented "% saved."
@@ -66,7 +83,7 @@ lemma start # gateway + dashboard on http://localhost:8081
66
83
  compiler-verified AST location instead of asking the model to output a full-file rewrite.
67
84
  - **Infrastructure Command Center** — 22 free tools for Jenkins, OKD/OpenShift, and Terraform:
68
85
  discover, connect, deploy, diagnose, and detect drift, all via MCP.
69
- - **Scoped tool surface** — of the 98 registered tools, only the ones your project shows evidence
86
+ - **Scoped tool surface** — of the 108 registered tools, only the ones your project shows evidence
70
87
  of needing are advertised to the model each turn; the rest stay one `lemma_toolbox` call away.
71
88
 
72
89
  See [`CHANGELOG.md`](CHANGELOG.md) for the full, per-version history.
@@ -75,13 +92,14 @@ See [`CHANGELOG.md`](CHANGELOG.md) for the full, per-version history.
75
92
 
76
93
  ## 💎 Free vs Pro
77
94
 
78
- 48 of the 98 registered tools work with no license; 50 require Pro. Enforced by one allowlist in
79
- code (`FREE_TOOLS` in `src/mcp/tools.ts`), not by narrative. A session without a license doesn't
80
- even advertise the Pro tools — they stay registered and discoverable via `lemma_toolbox`.
95
+ 58 of the 108 registered tools work with no license; 50 require Pro. Enforced by one allowlist in
96
+ code (`FREE_TOOLS` in `src/mcp/tools.ts`, including all 22 infrastructure tools), not by narrative.
97
+ A session without a license doesn't even advertise the Pro tools — they stay registered and
98
+ discoverable via `lemma_toolbox`.
81
99
 
82
- | | Free (48) | Pro (50) |
100
+ | | Free (58) | Pro (50) |
83
101
  | :--- | :--- | :--- |
84
- | **Caching & memory** | `smarter_cache`, `state_hash_cache`, `token_receipt`, `search_memory`, `store_memory`, `downvote_memory`, `verify_memory`, `token_budget` | `get_telepathic_hints`, `query_hybrid_consensus`, `semantic_dedup_guard`, `local_semantic_autofix` |
102
+ | **Caching & memory** | `smarter_cache`, `state_hash_cache`, `token_receipt`, `search_memory`, `store_memory`, `downvote_memory`, `verify_memory`, `token_budget`, `brain_upkeep`, `brain_trash`, `brain_merge` | `get_telepathic_hints`, `query_hybrid_consensus`, `semantic_dedup_guard`, `local_semantic_autofix` |
85
103
  | **Reading & context** | `read_workspace_file`, `scrub_privacy`, `import_tree_context`, `bulk_file_digest`, `auto_context_bundle`, `git_blame_heat`, `type_coverage_report` | `get_ast_hologram`, `smart_file_slice`, `get_symbol_surgical_context`, `diff_only` |
86
104
  | **Writing & workspace** | — | `write_workspace_file`, `apply_workspace_patch`, `multi_file_patch`, `search_workspace`, `run_workspace_command`, `validate_patch_sandbox`, `surgical_ast_insert` |
87
105
  | **Static analysis** | — | `entropy_score`, `coupling_radar`, `pattern_fossil`, `precrime_static`, `dead_export_necromancer`, `depgraph`, `refactor`, `ast_flow_visualizer`, `cognitive_map` |
@@ -96,7 +114,7 @@ Full per-tool listing: `lemma_toolbox { "action": "list" }`.
96
114
 
97
115
  ## 🎚️ Tool profiles
98
116
 
99
- Every advertised tool schema is re-sent on **every request** of the session — advertising all 97
117
+ Every advertised tool schema is re-sent on **every request** of the session — advertising all 108
100
118
  costs ~11,600 tokens/turn. Lemma advertises a scoped surface instead: core tools always, situational
101
119
  groups (e.g. infrastructure) only when the repo shows evidence for them. Nothing is removed —
102
120
  everything stays registered and reachable via `lemma_toolbox`.
@@ -194,6 +212,14 @@ JS/TS, Python, Go, Rust, Ruby, JVM, `make`, git/gh, read-only shell utilities, a
194
212
  CLIs. Extend via `lemma.config.json` → `mcp.allowedCommandPrefixes`. See
195
213
  [`.env.security.example`](.env.security.example) for every security-related env var.
196
214
 
215
+ **Brain at rest.** Secrets are redacted one-way before a memory is indexed or persisted
216
+ (scrub-on-store, same patterns as the traffic firewall — the token map is discarded, there is
217
+ no unmask step). `LEMMA_BRAIN_ENCRYPT=1` additionally stores the corpus AES-256-GCM encrypted
218
+ under `<brainDir>/.brain.key` (0600, auto-generated); `LEMMA_BRAIN_KEY` (64 hex chars or base64
219
+ of 32 bytes) overrides it for teams sharing one key. A malformed key fails loud at startup;
220
+ a wrong key flows into the integrity fallback (backup → quarantine → fresh start), never an
221
+ exception, never half a corpus.
222
+
197
223
  ---
198
224
 
199
225
  ## 🦜 SDK integrations & proxy mode
@@ -1 +1 @@
1
- {"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AA0cA,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA4DvF;AAqfD,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGtD;AAyqDD,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,CA8KhL"}
1
+ {"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AA0cA,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA4DvF;AAqfD,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGtD;AAsrDD,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,CA8KhL"}
@@ -1566,16 +1566,28 @@ class LemmaServer {
1566
1566
  // Cost Record Endpoint — the counterpart to /api/savings-record. Without it the
1567
1567
  // ledger only ever counts wins, which makes its totals unfalsifiable.
1568
1568
  this.app.post('/api/cost-record', (req, res) => {
1569
- const { source, tokens, chars } = req.body || {};
1569
+ // AN-01: attribution rides in the same body tool/host/origin are what turn
1570
+ // the toolResult bucket from an inscrutable total into auditable accounting.
1571
+ // Unknown/unset stays "unknown": unattributed events are labeled, never re-homed.
1572
+ const { source, tokens, chars, toolName, tool, host, origin } = req.body || {};
1570
1573
  const validSources = ['mcpInstructions', 'toolResult', 'cacheMiss'];
1571
1574
  if (!source || !validSources.includes(source)) {
1572
1575
  return res.status(400).json({ error: 'Invalid cost source' });
1573
1576
  }
1577
+ const attribution = typeof toolName === 'string' || typeof tool === 'string' ||
1578
+ typeof host === 'string' || typeof origin === 'string'
1579
+ ? {
1580
+ ...(typeof toolName === 'string' && toolName ? { tool: toolName.slice(0, 128) } : {}),
1581
+ ...(typeof tool === 'string' && tool ? { tool: tool.slice(0, 128) } : {}),
1582
+ ...(typeof host === 'string' && host ? { host } : {}),
1583
+ ...(typeof origin === 'string' && origin ? { origin } : {}),
1584
+ }
1585
+ : undefined;
1574
1586
  if (typeof tokens === 'number' && tokens > 0) {
1575
- SavingsLedger_1.savingsLedger.recordCost(source, tokens);
1587
+ SavingsLedger_1.savingsLedger.recordCost(source, tokens, attribution);
1576
1588
  }
1577
1589
  else if (typeof chars === 'number' && chars > 0) {
1578
- SavingsLedger_1.savingsLedger.recordCostChars(source, chars);
1590
+ SavingsLedger_1.savingsLedger.recordCostChars(source, chars, attribution);
1579
1591
  }
1580
1592
  const snap = SavingsLedger_1.savingsLedger.getSnapshot();
1581
1593
  res.json({ ok: true, totalCost: snap.totalCost, net: snap.net });