agentfootprint 12.0.1 → 12.2.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 (296) hide show
  1. package/AGENTS.md +1 -1
  2. package/CAPABILITIES.md +3 -0
  3. package/ai-instructions/claude-code/SKILL.md +1 -1
  4. package/dist/adapters/mcp/agentcoreRuntime/invoke.js +113 -7
  5. package/dist/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  6. package/dist/adapters/mcp/agentcoreRuntime/session.js +21 -21
  7. package/dist/adapters/mcp/agentcoreRuntime/session.js.map +1 -1
  8. package/dist/adapters/mcp/agentcoreRuntime/transport.js +79 -5
  9. package/dist/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  10. package/dist/core/Agent.js +6 -0
  11. package/dist/core/Agent.js.map +1 -1
  12. package/dist/core/agent/stages/toolCalls.js +4 -0
  13. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  14. package/dist/core/slots/buildToolsSlot.js +8 -0
  15. package/dist/core/slots/buildToolsSlot.js.map +1 -1
  16. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.d.ts +23 -4
  17. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js +112 -6
  18. package/dist/esm/adapters/mcp/agentcoreRuntime/invoke.js.map +1 -1
  19. package/dist/esm/adapters/mcp/agentcoreRuntime/session.d.ts +20 -6
  20. package/dist/esm/adapters/mcp/agentcoreRuntime/session.js +21 -21
  21. package/dist/esm/adapters/mcp/agentcoreRuntime/session.js.map +1 -1
  22. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js +81 -7
  23. package/dist/esm/adapters/mcp/agentcoreRuntime/transport.js.map +1 -1
  24. package/dist/esm/core/Agent.js +6 -0
  25. package/dist/esm/core/Agent.js.map +1 -1
  26. package/dist/esm/core/agent/stages/toolCalls.js +4 -0
  27. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  28. package/dist/esm/core/slots/buildToolsSlot.d.ts +12 -0
  29. package/dist/esm/core/slots/buildToolsSlot.js +8 -0
  30. package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
  31. package/dist/esm/events/payloads.d.ts +41 -0
  32. package/dist/esm/events/registry.d.ts +3 -1
  33. package/dist/esm/events/registry.js +2 -0
  34. package/dist/esm/events/registry.js.map +1 -1
  35. package/dist/esm/identity/types.d.ts +7 -3
  36. package/dist/esm/identity/types.js.map +1 -1
  37. package/dist/esm/index.d.ts +1 -1
  38. package/dist/esm/index.js +4 -1
  39. package/dist/esm/index.js.map +1 -1
  40. package/dist/esm/lib/boundedJson.d.ts +14 -7
  41. package/dist/esm/lib/boundedJson.js +14 -7
  42. package/dist/esm/lib/boundedJson.js.map +1 -1
  43. package/dist/esm/mcp/callChecks.d.ts +160 -0
  44. package/dist/esm/mcp/callChecks.js +237 -0
  45. package/dist/esm/mcp/callChecks.js.map +1 -0
  46. package/dist/esm/mcp/callLifetime.js +5 -2
  47. package/dist/esm/mcp/callLifetime.js.map +1 -1
  48. package/dist/esm/mcp/clientPort.d.ts +78 -0
  49. package/dist/esm/mcp/clientPort.js +33 -0
  50. package/dist/esm/mcp/clientPort.js.map +1 -0
  51. package/dist/esm/mcp/gatewayTransport.js +13 -3
  52. package/dist/esm/mcp/gatewayTransport.js.map +1 -1
  53. package/dist/esm/mcp/index.d.ts +11 -1
  54. package/dist/esm/mcp/index.js +15 -0
  55. package/dist/esm/mcp/index.js.map +1 -1
  56. package/dist/esm/mcp/listingGenerations.d.ts +54 -0
  57. package/dist/esm/mcp/listingGenerations.js +75 -0
  58. package/dist/esm/mcp/listingGenerations.js.map +1 -0
  59. package/dist/esm/mcp/mcpClient.d.ts +18 -1
  60. package/dist/esm/mcp/mcpClient.js +302 -57
  61. package/dist/esm/mcp/mcpClient.js.map +1 -1
  62. package/dist/esm/mcp/mockMcpClient.js +13 -0
  63. package/dist/esm/mcp/mockMcpClient.js.map +1 -1
  64. package/dist/esm/mcp/pool/boundTool.d.ts +58 -0
  65. package/dist/esm/mcp/pool/boundTool.js +218 -0
  66. package/dist/esm/mcp/pool/boundTool.js.map +1 -0
  67. package/dist/esm/mcp/pool/clientSet.d.ts +73 -0
  68. package/dist/esm/mcp/pool/clientSet.js +152 -0
  69. package/dist/esm/mcp/pool/clientSet.js.map +1 -0
  70. package/dist/esm/mcp/pool/definitions.d.ts +103 -0
  71. package/dist/esm/mcp/pool/definitions.js +168 -0
  72. package/dist/esm/mcp/pool/definitions.js.map +1 -0
  73. package/dist/esm/mcp/pool/errors.d.ts +76 -0
  74. package/dist/esm/mcp/pool/errors.js +91 -0
  75. package/dist/esm/mcp/pool/errors.js.map +1 -0
  76. package/dist/esm/mcp/pool/identityKey.d.ts +57 -0
  77. package/dist/esm/mcp/pool/identityKey.js +94 -0
  78. package/dist/esm/mcp/pool/identityKey.js.map +1 -0
  79. package/dist/esm/mcp/pool/lease.d.ts +36 -0
  80. package/dist/esm/mcp/pool/lease.js +51 -0
  81. package/dist/esm/mcp/pool/lease.js.map +1 -0
  82. package/dist/esm/mcp/pool/listTools.d.ts +33 -0
  83. package/dist/esm/mcp/pool/listTools.js +146 -0
  84. package/dist/esm/mcp/pool/listTools.js.map +1 -0
  85. package/dist/esm/mcp/pool/mcpClientPool.d.ts +121 -0
  86. package/dist/esm/mcp/pool/mcpClientPool.js +151 -0
  87. package/dist/esm/mcp/pool/mcpClientPool.js.map +1 -0
  88. package/dist/esm/mcp/pool/options.d.ts +183 -0
  89. package/dist/esm/mcp/pool/options.js +119 -0
  90. package/dist/esm/mcp/pool/options.js.map +1 -0
  91. package/dist/esm/mcp/pool/plan.d.ts +77 -0
  92. package/dist/esm/mcp/pool/plan.js +134 -0
  93. package/dist/esm/mcp/pool/plan.js.map +1 -0
  94. package/dist/esm/mcp/pool/pool.d.ts +307 -0
  95. package/dist/esm/mcp/pool/pool.js +1071 -0
  96. package/dist/esm/mcp/pool/pool.js.map +1 -0
  97. package/dist/esm/mcp/pool/pooledClient.d.ts +93 -0
  98. package/dist/esm/mcp/pool/pooledClient.js +90 -0
  99. package/dist/esm/mcp/pool/pooledClient.js.map +1 -0
  100. package/dist/esm/mcp/pool/record.d.ts +80 -0
  101. package/dist/esm/mcp/pool/record.js +75 -0
  102. package/dist/esm/mcp/pool/record.js.map +1 -0
  103. package/dist/esm/mcp/pool/sessionEnded.d.ts +24 -0
  104. package/dist/esm/mcp/pool/sessionEnded.js +31 -0
  105. package/dist/esm/mcp/pool/sessionEnded.js.map +1 -0
  106. package/dist/esm/mcp/pool/work.d.ts +116 -0
  107. package/dist/esm/mcp/pool/work.js +213 -0
  108. package/dist/esm/mcp/pool/work.js.map +1 -0
  109. package/dist/esm/mcp/requestGuard.d.ts +70 -0
  110. package/dist/esm/mcp/requestGuard.js +98 -0
  111. package/dist/esm/mcp/requestGuard.js.map +1 -0
  112. package/dist/esm/mcp/requestLedger.d.ts +35 -1
  113. package/dist/esm/mcp/requestLedger.js +76 -3
  114. package/dist/esm/mcp/requestLedger.js.map +1 -1
  115. package/dist/esm/mcp/seriesEvidence.d.ts +10 -6
  116. package/dist/esm/mcp/seriesEvidence.js +16 -7
  117. package/dist/esm/mcp/seriesEvidence.js.map +1 -1
  118. package/dist/esm/mcp/terminate.d.ts +94 -0
  119. package/dist/esm/mcp/terminate.js +184 -0
  120. package/dist/esm/mcp/terminate.js.map +1 -0
  121. package/dist/esm/mcp/throttleRetry.js +71 -7
  122. package/dist/esm/mcp/throttleRetry.js.map +1 -1
  123. package/dist/esm/mcp/toolList.d.ts +90 -0
  124. package/dist/esm/mcp/toolList.js +123 -0
  125. package/dist/esm/mcp/toolList.js.map +1 -0
  126. package/dist/esm/mcp/types.d.ts +197 -3
  127. package/dist/esm/redaction/knownStrings.js +34 -0
  128. package/dist/esm/redaction/knownStrings.js.map +1 -1
  129. package/dist/esm/tool-providers/index.d.ts +2 -2
  130. package/dist/esm/tool-providers/index.js +15 -1
  131. package/dist/esm/tool-providers/index.js.map +1 -1
  132. package/dist/esm/tools/mcpClientUse.d.ts +59 -0
  133. package/dist/esm/tools/mcpClientUse.js +216 -0
  134. package/dist/esm/tools/mcpClientUse.js.map +1 -0
  135. package/dist/esm/tools/toolProvider.d.ts +16 -0
  136. package/dist/esm/tools/toolSessions.d.ts +41 -0
  137. package/dist/esm/tools/toolSessions.js +41 -1
  138. package/dist/esm/tools/toolSessions.js.map +1 -1
  139. package/dist/events/registry.js +2 -0
  140. package/dist/events/registry.js.map +1 -1
  141. package/dist/identity/types.js.map +1 -1
  142. package/dist/index.js +6 -3
  143. package/dist/index.js.map +1 -1
  144. package/dist/lib/boundedJson.js +14 -7
  145. package/dist/lib/boundedJson.js.map +1 -1
  146. package/dist/mcp/callChecks.js +247 -0
  147. package/dist/mcp/callChecks.js.map +1 -0
  148. package/dist/mcp/callLifetime.js +5 -2
  149. package/dist/mcp/callLifetime.js.map +1 -1
  150. package/dist/mcp/clientPort.js +38 -0
  151. package/dist/mcp/clientPort.js.map +1 -0
  152. package/dist/mcp/gatewayTransport.js +13 -3
  153. package/dist/mcp/gatewayTransport.js.map +1 -1
  154. package/dist/mcp/index.js +25 -1
  155. package/dist/mcp/index.js.map +1 -1
  156. package/dist/mcp/listingGenerations.js +80 -0
  157. package/dist/mcp/listingGenerations.js.map +1 -0
  158. package/dist/mcp/mcpClient.js +306 -59
  159. package/dist/mcp/mcpClient.js.map +1 -1
  160. package/dist/mcp/mockMcpClient.js +13 -0
  161. package/dist/mcp/mockMcpClient.js.map +1 -1
  162. package/dist/mcp/pool/boundTool.js +223 -0
  163. package/dist/mcp/pool/boundTool.js.map +1 -0
  164. package/dist/mcp/pool/clientSet.js +157 -0
  165. package/dist/mcp/pool/clientSet.js.map +1 -0
  166. package/dist/mcp/pool/definitions.js +174 -0
  167. package/dist/mcp/pool/definitions.js.map +1 -0
  168. package/dist/mcp/pool/errors.js +96 -0
  169. package/dist/mcp/pool/errors.js.map +1 -0
  170. package/dist/mcp/pool/identityKey.js +99 -0
  171. package/dist/mcp/pool/identityKey.js.map +1 -0
  172. package/dist/mcp/pool/lease.js +55 -0
  173. package/dist/mcp/pool/lease.js.map +1 -0
  174. package/dist/mcp/pool/listTools.js +150 -0
  175. package/dist/mcp/pool/listTools.js.map +1 -0
  176. package/dist/mcp/pool/mcpClientPool.js +155 -0
  177. package/dist/mcp/pool/mcpClientPool.js.map +1 -0
  178. package/dist/mcp/pool/options.js +123 -0
  179. package/dist/mcp/pool/options.js.map +1 -0
  180. package/dist/mcp/pool/plan.js +140 -0
  181. package/dist/mcp/pool/plan.js.map +1 -0
  182. package/dist/mcp/pool/pool.js +1075 -0
  183. package/dist/mcp/pool/pool.js.map +1 -0
  184. package/dist/mcp/pool/pooledClient.js +94 -0
  185. package/dist/mcp/pool/pooledClient.js.map +1 -0
  186. package/dist/mcp/pool/record.js +80 -0
  187. package/dist/mcp/pool/record.js.map +1 -0
  188. package/dist/mcp/pool/sessionEnded.js +35 -0
  189. package/dist/mcp/pool/sessionEnded.js.map +1 -0
  190. package/dist/mcp/pool/work.js +219 -0
  191. package/dist/mcp/pool/work.js.map +1 -0
  192. package/dist/mcp/requestGuard.js +106 -0
  193. package/dist/mcp/requestGuard.js.map +1 -0
  194. package/dist/mcp/requestLedger.js +76 -3
  195. package/dist/mcp/requestLedger.js.map +1 -1
  196. package/dist/mcp/seriesEvidence.js +16 -7
  197. package/dist/mcp/seriesEvidence.js.map +1 -1
  198. package/dist/mcp/terminate.js +193 -0
  199. package/dist/mcp/terminate.js.map +1 -0
  200. package/dist/mcp/throttleRetry.js +71 -7
  201. package/dist/mcp/throttleRetry.js.map +1 -1
  202. package/dist/mcp/toolList.js +128 -0
  203. package/dist/mcp/toolList.js.map +1 -0
  204. package/dist/redaction/knownStrings.js +34 -0
  205. package/dist/redaction/knownStrings.js.map +1 -1
  206. package/dist/tool-providers/index.js +20 -1
  207. package/dist/tool-providers/index.js.map +1 -1
  208. package/dist/tools/mcpClientUse.js +225 -0
  209. package/dist/tools/mcpClientUse.js.map +1 -0
  210. package/dist/tools/toolSessions.js +44 -1
  211. package/dist/tools/toolSessions.js.map +1 -1
  212. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts +23 -4
  213. package/dist/types/adapters/mcp/agentcoreRuntime/invoke.d.ts.map +1 -1
  214. package/dist/types/adapters/mcp/agentcoreRuntime/session.d.ts +20 -6
  215. package/dist/types/adapters/mcp/agentcoreRuntime/session.d.ts.map +1 -1
  216. package/dist/types/adapters/mcp/agentcoreRuntime/transport.d.ts.map +1 -1
  217. package/dist/types/core/Agent.d.ts.map +1 -1
  218. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  219. package/dist/types/core/slots/buildToolsSlot.d.ts +12 -0
  220. package/dist/types/core/slots/buildToolsSlot.d.ts.map +1 -1
  221. package/dist/types/events/payloads.d.ts +41 -0
  222. package/dist/types/events/payloads.d.ts.map +1 -1
  223. package/dist/types/events/registry.d.ts +3 -1
  224. package/dist/types/events/registry.d.ts.map +1 -1
  225. package/dist/types/identity/types.d.ts +7 -3
  226. package/dist/types/identity/types.d.ts.map +1 -1
  227. package/dist/types/index.d.ts +1 -1
  228. package/dist/types/index.d.ts.map +1 -1
  229. package/dist/types/lib/boundedJson.d.ts +14 -7
  230. package/dist/types/lib/boundedJson.d.ts.map +1 -1
  231. package/dist/types/mcp/callChecks.d.ts +161 -0
  232. package/dist/types/mcp/callChecks.d.ts.map +1 -0
  233. package/dist/types/mcp/callLifetime.d.ts.map +1 -1
  234. package/dist/types/mcp/clientPort.d.ts +79 -0
  235. package/dist/types/mcp/clientPort.d.ts.map +1 -0
  236. package/dist/types/mcp/gatewayTransport.d.ts.map +1 -1
  237. package/dist/types/mcp/index.d.ts +11 -1
  238. package/dist/types/mcp/index.d.ts.map +1 -1
  239. package/dist/types/mcp/listingGenerations.d.ts +55 -0
  240. package/dist/types/mcp/listingGenerations.d.ts.map +1 -0
  241. package/dist/types/mcp/mcpClient.d.ts +18 -1
  242. package/dist/types/mcp/mcpClient.d.ts.map +1 -1
  243. package/dist/types/mcp/mockMcpClient.d.ts.map +1 -1
  244. package/dist/types/mcp/pool/boundTool.d.ts +59 -0
  245. package/dist/types/mcp/pool/boundTool.d.ts.map +1 -0
  246. package/dist/types/mcp/pool/clientSet.d.ts +74 -0
  247. package/dist/types/mcp/pool/clientSet.d.ts.map +1 -0
  248. package/dist/types/mcp/pool/definitions.d.ts +104 -0
  249. package/dist/types/mcp/pool/definitions.d.ts.map +1 -0
  250. package/dist/types/mcp/pool/errors.d.ts +77 -0
  251. package/dist/types/mcp/pool/errors.d.ts.map +1 -0
  252. package/dist/types/mcp/pool/identityKey.d.ts +58 -0
  253. package/dist/types/mcp/pool/identityKey.d.ts.map +1 -0
  254. package/dist/types/mcp/pool/lease.d.ts +37 -0
  255. package/dist/types/mcp/pool/lease.d.ts.map +1 -0
  256. package/dist/types/mcp/pool/listTools.d.ts +34 -0
  257. package/dist/types/mcp/pool/listTools.d.ts.map +1 -0
  258. package/dist/types/mcp/pool/mcpClientPool.d.ts +122 -0
  259. package/dist/types/mcp/pool/mcpClientPool.d.ts.map +1 -0
  260. package/dist/types/mcp/pool/options.d.ts +184 -0
  261. package/dist/types/mcp/pool/options.d.ts.map +1 -0
  262. package/dist/types/mcp/pool/plan.d.ts +78 -0
  263. package/dist/types/mcp/pool/plan.d.ts.map +1 -0
  264. package/dist/types/mcp/pool/pool.d.ts +308 -0
  265. package/dist/types/mcp/pool/pool.d.ts.map +1 -0
  266. package/dist/types/mcp/pool/pooledClient.d.ts +94 -0
  267. package/dist/types/mcp/pool/pooledClient.d.ts.map +1 -0
  268. package/dist/types/mcp/pool/record.d.ts +81 -0
  269. package/dist/types/mcp/pool/record.d.ts.map +1 -0
  270. package/dist/types/mcp/pool/sessionEnded.d.ts +25 -0
  271. package/dist/types/mcp/pool/sessionEnded.d.ts.map +1 -0
  272. package/dist/types/mcp/pool/work.d.ts +117 -0
  273. package/dist/types/mcp/pool/work.d.ts.map +1 -0
  274. package/dist/types/mcp/requestGuard.d.ts +71 -0
  275. package/dist/types/mcp/requestGuard.d.ts.map +1 -0
  276. package/dist/types/mcp/requestLedger.d.ts +35 -1
  277. package/dist/types/mcp/requestLedger.d.ts.map +1 -1
  278. package/dist/types/mcp/seriesEvidence.d.ts +10 -6
  279. package/dist/types/mcp/seriesEvidence.d.ts.map +1 -1
  280. package/dist/types/mcp/terminate.d.ts +95 -0
  281. package/dist/types/mcp/terminate.d.ts.map +1 -0
  282. package/dist/types/mcp/throttleRetry.d.ts.map +1 -1
  283. package/dist/types/mcp/toolList.d.ts +91 -0
  284. package/dist/types/mcp/toolList.d.ts.map +1 -0
  285. package/dist/types/mcp/types.d.ts +197 -3
  286. package/dist/types/mcp/types.d.ts.map +1 -1
  287. package/dist/types/redaction/knownStrings.d.ts.map +1 -1
  288. package/dist/types/tool-providers/index.d.ts +2 -2
  289. package/dist/types/tool-providers/index.d.ts.map +1 -1
  290. package/dist/types/tools/mcpClientUse.d.ts +60 -0
  291. package/dist/types/tools/mcpClientUse.d.ts.map +1 -0
  292. package/dist/types/tools/toolProvider.d.ts +16 -0
  293. package/dist/types/tools/toolProvider.d.ts.map +1 -1
  294. package/dist/types/tools/toolSessions.d.ts +41 -0
  295. package/dist/types/tools/toolSessions.d.ts.map +1 -1
  296. package/package.json +3 -3
@@ -0,0 +1,58 @@
1
+ /**
2
+ * boundTool — a tool bound to its conversation, the list it came from and that
3
+ * list's generation, re-checked after every wait and at the send gate.
4
+ *
5
+ * Pattern: the shape every MCP tool takes (`mcpClient.ts` · `mcpToolShape`) +
6
+ * one `execute` that runs the five steps of § 6.3.
7
+ * Role: A bound tool carries its BINDING: the key it was listed for; the
8
+ * context it was listed in (per client, the configuration; shared, the
9
+ * entry's context); the list it came from (per client, the client
10
+ * incarnation; shared, the entry); and that list's generation. Its
11
+ * `execute`:
12
+ *
13
+ * 1. checks that the calling run's caller identity encodes to its key —
14
+ * otherwise `identity-mismatch`, nothing sent;
15
+ * 2. checks its binding is current — otherwise `stale-tools`, nothing sent;
16
+ * 3. is admitted against `maxOperations` and takes a lease on its key's
17
+ * client, opening one from a plan resolved now when the key has none. A
18
+ * client whose plan's context differs from the binding's refuses with
19
+ * `binding-changed` (the client stays for the next list). A client that is
20
+ * not the incarnation the tool was listed from is checked against its OWN
21
+ * fresh list — the call goes on only if that list holds the same
22
+ * definition, compared as canonical JSON; otherwise `stale-tools`. Under
23
+ * the app's sharing contract, a replacement whose context matches uses the
24
+ * shared entry as it stands;
25
+ * 4. after every wait, checks step 2 again — and asks the app's `share`
26
+ * again, so a changed authorization name refuses it (`binding-changed`);
27
+ * 5. sends through the send gate (`mcp/requestGuard.ts`), asked at every
28
+ * boundary the request crosses — before every attempt, after a credential
29
+ * arrives, after signing — classifies the outcome (a server's 404 for the
30
+ * session is `SessionExpiredError`; a handle this process lost is
31
+ * `LocalSessionHandleLostError`; neither is repeated), files its use, and
32
+ * releases its lease once the request's own work has settled.
33
+ *
34
+ * Never another conversation's connection: the binding is to the KEY, and a
35
+ * client of any other key never serves it.
36
+ */
37
+ import type { Tool } from '../../tools/tools.js';
38
+ import type { Definition } from './definitions.js';
39
+ import { type PoolKey } from './identityKey.js';
40
+ import type { Pool } from './pool.js';
41
+ import { UseFacts } from './record.js';
42
+ /** What a bound tool was listed under. */
43
+ export interface Binding {
44
+ readonly key: PoolKey;
45
+ /** The definitions context: `pc:<configHash>` per client, `sh:<context>` shared. */
46
+ readonly context: string;
47
+ readonly shared: boolean;
48
+ /** The list it came from: an incarnation's own, or a shared entry's. */
49
+ readonly listId: string;
50
+ readonly generation: number;
51
+ /** Per client: the incarnation it was listed from. */
52
+ readonly clientId?: string;
53
+ readonly definition: Definition;
54
+ }
55
+ /** A callable tool for `binding`, shaped as every MCP tool is. */
56
+ export declare function boundTool(pool: Pool, binding: Binding): Tool;
57
+ /** A refusal's word on the record. */
58
+ export declare function noteRefusal(facts: UseFacts, error: unknown): void;
@@ -0,0 +1,218 @@
1
+ /**
2
+ * boundTool — a tool bound to its conversation, the list it came from and that
3
+ * list's generation, re-checked after every wait and at the send gate.
4
+ *
5
+ * Pattern: the shape every MCP tool takes (`mcpClient.ts` · `mcpToolShape`) +
6
+ * one `execute` that runs the five steps of § 6.3.
7
+ * Role: A bound tool carries its BINDING: the key it was listed for; the
8
+ * context it was listed in (per client, the configuration; shared, the
9
+ * entry's context); the list it came from (per client, the client
10
+ * incarnation; shared, the entry); and that list's generation. Its
11
+ * `execute`:
12
+ *
13
+ * 1. checks that the calling run's caller identity encodes to its key —
14
+ * otherwise `identity-mismatch`, nothing sent;
15
+ * 2. checks its binding is current — otherwise `stale-tools`, nothing sent;
16
+ * 3. is admitted against `maxOperations` and takes a lease on its key's
17
+ * client, opening one from a plan resolved now when the key has none. A
18
+ * client whose plan's context differs from the binding's refuses with
19
+ * `binding-changed` (the client stays for the next list). A client that is
20
+ * not the incarnation the tool was listed from is checked against its OWN
21
+ * fresh list — the call goes on only if that list holds the same
22
+ * definition, compared as canonical JSON; otherwise `stale-tools`. Under
23
+ * the app's sharing contract, a replacement whose context matches uses the
24
+ * shared entry as it stands;
25
+ * 4. after every wait, checks step 2 again — and asks the app's `share`
26
+ * again, so a changed authorization name refuses it (`binding-changed`);
27
+ * 5. sends through the send gate (`mcp/requestGuard.ts`), asked at every
28
+ * boundary the request crosses — before every attempt, after a credential
29
+ * arrives, after signing — classifies the outcome (a server's 404 for the
30
+ * session is `SessionExpiredError`; a handle this process lost is
31
+ * `LocalSessionHandleLostError`; neither is repeated), files its use, and
32
+ * releases its lease once the request's own work has settled.
33
+ *
34
+ * Never another conversation's connection: the binding is to the KEY, and a
35
+ * client of any other key never serves it.
36
+ */
37
+ import { mcpClientUseOf } from '../../tools/mcpClientUse.js';
38
+ import { LocalSessionHandleLostError } from '../../tools/toolSessions.js';
39
+ import { ServerEndedSessionError } from './sessionEnded.js';
40
+ import { mcpToolShape } from '../mcpClient.js';
41
+ import { withCallGuard } from '../requestGuard.js';
42
+ import { McpPoolRefusedError, PoolFullError } from './errors.js';
43
+ import { poolKeyOf } from './identityKey.js';
44
+ import { UseFacts } from './record.js';
45
+ /** A callable tool for `binding`, shaped as every MCP tool is. */
46
+ export function boundTool(pool, binding) {
47
+ return {
48
+ ...mcpToolShape(pool.settings.name, binding.definition.listed),
49
+ execute: (args, ctx) => executeBound(pool, binding, args, ctx),
50
+ };
51
+ }
52
+ /** The five steps. */
53
+ async function executeBound(pool, binding, args, ctx) {
54
+ const facts = new UseFacts(pool.settings.name, 'call');
55
+ facts.keyHash = binding.key.keyHash;
56
+ let operation;
57
+ try {
58
+ // 1 — the calling run's caller identity, encoded the one way.
59
+ const caller = poolKeyOf(ctx?.identity, { requirePrincipal: false, requireTenant: false });
60
+ if (typeof caller === 'string' || caller.key !== binding.key.key) {
61
+ throw pool.refused('identity-mismatch');
62
+ }
63
+ pool.interact();
64
+ // 2 — the binding, before anything is admitted.
65
+ if (beforeLease(pool, binding) === 'stale')
66
+ throw pool.refused('stale-tools');
67
+ // 3 — admitted, leased, opened when the key has none; the app's names asked
68
+ // again, so a changed authorization refuses what was listed under the old.
69
+ operation = pool.admit('call', 'call', ctx?.signal);
70
+ const client = await pool.leaseClient(binding.key, operation, facts);
71
+ if (pool.refreshContext(client).context !== binding.context) {
72
+ throw pool.refused('binding-changed');
73
+ }
74
+ const { inner, effective } = await toolOn(pool, binding, client, operation, facts);
75
+ // 4 — after every wait, the binding again.
76
+ operation.check();
77
+ checkHolds(pool, client, effective);
78
+ // 5 — the send gate, asked at every boundary the request crosses.
79
+ operation.guardWith(() => checkHolds(pool, client, effective));
80
+ operation.phase = 'call';
81
+ const callCtx = withCallGuard({ ...(ctx ?? {}), signal: operation.signal }, operation);
82
+ try {
83
+ return await inner.execute(args, callCtx);
84
+ }
85
+ catch (error) {
86
+ throw classified(pool, client, operation, facts, error);
87
+ }
88
+ }
89
+ catch (error) {
90
+ noteRefusal(facts, error);
91
+ throw error;
92
+ }
93
+ finally {
94
+ operation?.finish();
95
+ mcpClientUseOf(ctx)?.file(facts.toUse());
96
+ }
97
+ }
98
+ /** The tool to run on `client`, and the binding the send gate checks it against. */
99
+ async function toolOn(pool, binding, client, operation, facts) {
100
+ const name = binding.definition.listed.name;
101
+ const port = client.port;
102
+ if (port === undefined)
103
+ throw pool.refused('init-failed');
104
+ if (binding.shared) {
105
+ // The shared entry as it stands: a definition this client may never have
106
+ // listed, so the tool carries its own checks (`ClientPort.bind`).
107
+ return { inner: port.bind(binding.definition.listed), effective: binding };
108
+ }
109
+ if (client.clientId === binding.clientId) {
110
+ const own = client.list.tool(name);
111
+ if (own === undefined)
112
+ throw pool.refused('stale-tools');
113
+ return { inner: own, effective: binding };
114
+ }
115
+ // A replacement: its own fresh list, under the context of now, then the
116
+ // same definition or nothing.
117
+ const listed = await pool.ensureListed(client, operation);
118
+ if (listed.context !== binding.context)
119
+ throw pool.refused('binding-changed');
120
+ const fresh = listed.list.definition(name);
121
+ const own = listed.list.tool(name);
122
+ if (fresh === undefined ||
123
+ own === undefined ||
124
+ fresh.canonical !== binding.definition.canonical) {
125
+ facts.revalidated = 'refused';
126
+ throw pool.refused('stale-tools');
127
+ }
128
+ facts.revalidated = 'kept';
129
+ return {
130
+ inner: own,
131
+ effective: {
132
+ ...binding,
133
+ clientId: client.clientId,
134
+ listId: listed.list.id,
135
+ generation: listed.list.generation,
136
+ },
137
+ };
138
+ }
139
+ /**
140
+ * Step 2, before a lease: a shared binding against its entry; a per-client
141
+ * binding against its incarnation when that incarnation is still the key's
142
+ * current client. An incarnation that is gone is not stale yet — step 3 checks
143
+ * the replacement's own list.
144
+ */
145
+ function beforeLease(pool, binding) {
146
+ if (binding.shared)
147
+ return sharedHolds(pool, binding) ? 'ok' : 'stale';
148
+ const current = pool.clients.currentFor(binding.key.key);
149
+ if (current === undefined || current.clientId !== binding.clientId)
150
+ return 'ok';
151
+ return listHolds(current, binding) ? 'ok' : 'stale';
152
+ }
153
+ /**
154
+ * The binding holds on `client` — the one the call runs on: the app's names
155
+ * still give its context, and its list has not moved. Otherwise the refusal:
156
+ * `binding-changed` for a changed context, `stale-tools` for a moved list.
157
+ */
158
+ function checkHolds(pool, client, binding) {
159
+ if (!pool.contextHolds(client, binding.context))
160
+ throw pool.refused('binding-changed');
161
+ const holds = binding.shared ? sharedHolds(pool, binding) : listHolds(client, binding);
162
+ if (!holds)
163
+ throw pool.refused('stale-tools');
164
+ }
165
+ function sharedHolds(pool, binding) {
166
+ const entry = pool.shared.peek(binding.context);
167
+ return (entry !== undefined &&
168
+ entry.list.id === binding.listId &&
169
+ entry.list.generation === binding.generation);
170
+ }
171
+ function listHolds(client, binding) {
172
+ return client.list.id === binding.listId && client.list.generation === binding.generation;
173
+ }
174
+ /**
175
+ * What the call failed with, as the pool read it: a server's 404 for the
176
+ * session it issued is `SessionExpiredError`; a handle this process lost is
177
+ * `LocalSessionHandleLostError` (the transport's own object). Either way the
178
+ * client leaves its key, and the call is not repeated. Anything else is the
179
+ * error as it came.
180
+ */
181
+ function classified(pool, client, operation, facts, error) {
182
+ const lost = pool.classifyFailure(client, operation, error);
183
+ if (lost === 'expired') {
184
+ facts.client = 'expired';
185
+ facts.evidence = 'server-404';
186
+ return new ServerEndedSessionError(pool.settings.name, client.clientId, error);
187
+ }
188
+ if (lost === 'handle-lost') {
189
+ facts.client = 'handle-lost';
190
+ facts.evidence = 'transport-forgot-handle';
191
+ return error instanceof LocalSessionHandleLostError
192
+ ? error
193
+ : new LocalSessionHandleLostError({ cause: error });
194
+ }
195
+ return error;
196
+ }
197
+ /** A refusal's word on the record. */
198
+ export function noteRefusal(facts, error) {
199
+ if (error instanceof McpPoolRefusedError) {
200
+ facts.refusal = error.reason;
201
+ }
202
+ else if (error instanceof PoolFullError) {
203
+ facts.refusal = LIMIT_WORDS[error.limit];
204
+ }
205
+ else {
206
+ return;
207
+ }
208
+ // No client was touched: the pool refused to give one.
209
+ if (facts.clientId === undefined)
210
+ facts.client = 'refused';
211
+ }
212
+ const LIMIT_WORDS = {
213
+ pool: 'pool-full',
214
+ principal: 'principal-full',
215
+ ending: 'ending-full',
216
+ operations: 'operations-full',
217
+ };
218
+ //# sourceMappingURL=boundTool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boundTool.js","sourceRoot":"","sources":["../../../../src/mcp/pool/boundTool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * clientSet — which clients the pool holds, and in which of its two sets.
3
+ *
4
+ * Pattern: two sets and their indexes, mutated only together.
5
+ * Role: § 5.3 of the design. The OPEN set holds every client that counts
6
+ * toward `maxClients` — opening, busy, idle, deferred, or an abandoned
7
+ * open that has not settled. The ENDING set holds every client from the
8
+ * decision to end it until that ending's work has settled, and counts
9
+ * toward `maxEnding`. A client leaves the open set only into the ending
10
+ * set — a lost handle too: its ending is its local close — or, when its
11
+ * open failed and left nothing to end, by being dropped. So the pool
12
+ * holds at most `maxClients + maxEnding` client objects.
13
+ *
14
+ * Each key has at most one CURRENT client — the one new leases go to. A client
15
+ * named by `terminate`, or whose session expired, stops being current at once
16
+ * while it stays in the open set, counted, until it can end.
17
+ *
18
+ * What the pool remembers of a key after its client left — the incarnation
19
+ * count and why the last one left — is bounded (`KEY_MEMORY`), least recently
20
+ * used forgotten first: after that a key's count starts again at 1. The record
21
+ * reads it; no binding depends on it.
22
+ */
23
+ import type { EndReason, PooledClient } from './pooledClient.js';
24
+ /** How many keys' incarnation counts the pool remembers. */
25
+ export declare const KEY_MEMORY = 4096;
26
+ /** Why a key's previous client left, as the record names it. */
27
+ export type PreviousEnd = 'idle' | 'evicted' | 'expired' | 'handle-lost' | 'terminated';
28
+ export declare class ClientSet {
29
+ private readonly open;
30
+ private readonly ending;
31
+ private readonly current;
32
+ private readonly perPrincipal;
33
+ private readonly memory;
34
+ /** Clients in the open set. */
35
+ get openCount(): number;
36
+ /** Clients in the ending set. */
37
+ get endingCount(): number;
38
+ /** Every client in the open set. */
39
+ openClients(): readonly PooledClient[];
40
+ /** Clients of the open set that count for `principal`. */
41
+ principalCount(principal: string): number;
42
+ /** The key's current client — opening or open, taking new leases — if it has one. */
43
+ currentFor(key: string): PooledClient | undefined;
44
+ /** The next incarnation number for `key`, and why its previous client left. */
45
+ nextIncarnation(key: string): {
46
+ readonly generation: number;
47
+ readonly previous?: PreviousEnd;
48
+ };
49
+ /** A new client joins the open set as its key's current client. */
50
+ admit(client: PooledClient): void;
51
+ /**
52
+ * The client stops taking new leases: its key has no current client until the
53
+ * next open, and that open's record says `why`. A client that is no longer
54
+ * its key's current one has already left it, so nothing is recorded again —
55
+ * a later client of the key keeps its own reason.
56
+ */
57
+ retire(client: PooledClient, why: PreviousEnd): void;
58
+ /** The client moves from the open set into the ending set. */
59
+ moveToEnding(client: PooledClient, why: PreviousEnd | undefined): void;
60
+ /** The client's ending settled: it leaves the ending set. */
61
+ ended(client: PooledClient): void;
62
+ /** The client leaves the open set without ending — a failed open, a lost handle. */
63
+ drop(client: PooledClient, why?: PreviousEnd): void;
64
+ /**
65
+ * The least recently used idle client of the open set — among those `pick`
66
+ * accepts — or `undefined` when every one is busy.
67
+ */
68
+ leastRecentlyUsedIdle(pick: (client: PooledClient) => boolean): PooledClient | undefined;
69
+ private leaveOpen;
70
+ private remember;
71
+ }
72
+ /** The record's `previous` for an end reason, when it names one. */
73
+ export declare function previousOf(reason: EndReason): PreviousEnd | undefined;
@@ -0,0 +1,152 @@
1
+ /**
2
+ * clientSet — which clients the pool holds, and in which of its two sets.
3
+ *
4
+ * Pattern: two sets and their indexes, mutated only together.
5
+ * Role: § 5.3 of the design. The OPEN set holds every client that counts
6
+ * toward `maxClients` — opening, busy, idle, deferred, or an abandoned
7
+ * open that has not settled. The ENDING set holds every client from the
8
+ * decision to end it until that ending's work has settled, and counts
9
+ * toward `maxEnding`. A client leaves the open set only into the ending
10
+ * set — a lost handle too: its ending is its local close — or, when its
11
+ * open failed and left nothing to end, by being dropped. So the pool
12
+ * holds at most `maxClients + maxEnding` client objects.
13
+ *
14
+ * Each key has at most one CURRENT client — the one new leases go to. A client
15
+ * named by `terminate`, or whose session expired, stops being current at once
16
+ * while it stays in the open set, counted, until it can end.
17
+ *
18
+ * What the pool remembers of a key after its client left — the incarnation
19
+ * count and why the last one left — is bounded (`KEY_MEMORY`), least recently
20
+ * used forgotten first: after that a key's count starts again at 1. The record
21
+ * reads it; no binding depends on it.
22
+ */
23
+ /** How many keys' incarnation counts the pool remembers. */
24
+ export const KEY_MEMORY = 4096;
25
+ export class ClientSet {
26
+ open = new Set();
27
+ ending = new Set();
28
+ current = new Map();
29
+ perPrincipal = new Map();
30
+ memory = new Map();
31
+ /** Clients in the open set. */
32
+ get openCount() {
33
+ return this.open.size;
34
+ }
35
+ /** Clients in the ending set. */
36
+ get endingCount() {
37
+ return this.ending.size;
38
+ }
39
+ /** Every client in the open set. */
40
+ openClients() {
41
+ return [...this.open];
42
+ }
43
+ /** Clients of the open set that count for `principal`. */
44
+ principalCount(principal) {
45
+ return this.perPrincipal.get(principal) ?? 0;
46
+ }
47
+ /** The key's current client — opening or open, taking new leases — if it has one. */
48
+ currentFor(key) {
49
+ return this.current.get(key);
50
+ }
51
+ /** The next incarnation number for `key`, and why its previous client left. */
52
+ nextIncarnation(key) {
53
+ const remembered = this.remember(key);
54
+ remembered.incarnations += 1;
55
+ const previous = remembered.previous;
56
+ remembered.previous = undefined;
57
+ return { generation: remembered.incarnations, ...(previous !== undefined && { previous }) };
58
+ }
59
+ /** A new client joins the open set as its key's current client. */
60
+ admit(client) {
61
+ this.open.add(client);
62
+ this.current.set(client.key.key, client);
63
+ this.perPrincipal.set(client.key.principal, this.principalCount(client.key.principal) + 1);
64
+ }
65
+ /**
66
+ * The client stops taking new leases: its key has no current client until the
67
+ * next open, and that open's record says `why`. A client that is no longer
68
+ * its key's current one has already left it, so nothing is recorded again —
69
+ * a later client of the key keeps its own reason.
70
+ */
71
+ retire(client, why) {
72
+ if (this.current.get(client.key.key) !== client)
73
+ return;
74
+ this.current.delete(client.key.key);
75
+ this.remember(client.key.key).previous = why;
76
+ }
77
+ /** The client moves from the open set into the ending set. */
78
+ moveToEnding(client, why) {
79
+ if (why !== undefined)
80
+ this.retire(client, why);
81
+ else if (this.current.get(client.key.key) === client)
82
+ this.current.delete(client.key.key);
83
+ this.leaveOpen(client);
84
+ this.ending.add(client);
85
+ }
86
+ /** The client's ending settled: it leaves the ending set. */
87
+ ended(client) {
88
+ this.ending.delete(client);
89
+ }
90
+ /** The client leaves the open set without ending — a failed open, a lost handle. */
91
+ drop(client, why) {
92
+ if (why !== undefined)
93
+ this.retire(client, why);
94
+ else if (this.current.get(client.key.key) === client)
95
+ this.current.delete(client.key.key);
96
+ this.leaveOpen(client);
97
+ }
98
+ /**
99
+ * The least recently used idle client of the open set — among those `pick`
100
+ * accepts — or `undefined` when every one is busy.
101
+ */
102
+ leastRecentlyUsedIdle(pick) {
103
+ let oldest;
104
+ for (const client of this.open) {
105
+ if (client.busy || client.state !== 'open' || !pick(client))
106
+ continue;
107
+ if (oldest === undefined || client.usedAt < oldest.usedAt)
108
+ oldest = client;
109
+ }
110
+ return oldest;
111
+ }
112
+ leaveOpen(client) {
113
+ if (!this.open.delete(client))
114
+ return;
115
+ const left = this.principalCount(client.key.principal) - 1;
116
+ if (left > 0)
117
+ this.perPrincipal.set(client.key.principal, left);
118
+ else
119
+ this.perPrincipal.delete(client.key.principal);
120
+ }
121
+ remember(key) {
122
+ let remembered = this.memory.get(key);
123
+ if (remembered !== undefined)
124
+ this.memory.delete(key);
125
+ else
126
+ remembered = { incarnations: 0, previous: undefined };
127
+ this.memory.set(key, remembered);
128
+ while (this.memory.size > KEY_MEMORY) {
129
+ const oldest = this.memory.keys().next().value;
130
+ if (oldest === undefined)
131
+ break;
132
+ this.memory.delete(oldest);
133
+ }
134
+ return remembered;
135
+ }
136
+ }
137
+ /** The record's `previous` for an end reason, when it names one. */
138
+ export function previousOf(reason) {
139
+ switch (reason) {
140
+ case 'idle':
141
+ case 'evicted':
142
+ case 'expired':
143
+ case 'handle-lost':
144
+ return reason;
145
+ case 'terminated':
146
+ case 'closed':
147
+ return 'terminated';
148
+ case 'abandoned-open':
149
+ return undefined;
150
+ }
151
+ }
152
+ //# sourceMappingURL=clientSet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientSet.js","sourceRoot":"","sources":["../../../../src/mcp/pool/clientSet.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * definitions — the tool lists a pool serves, and when each stops being served.
3
+ *
4
+ * Pattern: one list type, two owners — a client incarnation, or a shared entry.
5
+ * Role: § 6 of the design. A definition is what one `tools/list` entry says:
6
+ * name, description, input schema, and the declarations its `_meta`
7
+ * carries. The executable half (the connection) is never shared.
8
+ *
9
+ * - PER CLIENT (the default): a conversation's list is its own client's, and
10
+ * it belongs to that client INCARNATION alone — a replacement client, even
11
+ * one opened from the same plan, is a new session whose list may differ,
12
+ * so it lists again.
13
+ * - SHARED, only under the app's declared contract: one entry per context
14
+ * (`plan.ts`), listed on the client of whichever conversation needs it,
15
+ * bounded at `MAX_DEFINITION_ENTRIES` entries; a list longer than
16
+ * `MAX_SHARED_TOOLS` is used by its own client and not shared.
17
+ *
18
+ * A list stops being served in four ways, plus a time limit: the configuration
19
+ * (a new context is a new list), the server's tools-changed notice, the app's
20
+ * `permissionsChanged`, and `toolsChanged`. Invalidation moves the list's
21
+ * GENERATION at once — every tool bound to an older one is refused — and marks
22
+ * it to be listed again. A lapsed time limit lists again at the next list, and
23
+ * moves the generation only if the new list differs. A generation counts within
24
+ * one list: a replacement client and a new entry start counts of their own, and
25
+ * a binding names the list it came from, so no number of an old list can match
26
+ * a new one. A listing still in flight when its list's generation moved is
27
+ * discarded, never written.
28
+ *
29
+ * Every list is a frozen plain-data copy (`mcp/plainData.ts` · `copyJsonObject`),
30
+ * written once per generation, by one listing at a time.
31
+ */
32
+ import type { Tool } from '../../tools/tools.js';
33
+ import type { McpListedTool } from '../types.js';
34
+ /** One definition, frozen, and its canonical JSON — what "the same definition" compares. */
35
+ export interface Definition {
36
+ readonly listed: McpListedTool;
37
+ readonly canonical: string;
38
+ }
39
+ /** A frozen copy of `listed`, or `undefined` when it is not plain JSON data. */
40
+ export declare function definitionOf(listed: McpListedTool): Definition | undefined;
41
+ /**
42
+ * One list: an incarnation's own or a shared entry. Its `id` is stable for its
43
+ * life; its `generation` moves on invalidation, and on a time-limit relisting
44
+ * that changed it.
45
+ */
46
+ export declare class DefinitionList {
47
+ readonly id: string;
48
+ private current;
49
+ private tools;
50
+ /** Has any listing been written? */
51
+ private written;
52
+ /** 0 until the first listing is written. */
53
+ generation: number;
54
+ /** Invalidated: listed again before it is served. */
55
+ stale: boolean;
56
+ /** When it was last written, on the pool's clock. */
57
+ listedAt: number;
58
+ /** The listing in flight, joined by anyone who needs the same list. */
59
+ listing: Promise<void> | undefined;
60
+ /** Can it be served at `now`, as it stands? */
61
+ servable(now: number, ttlMs: number): boolean;
62
+ /**
63
+ * Invalidate: every older binding is refused, the next list lists again, and
64
+ * a listing in flight is discarded — even a first one, before anything was
65
+ * written. Generations only ever increase.
66
+ */
67
+ invalidate(): void;
68
+ /** The definition named `name`, at the current generation. */
69
+ definition(name: string): Definition | undefined;
70
+ /** The client's own wrapped tool named `name` (per-client lists only). */
71
+ tool(name: string): Tool | undefined;
72
+ /** Every definition, in listing order. */
73
+ all(): readonly Definition[];
74
+ /**
75
+ * Write a listing that began at generation `began`. Refused — `false`, nothing
76
+ * written — when the generation moved while it ran. A first write moves the
77
+ * generation to a number no binding has seen; a write after invalidation keeps
78
+ * the moved one; a time-limit rewrite moves it only when the list differs.
79
+ */
80
+ write(began: number, definitions: readonly Definition[], tools: readonly Tool[] | undefined, now: number): boolean;
81
+ }
82
+ /** A shared entry: a list and the tenant its context carries. */
83
+ export interface SharedEntry {
84
+ readonly list: DefinitionList;
85
+ readonly tenant: string;
86
+ }
87
+ /**
88
+ * The shared definition entries, by context — bounded at
89
+ * `MAX_DEFINITION_ENTRIES`, the least recently used dropped first. A dropped
90
+ * entry's bindings are refused as stale: the entry they name is gone.
91
+ */
92
+ export declare class SharedDefinitions {
93
+ private readonly maxEntries;
94
+ private readonly entries;
95
+ constructor(maxEntries?: number);
96
+ get size(): number;
97
+ /** The entry for `context`, created empty when there is none; most recently used. */
98
+ entryFor(context: string, tenant: string): SharedEntry;
99
+ /** The entry for `context` if it still exists — never created. */
100
+ peek(context: string): SharedEntry | undefined;
101
+ /** Invalidate every entry `matches` selects. */
102
+ invalidate(matches: (entry: SharedEntry) => boolean): void;
103
+ }