@darkiceinteractive/mcp-conductor 2.0.0-alpha.1 → 3.0.0-beta.2

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 (276) hide show
  1. package/README.md +35 -5
  2. package/dist/bin/cli.d.ts +20 -0
  3. package/dist/bin/cli.d.ts.map +1 -0
  4. package/dist/bin/cli.js +260 -0
  5. package/dist/bin/cli.js.map +1 -0
  6. package/dist/bridge/http-server.d.ts +35 -0
  7. package/dist/bridge/http-server.d.ts.map +1 -1
  8. package/dist/bridge/http-server.js +51 -2
  9. package/dist/bridge/http-server.js.map +1 -1
  10. package/dist/bridge/index.d.ts +1 -0
  11. package/dist/bridge/index.d.ts.map +1 -1
  12. package/dist/bridge/index.js +1 -0
  13. package/dist/bridge/index.js.map +1 -1
  14. package/dist/bridge/pool.d.ts +95 -0
  15. package/dist/bridge/pool.d.ts.map +1 -0
  16. package/dist/bridge/pool.js +384 -0
  17. package/dist/bridge/pool.js.map +1 -0
  18. package/dist/cache/cache.d.ts +64 -0
  19. package/dist/cache/cache.d.ts.map +1 -0
  20. package/dist/cache/cache.js +209 -0
  21. package/dist/cache/cache.js.map +1 -0
  22. package/dist/cache/delta.d.ts +32 -0
  23. package/dist/cache/delta.d.ts.map +1 -0
  24. package/dist/cache/delta.js +131 -0
  25. package/dist/cache/delta.js.map +1 -0
  26. package/dist/cache/disk.d.ts +65 -0
  27. package/dist/cache/disk.d.ts.map +1 -0
  28. package/dist/cache/disk.js +238 -0
  29. package/dist/cache/disk.js.map +1 -0
  30. package/dist/cache/index.d.ts +53 -0
  31. package/dist/cache/index.d.ts.map +1 -0
  32. package/dist/cache/index.js +12 -0
  33. package/dist/cache/index.js.map +1 -0
  34. package/dist/cache/key.d.ts +44 -0
  35. package/dist/cache/key.d.ts.map +1 -0
  36. package/dist/cache/key.js +83 -0
  37. package/dist/cache/key.js.map +1 -0
  38. package/dist/cache/lru.d.ts +57 -0
  39. package/dist/cache/lru.d.ts.map +1 -0
  40. package/dist/cache/lru.js +112 -0
  41. package/dist/cache/lru.js.map +1 -0
  42. package/dist/cache/policy.d.ts +34 -0
  43. package/dist/cache/policy.d.ts.map +1 -0
  44. package/dist/cache/policy.js +95 -0
  45. package/dist/cache/policy.js.map +1 -0
  46. package/dist/cli/commands/doctor.d.ts +33 -0
  47. package/dist/cli/commands/doctor.d.ts.map +1 -0
  48. package/dist/cli/commands/doctor.js +135 -0
  49. package/dist/cli/commands/doctor.js.map +1 -0
  50. package/dist/cli/commands/export-servers.d.ts +22 -0
  51. package/dist/cli/commands/export-servers.d.ts.map +1 -0
  52. package/dist/cli/commands/export-servers.js +45 -0
  53. package/dist/cli/commands/export-servers.js.map +1 -0
  54. package/dist/cli/commands/import-servers.d.ts +57 -0
  55. package/dist/cli/commands/import-servers.d.ts.map +1 -0
  56. package/dist/cli/commands/import-servers.js +137 -0
  57. package/dist/cli/commands/import-servers.js.map +1 -0
  58. package/dist/cli/commands/routing.d.ts +34 -0
  59. package/dist/cli/commands/routing.d.ts.map +1 -0
  60. package/dist/cli/commands/routing.js +60 -0
  61. package/dist/cli/commands/routing.js.map +1 -0
  62. package/dist/cli/commands/test-server.d.ts +34 -0
  63. package/dist/cli/commands/test-server.d.ts.map +1 -0
  64. package/dist/cli/commands/test-server.js +86 -0
  65. package/dist/cli/commands/test-server.js.map +1 -0
  66. package/dist/cli/daemon.d.ts +60 -0
  67. package/dist/cli/daemon.d.ts.map +1 -0
  68. package/dist/cli/daemon.js +244 -0
  69. package/dist/cli/daemon.js.map +1 -0
  70. package/dist/cli/replay.d.ts +16 -0
  71. package/dist/cli/replay.d.ts.map +1 -0
  72. package/dist/cli/replay.js +89 -0
  73. package/dist/cli/replay.js.map +1 -0
  74. package/dist/cli/wizard/setup.d.ts +12 -0
  75. package/dist/cli/wizard/setup.d.ts.map +1 -0
  76. package/dist/cli/wizard/setup.js +71 -0
  77. package/dist/cli/wizard/setup.js.map +1 -0
  78. package/dist/config/defaults.d.ts.map +1 -1
  79. package/dist/config/defaults.js +4 -1
  80. package/dist/config/defaults.js.map +1 -1
  81. package/dist/config/schema.d.ts +34 -0
  82. package/dist/config/schema.d.ts.map +1 -1
  83. package/dist/daemon/client.d.ts +99 -0
  84. package/dist/daemon/client.d.ts.map +1 -0
  85. package/dist/daemon/client.js +292 -0
  86. package/dist/daemon/client.js.map +1 -0
  87. package/dist/daemon/discovery.d.ts +50 -0
  88. package/dist/daemon/discovery.d.ts.map +1 -0
  89. package/dist/daemon/discovery.js +104 -0
  90. package/dist/daemon/discovery.js.map +1 -0
  91. package/dist/daemon/index.d.ts +16 -0
  92. package/dist/daemon/index.d.ts.map +1 -0
  93. package/dist/daemon/index.js +11 -0
  94. package/dist/daemon/index.js.map +1 -0
  95. package/dist/daemon/sandbox-api.d.ts +45 -0
  96. package/dist/daemon/sandbox-api.d.ts.map +1 -0
  97. package/dist/daemon/sandbox-api.js +74 -0
  98. package/dist/daemon/sandbox-api.js.map +1 -0
  99. package/dist/daemon/server.d.ts +65 -0
  100. package/dist/daemon/server.d.ts.map +1 -0
  101. package/dist/daemon/server.js +373 -0
  102. package/dist/daemon/server.js.map +1 -0
  103. package/dist/daemon/shared-kv.d.ts +81 -0
  104. package/dist/daemon/shared-kv.d.ts.map +1 -0
  105. package/dist/daemon/shared-kv.js +215 -0
  106. package/dist/daemon/shared-kv.js.map +1 -0
  107. package/dist/daemon/shared-lock.d.ts +71 -0
  108. package/dist/daemon/shared-lock.d.ts.map +1 -0
  109. package/dist/daemon/shared-lock.js +119 -0
  110. package/dist/daemon/shared-lock.js.map +1 -0
  111. package/dist/hub/mcp-hub.d.ts +23 -0
  112. package/dist/hub/mcp-hub.d.ts.map +1 -1
  113. package/dist/hub/mcp-hub.js +34 -1
  114. package/dist/hub/mcp-hub.js.map +1 -1
  115. package/dist/index.js +7 -0
  116. package/dist/index.js.map +1 -1
  117. package/dist/observability/anomaly.d.ts +67 -0
  118. package/dist/observability/anomaly.d.ts.map +1 -0
  119. package/dist/observability/anomaly.js +141 -0
  120. package/dist/observability/anomaly.js.map +1 -0
  121. package/dist/observability/cost-predictor.d.ts +49 -0
  122. package/dist/observability/cost-predictor.d.ts.map +1 -0
  123. package/dist/observability/cost-predictor.js +145 -0
  124. package/dist/observability/cost-predictor.js.map +1 -0
  125. package/dist/observability/hot-path.d.ts +49 -0
  126. package/dist/observability/hot-path.d.ts.map +1 -0
  127. package/dist/observability/hot-path.js +125 -0
  128. package/dist/observability/hot-path.js.map +1 -0
  129. package/dist/observability/index.d.ts +10 -0
  130. package/dist/observability/index.d.ts.map +1 -0
  131. package/dist/observability/index.js +10 -0
  132. package/dist/observability/index.js.map +1 -0
  133. package/dist/observability/replay.d.ts +104 -0
  134. package/dist/observability/replay.d.ts.map +1 -0
  135. package/dist/observability/replay.js +239 -0
  136. package/dist/observability/replay.js.map +1 -0
  137. package/dist/registry/built-in-recommendations.d.ts +54 -0
  138. package/dist/registry/built-in-recommendations.d.ts.map +1 -0
  139. package/dist/registry/built-in-recommendations.js +65 -0
  140. package/dist/registry/built-in-recommendations.js.map +1 -0
  141. package/dist/registry/events.d.ts +26 -0
  142. package/dist/registry/events.d.ts.map +1 -0
  143. package/dist/registry/events.js +22 -0
  144. package/dist/registry/events.js.map +1 -0
  145. package/dist/registry/index.d.ts +159 -0
  146. package/dist/registry/index.d.ts.map +1 -0
  147. package/dist/registry/index.js +12 -0
  148. package/dist/registry/index.js.map +1 -0
  149. package/dist/registry/registry.d.ts +87 -0
  150. package/dist/registry/registry.d.ts.map +1 -0
  151. package/dist/registry/registry.js +294 -0
  152. package/dist/registry/registry.js.map +1 -0
  153. package/dist/registry/snapshot.d.ts +42 -0
  154. package/dist/registry/snapshot.d.ts.map +1 -0
  155. package/dist/registry/snapshot.js +71 -0
  156. package/dist/registry/snapshot.js.map +1 -0
  157. package/dist/registry/typegen.d.ts +48 -0
  158. package/dist/registry/typegen.d.ts.map +1 -0
  159. package/dist/registry/typegen.js +200 -0
  160. package/dist/registry/typegen.js.map +1 -0
  161. package/dist/registry/validator.d.ts +23 -0
  162. package/dist/registry/validator.d.ts.map +1 -0
  163. package/dist/registry/validator.js +50 -0
  164. package/dist/registry/validator.js.map +1 -0
  165. package/dist/reliability/breaker.d.ts +57 -0
  166. package/dist/reliability/breaker.d.ts.map +1 -0
  167. package/dist/reliability/breaker.js +130 -0
  168. package/dist/reliability/breaker.js.map +1 -0
  169. package/dist/reliability/errors.d.ts +78 -0
  170. package/dist/reliability/errors.d.ts.map +1 -0
  171. package/dist/reliability/errors.js +160 -0
  172. package/dist/reliability/errors.js.map +1 -0
  173. package/dist/reliability/gateway.d.ts +88 -0
  174. package/dist/reliability/gateway.d.ts.map +1 -0
  175. package/dist/reliability/gateway.js +180 -0
  176. package/dist/reliability/gateway.js.map +1 -0
  177. package/dist/reliability/index.d.ts +20 -0
  178. package/dist/reliability/index.d.ts.map +1 -0
  179. package/dist/reliability/index.js +16 -0
  180. package/dist/reliability/index.js.map +1 -0
  181. package/dist/reliability/profile.d.ts +49 -0
  182. package/dist/reliability/profile.d.ts.map +1 -0
  183. package/dist/reliability/profile.js +58 -0
  184. package/dist/reliability/profile.js.map +1 -0
  185. package/dist/reliability/retry.d.ts +39 -0
  186. package/dist/reliability/retry.d.ts.map +1 -0
  187. package/dist/reliability/retry.js +51 -0
  188. package/dist/reliability/retry.js.map +1 -0
  189. package/dist/reliability/timeout.d.ts +34 -0
  190. package/dist/reliability/timeout.d.ts.map +1 -0
  191. package/dist/reliability/timeout.js +53 -0
  192. package/dist/reliability/timeout.js.map +1 -0
  193. package/dist/runtime/executor.d.ts.map +1 -1
  194. package/dist/runtime/executor.js +122 -14
  195. package/dist/runtime/executor.js.map +1 -1
  196. package/dist/runtime/findtool/embed.d.ts +28 -0
  197. package/dist/runtime/findtool/embed.d.ts.map +1 -0
  198. package/dist/runtime/findtool/embed.js +85 -0
  199. package/dist/runtime/findtool/embed.js.map +1 -0
  200. package/dist/runtime/findtool/index.d.ts +52 -0
  201. package/dist/runtime/findtool/index.d.ts.map +1 -0
  202. package/dist/runtime/findtool/index.js +78 -0
  203. package/dist/runtime/findtool/index.js.map +1 -0
  204. package/dist/runtime/findtool/vector-index.d.ts +53 -0
  205. package/dist/runtime/findtool/vector-index.d.ts.map +1 -0
  206. package/dist/runtime/findtool/vector-index.js +71 -0
  207. package/dist/runtime/findtool/vector-index.js.map +1 -0
  208. package/dist/runtime/helpers/budget.d.ts +27 -0
  209. package/dist/runtime/helpers/budget.d.ts.map +1 -0
  210. package/dist/runtime/helpers/budget.js +103 -0
  211. package/dist/runtime/helpers/budget.js.map +1 -0
  212. package/dist/runtime/helpers/compact.d.ts +32 -0
  213. package/dist/runtime/helpers/compact.d.ts.map +1 -0
  214. package/dist/runtime/helpers/compact.js +93 -0
  215. package/dist/runtime/helpers/compact.js.map +1 -0
  216. package/dist/runtime/helpers/delta.d.ts +45 -0
  217. package/dist/runtime/helpers/delta.d.ts.map +1 -0
  218. package/dist/runtime/helpers/delta.js +116 -0
  219. package/dist/runtime/helpers/delta.js.map +1 -0
  220. package/dist/runtime/helpers/index.d.ts +16 -0
  221. package/dist/runtime/helpers/index.d.ts.map +1 -0
  222. package/dist/runtime/helpers/index.js +13 -0
  223. package/dist/runtime/helpers/index.js.map +1 -0
  224. package/dist/runtime/helpers/summarize.d.ts +24 -0
  225. package/dist/runtime/helpers/summarize.d.ts.map +1 -0
  226. package/dist/runtime/helpers/summarize.js +124 -0
  227. package/dist/runtime/helpers/summarize.js.map +1 -0
  228. package/dist/runtime/helpers/worker-preload.d.ts +25 -0
  229. package/dist/runtime/helpers/worker-preload.d.ts.map +1 -0
  230. package/dist/runtime/helpers/worker-preload.js +223 -0
  231. package/dist/runtime/helpers/worker-preload.js.map +1 -0
  232. package/dist/runtime/index.d.ts +1 -0
  233. package/dist/runtime/index.d.ts.map +1 -1
  234. package/dist/runtime/index.js +1 -0
  235. package/dist/runtime/index.js.map +1 -1
  236. package/dist/runtime/pool/index.d.ts +11 -0
  237. package/dist/runtime/pool/index.d.ts.map +1 -0
  238. package/dist/runtime/pool/index.js +8 -0
  239. package/dist/runtime/pool/index.js.map +1 -0
  240. package/dist/runtime/pool/recycle.d.ts +44 -0
  241. package/dist/runtime/pool/recycle.d.ts.map +1 -0
  242. package/dist/runtime/pool/recycle.js +50 -0
  243. package/dist/runtime/pool/recycle.js.map +1 -0
  244. package/dist/runtime/pool/worker-pool.d.ts +77 -0
  245. package/dist/runtime/pool/worker-pool.d.ts.map +1 -0
  246. package/dist/runtime/pool/worker-pool.js +216 -0
  247. package/dist/runtime/pool/worker-pool.js.map +1 -0
  248. package/dist/runtime/pool/worker.d.ts +80 -0
  249. package/dist/runtime/pool/worker.d.ts.map +1 -0
  250. package/dist/runtime/pool/worker.js +324 -0
  251. package/dist/runtime/pool/worker.js.map +1 -0
  252. package/dist/server/mcp-server.d.ts +3 -0
  253. package/dist/server/mcp-server.d.ts.map +1 -1
  254. package/dist/server/mcp-server.js +457 -3
  255. package/dist/server/mcp-server.js.map +1 -1
  256. package/dist/server/passthrough-registrar.d.ts +123 -0
  257. package/dist/server/passthrough-registrar.d.ts.map +1 -0
  258. package/dist/server/passthrough-registrar.js +199 -0
  259. package/dist/server/passthrough-registrar.js.map +1 -0
  260. package/dist/skills/skills-engine.d.ts +9 -1
  261. package/dist/skills/skills-engine.d.ts.map +1 -1
  262. package/dist/skills/skills-engine.js +20 -3
  263. package/dist/skills/skills-engine.js.map +1 -1
  264. package/dist/utils/index.d.ts +1 -0
  265. package/dist/utils/index.d.ts.map +1 -1
  266. package/dist/utils/index.js +1 -0
  267. package/dist/utils/index.js.map +1 -1
  268. package/dist/utils/tokenize.d.ts +55 -0
  269. package/dist/utils/tokenize.d.ts.map +1 -0
  270. package/dist/utils/tokenize.js +205 -0
  271. package/dist/utils/tokenize.js.map +1 -0
  272. package/dist/version.d.ts +3 -3
  273. package/dist/version.d.ts.map +1 -1
  274. package/dist/version.js +3 -3
  275. package/dist/version.js.map +1 -1
  276. package/package.json +13 -3
@@ -0,0 +1,209 @@
1
+ /**
2
+ * CacheLayer — three-tier cache composition (memory LRU + disk CBOR + delta).
3
+ *
4
+ * Call flow:
5
+ * get(server, tool, args)
6
+ * → memory LRU hit? → return CacheHit (source: 'memory')
7
+ * → disk hit? → promote to memory, return CacheHit (source: 'disk')
8
+ * → miss → return null (caller must fetch from backend)
9
+ *
10
+ * Stale-while-revalidate (SWR):
11
+ * All staleness decisions are made here, not in DiskCache, so that
12
+ * vi.useFakeTimers() in tests correctly affects TTL checks at all tiers.
13
+ *
14
+ * Bridge wiring order (per spec):
15
+ * cache check → cache miss → reliability gateway (Agent C) → backend
16
+ *
17
+ * @module cache/cache
18
+ */
19
+ import { MemoryLru } from './lru.js';
20
+ import { DiskCache } from './disk.js';
21
+ import { buildCacheKey, cacheKeyToString } from './key.js';
22
+ import { resolveTtl, isCacheable } from './policy.js';
23
+ import { computeDelta } from './delta.js';
24
+ import { logger } from '../utils/index.js';
25
+ export class CacheLayer {
26
+ lru;
27
+ disk;
28
+ registry;
29
+ options;
30
+ unsubscribe = null;
31
+ diskMisses = 0;
32
+ ttlMap = new Map();
33
+ /** Keys currently being background-revalidated; prevents SWR thundering herd. */
34
+ revalidating = new Set();
35
+ constructor(options) {
36
+ this.options = {
37
+ diskDir: `${process.env['HOME'] ?? '/tmp'}/.mcp-conductor/cache`,
38
+ maxMemoryBytes: 100 * 1024 * 1024,
39
+ maxDiskBytes: 2 * 1024 * 1024 * 1024,
40
+ staleWhileRevalidate: true,
41
+ policies: {},
42
+ ...options,
43
+ };
44
+ this.registry = options.registry;
45
+ this.lru = new MemoryLru({ maxMemoryBytes: this.options.maxMemoryBytes });
46
+ this.disk = new DiskCache({
47
+ diskDir: this.options.diskDir,
48
+ maxDiskBytes: this.options.maxDiskBytes,
49
+ });
50
+ const sub = this.registry.watch((event) => {
51
+ if (event.type === 'tool-updated') {
52
+ const prefix = `${event.server}:${event.tool}:`;
53
+ this.lru.invalidateByPrefix(prefix);
54
+ this.disk.invalidateByPrefix(prefix).catch((err) => logger.warn('CacheLayer: disk invalidation error', { error: String(err) }));
55
+ logger.debug('CacheLayer: invalidated on tool-updated', {
56
+ server: event.server,
57
+ tool: event.tool,
58
+ });
59
+ }
60
+ });
61
+ this.unsubscribe = sub.unsubscribe;
62
+ }
63
+ async get(server, tool, args) {
64
+ const cacheKey = buildCacheKey(server, tool, args);
65
+ const keyStr = cacheKeyToString(cacheKey);
66
+ const now = Date.now();
67
+ // 1. Memory LRU — MemoryLru.get() enforces TTL via manual storedAt check
68
+ const memHit = this.lru.get(keyStr);
69
+ if (memHit) {
70
+ const ttlMs = this.ttlMap.get(keyStr) ?? 0;
71
+ const isStale = ttlMs > 0 && now - memHit.storedAt > ttlMs;
72
+ if (!isStale) {
73
+ return { ...memHit, staleness: now - memHit.storedAt };
74
+ }
75
+ if (this.options.staleWhileRevalidate) {
76
+ // Suppress duplicate SWR triggers: if already revalidating, return stale without the flag
77
+ const needsRevalidation = !this.revalidating.has(keyStr);
78
+ return { ...memHit, staleness: now - memHit.storedAt, needsRevalidation };
79
+ }
80
+ this.lru.delete(keyStr);
81
+ // fall through to disk
82
+ }
83
+ // 2. Disk — DiskCache.get() does NOT enforce TTL; we decide staleness here
84
+ const diskHit = await this.disk.get(cacheKey.argsHash);
85
+ if (diskHit) {
86
+ const entryTtl = diskHit.ttlMs > 0 ? diskHit.ttlMs : (this.ttlMap.get(keyStr) ?? 0);
87
+ const staleness = now - diskHit.storedAt;
88
+ const isStale = entryTtl > 0 && staleness > entryTtl;
89
+ if (!isStale) {
90
+ const remaining = entryTtl > 0 ? Math.max(1, entryTtl - staleness) : 0;
91
+ this.lru.set(keyStr, diskHit.value, remaining);
92
+ this.ttlMap.set(keyStr, entryTtl);
93
+ return { value: diskHit.value, storedAt: diskHit.storedAt, source: 'disk', staleness };
94
+ }
95
+ if (this.options.staleWhileRevalidate) {
96
+ const remaining = Math.max(1, entryTtl);
97
+ this.lru.set(keyStr, diskHit.value, remaining);
98
+ this.ttlMap.set(keyStr, entryTtl);
99
+ // Suppress duplicate SWR triggers: if already revalidating, return stale without the flag
100
+ const needsRevalidation = !this.revalidating.has(keyStr);
101
+ return {
102
+ value: diskHit.value,
103
+ storedAt: diskHit.storedAt,
104
+ source: 'disk',
105
+ staleness,
106
+ needsRevalidation,
107
+ };
108
+ }
109
+ await this.disk.delete(cacheKey.argsHash);
110
+ }
111
+ this.diskMisses++;
112
+ return null;
113
+ }
114
+ async set(server, tool, args, result, options) {
115
+ const toolDef = this.registry.getTool(server, tool);
116
+ const ttlMs = options?.ttl ?? resolveTtl(toolDef, this.options.policies);
117
+ if (ttlMs === 0)
118
+ return;
119
+ const cacheKey = buildCacheKey(server, tool, args);
120
+ const keyStr = cacheKeyToString(cacheKey);
121
+ this.lru.set(keyStr, result, ttlMs);
122
+ this.ttlMap.set(keyStr, ttlMs);
123
+ await this.disk.set(cacheKey.argsHash, {
124
+ value: result,
125
+ storedAt: Date.now(),
126
+ ttlMs,
127
+ server,
128
+ tool,
129
+ });
130
+ }
131
+ async invalidate(server, pattern) {
132
+ const prefix = pattern ? `${server}:${pattern}` : `${server}:`;
133
+ const memCount = this.lru.invalidateByPrefix(prefix);
134
+ const diskCount = await this.disk.invalidateByPrefix(prefix);
135
+ return memCount + diskCount;
136
+ }
137
+ async delta(server, tool, args, current) {
138
+ const hit = await this.get(server, tool, args);
139
+ if (!hit)
140
+ return { unchanged: false, full: current };
141
+ return computeDelta(hit.value, current);
142
+ }
143
+ stats() {
144
+ const lruCounters = this.lru.getCounters();
145
+ const diskCounters = this.disk.getCounters();
146
+ return {
147
+ memoryHits: lruCounters.hits,
148
+ diskHits: diskCounters.hits,
149
+ misses: this.diskMisses,
150
+ evictions: lruCounters.evictions,
151
+ bytesInMemory: this.lru.bytesUsed,
152
+ bytesOnDisk: this.disk.approximateBytesOnDisk,
153
+ };
154
+ }
155
+ async clear() {
156
+ this.lru.clear();
157
+ this.lru.resetCounters();
158
+ this.ttlMap.clear();
159
+ this.diskMisses = 0;
160
+ await this.disk.clear();
161
+ }
162
+ wouldCache(server, tool) {
163
+ const toolDef = this.registry.getTool(server, tool);
164
+ return isCacheable(toolDef, this.options.policies);
165
+ }
166
+ /**
167
+ * Deduplicated background revalidation helper for stale-while-revalidate.
168
+ *
169
+ * Marks the cache key as being revalidated so subsequent concurrent `get()`
170
+ * calls that would also see `needsRevalidation: true` get `false` instead,
171
+ * preventing a thundering herd of parallel refreshes.
172
+ *
173
+ * The key is removed from the revalidating set on completion (success or
174
+ * failure), allowing a future `get()` to schedule a fresh revalidation if
175
+ * the entry is still stale at that point.
176
+ *
177
+ * @param server MCP server name.
178
+ * @param tool Tool name.
179
+ * @param args Original call arguments (used to build the cache key).
180
+ * @param fetchFn Async function that calls the backend and returns the fresh result.
181
+ * @returns A promise that resolves when the background refresh completes.
182
+ * Callers should `.catch()` the returned promise to handle errors.
183
+ */
184
+ refreshInBackground(server, tool, args, fetchFn) {
185
+ const cacheKey = buildCacheKey(server, tool, args);
186
+ const keyStr = cacheKeyToString(cacheKey);
187
+ // Already in-flight — skip
188
+ if (this.revalidating.has(keyStr)) {
189
+ return Promise.resolve();
190
+ }
191
+ this.revalidating.add(keyStr);
192
+ return (async () => {
193
+ try {
194
+ const freshResult = await fetchFn();
195
+ await this.set(server, tool, args, freshResult);
196
+ }
197
+ finally {
198
+ this.revalidating.delete(keyStr);
199
+ }
200
+ })();
201
+ }
202
+ destroy() {
203
+ if (this.unsubscribe) {
204
+ this.unsubscribe();
205
+ this.unsubscribe = null;
206
+ }
207
+ }
208
+ }
209
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Delta encoding for repeated tool-call results.
3
+ *
4
+ * When a caller wants to know "what changed since the last call", we compute
5
+ * a structural diff and return only the delta. This is significantly smaller
6
+ * than the full result for incremental work (e.g. polling a list of issues).
7
+ *
8
+ * Strategy:
9
+ * - Arrays: compare items by identity (JSON equality). Report added/removed.
10
+ * Items that appear in both but at different positions count as unchanged
11
+ * (we do not track moves for simplicity).
12
+ * - Objects at the top level: compare property values; modified = { before, after }.
13
+ * - Scalars or mixed types: return full result (no useful delta possible).
14
+ * - When the delta payload is larger than the full result, return full result.
15
+ *
16
+ * @module cache/delta
17
+ */
18
+ import type { DeltaResult } from './index.js';
19
+ /**
20
+ * Compute the delta between a previous result and the current result.
21
+ *
22
+ * Always returns a DeltaResult. When results are identical, returns
23
+ * `{ unchanged: true }`. When results differ but the full payload is
24
+ * smaller than the delta, `full` is set and the delta fields are absent.
25
+ */
26
+ export declare function computeDelta(previous: unknown, current: unknown): DeltaResult;
27
+ /**
28
+ * Deep equality via JSON serialisation. Fast enough for typical MCP result
29
+ * sizes; avoids pulling in a heavy comparison library.
30
+ */
31
+ export declare function deepEqual(a: unknown, b: unknown): boolean;
32
+ //# sourceMappingURL=delta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta.d.ts","sourceRoot":"","sources":["../../src/cache/delta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,WAAW,CAqB7E;AAiFD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAOzD"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Delta encoding for repeated tool-call results.
3
+ *
4
+ * When a caller wants to know "what changed since the last call", we compute
5
+ * a structural diff and return only the delta. This is significantly smaller
6
+ * than the full result for incremental work (e.g. polling a list of issues).
7
+ *
8
+ * Strategy:
9
+ * - Arrays: compare items by identity (JSON equality). Report added/removed.
10
+ * Items that appear in both but at different positions count as unchanged
11
+ * (we do not track moves for simplicity).
12
+ * - Objects at the top level: compare property values; modified = { before, after }.
13
+ * - Scalars or mixed types: return full result (no useful delta possible).
14
+ * - When the delta payload is larger than the full result, return full result.
15
+ *
16
+ * @module cache/delta
17
+ */
18
+ /**
19
+ * Compute the delta between a previous result and the current result.
20
+ *
21
+ * Always returns a DeltaResult. When results are identical, returns
22
+ * `{ unchanged: true }`. When results differ but the full payload is
23
+ * smaller than the delta, `full` is set and the delta fields are absent.
24
+ */
25
+ export function computeDelta(previous, current) {
26
+ // Identical check (fast path)
27
+ if (deepEqual(previous, current)) {
28
+ return { unchanged: true };
29
+ }
30
+ // Array diff
31
+ if (Array.isArray(previous) && Array.isArray(current)) {
32
+ return arrayDelta(previous, current);
33
+ }
34
+ // Object diff
35
+ if (isPlainObject(previous) && isPlainObject(current)) {
36
+ return objectDelta(previous, current);
37
+ }
38
+ // Scalar or mixed-type change — return full
39
+ return { unchanged: false, full: current };
40
+ }
41
+ // ── Array diff ────────────────────────────────────────────────────────────────
42
+ function arrayDelta(prev, curr) {
43
+ const added = [];
44
+ const removed = [];
45
+ // Items in curr but not in prev
46
+ for (const item of curr) {
47
+ if (!prev.some((p) => deepEqual(p, item))) {
48
+ added.push(item);
49
+ }
50
+ }
51
+ // Items in prev but not in curr
52
+ for (const item of prev) {
53
+ if (!curr.some((c) => deepEqual(c, item))) {
54
+ removed.push(item);
55
+ }
56
+ }
57
+ const delta = {
58
+ unchanged: false,
59
+ added: added.length > 0 ? added : undefined,
60
+ removed: removed.length > 0 ? removed : undefined,
61
+ };
62
+ // Only prefer full when the delta is genuinely larger than the full result
63
+ if (shouldReturnFull(delta, curr)) {
64
+ return { unchanged: false, full: curr };
65
+ }
66
+ return delta;
67
+ }
68
+ // ── Object diff ───────────────────────────────────────────────────────────────
69
+ function objectDelta(prev, curr) {
70
+ const added = [];
71
+ const removed = [];
72
+ const modified = [];
73
+ const allKeys = new Set([...Object.keys(prev), ...Object.keys(curr)]);
74
+ for (const key of allKeys) {
75
+ const inPrev = key in prev;
76
+ const inCurr = key in curr;
77
+ if (!inPrev && inCurr) {
78
+ added.push({ [key]: curr[key] });
79
+ }
80
+ else if (inPrev && !inCurr) {
81
+ removed.push({ [key]: prev[key] });
82
+ }
83
+ else if (!deepEqual(prev[key], curr[key])) {
84
+ modified.push({ before: { [key]: prev[key] }, after: { [key]: curr[key] } });
85
+ }
86
+ }
87
+ const delta = {
88
+ unchanged: false,
89
+ added: added.length > 0 ? added : undefined,
90
+ removed: removed.length > 0 ? removed : undefined,
91
+ modified: modified.length > 0 ? modified : undefined,
92
+ };
93
+ if (shouldReturnFull(delta, curr)) {
94
+ return { unchanged: false, full: curr };
95
+ }
96
+ return delta;
97
+ }
98
+ // ── Utilities ─────────────────────────────────────────────────────────────────
99
+ function isPlainObject(v) {
100
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
101
+ }
102
+ /**
103
+ * Deep equality via JSON serialisation. Fast enough for typical MCP result
104
+ * sizes; avoids pulling in a heavy comparison library.
105
+ */
106
+ export function deepEqual(a, b) {
107
+ if (a === b)
108
+ return true;
109
+ try {
110
+ return JSON.stringify(a) === JSON.stringify(b);
111
+ }
112
+ catch {
113
+ return false;
114
+ }
115
+ }
116
+ /**
117
+ * Returns true when the full current value is strictly smaller (in serialised
118
+ * bytes) than the delta payload. We use a strict greater-than comparison so
119
+ * that delta is preferred when sizes are equal.
120
+ */
121
+ function shouldReturnFull(delta, current) {
122
+ try {
123
+ const deltaSize = Buffer.byteLength(JSON.stringify(delta), 'utf8');
124
+ const fullSize = Buffer.byteLength(JSON.stringify(current), 'utf8');
125
+ return deltaSize > fullSize;
126
+ }
127
+ catch {
128
+ return true; // If we can't measure, default to full
129
+ }
130
+ }
131
+ //# sourceMappingURL=delta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta.js","sourceRoot":"","sources":["../../src/cache/delta.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Persistent disk cache tier using CBOR encoding (cbor-x).
3
+ *
4
+ * Layout on disk:
5
+ * <diskDir>/<sha256-prefix-2>/<full-argsHash>.cbor
6
+ *
7
+ * TTL enforcement is the responsibility of the caller (CacheLayer). DiskCache
8
+ * returns entries regardless of TTL so that stale-while-revalidate can be
9
+ * handled at the CacheLayer level.
10
+ *
11
+ * Parallel writes are safe: each key maps to a unique path; writes are
12
+ * atomic via a temp-file rename pattern.
13
+ *
14
+ * @module cache/disk
15
+ */
16
+ import type { CacheHit } from './index.js';
17
+ export interface DiskEntry {
18
+ value: unknown;
19
+ storedAt: number;
20
+ ttlMs: number;
21
+ server: string;
22
+ tool: string;
23
+ }
24
+ /** Extended CacheHit that includes the stored TTL so CacheLayer can apply its own expiry policy. */
25
+ export interface DiskCacheHit extends CacheHit {
26
+ ttlMs: number;
27
+ }
28
+ export interface DiskCacheOptions {
29
+ diskDir: string;
30
+ maxDiskBytes?: number;
31
+ }
32
+ export declare class DiskCache {
33
+ private diskDir;
34
+ private maxDiskBytes;
35
+ private hits;
36
+ private misses;
37
+ private bytesOnDisk;
38
+ private ready;
39
+ constructor(options: DiskCacheOptions);
40
+ private ensureReady;
41
+ private entryPath;
42
+ /**
43
+ * Read an entry from disk.
44
+ * Returns null only on genuine miss or read errors — TTL is NOT enforced here.
45
+ * CacheLayer is responsible for staleness decisions (enabling SWR to work).
46
+ */
47
+ get(argsHash: string): Promise<DiskCacheHit | null>;
48
+ /**
49
+ * Write an entry to disk atomically (write to .tmp then rename).
50
+ * Triggers rotation when over maxDiskBytes.
51
+ */
52
+ set(argsHash: string, entry: DiskEntry): Promise<void>;
53
+ delete(argsHash: string): Promise<boolean>;
54
+ invalidateByPrefix(serverToolPrefix: string): Promise<number>;
55
+ invalidateServer(server: string): Promise<number>;
56
+ clear(): Promise<void>;
57
+ get approximateBytesOnDisk(): number;
58
+ getCounters(): {
59
+ hits: number;
60
+ misses: number;
61
+ };
62
+ private scanAndDelete;
63
+ private rotate;
64
+ }
65
+ //# sourceMappingURL=disk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disk.d.ts","sourceRoot":"","sources":["../../src/cache/disk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oGAAoG;AACpG,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAID,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,KAAK,CAAgB;gBAEjB,OAAO,EAAE,gBAAgB;YAMvB,WAAW;IAIzB,OAAO,CAAC,SAAS;IAKjB;;;;OAIG;IACG,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAuBzD;;;OAGG;IACG,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBtD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAa1C,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAsB7D,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiBjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,IAAI,sBAAsB,IAAI,MAAM,CAA6B;IACjE,WAAW,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;YAEjC,aAAa;YA2Bb,MAAM;CAqCrB"}