@pithy-sh/core 0.12.0 → 0.14.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 (362) hide show
  1. package/README.md +54 -0
  2. package/dist/audit/auditEvent.js +1 -1
  3. package/dist/audit/chain.d.ts +289 -0
  4. package/dist/audit/chain.d.ts.map +1 -0
  5. package/dist/audit/chain.js +400 -0
  6. package/dist/audit/citations.d.ts +52 -0
  7. package/dist/audit/citations.d.ts.map +1 -0
  8. package/dist/audit/citations.js +13 -0
  9. package/dist/audit/composed.d.ts +18 -0
  10. package/dist/audit/composed.d.ts.map +1 -0
  11. package/dist/audit/composed.js +28 -0
  12. package/dist/capability/bindings.d.ts +22 -0
  13. package/dist/capability/bindings.d.ts.map +1 -1
  14. package/dist/capability/bindings.js +32 -2
  15. package/dist/capability/capability.d.ts +133 -15
  16. package/dist/capability/capability.d.ts.map +1 -1
  17. package/dist/capability/capability.js +17 -2
  18. package/dist/capability/erasure.d.ts +75 -0
  19. package/dist/capability/erasure.d.ts.map +1 -0
  20. package/dist/capability/erasure.js +2 -0
  21. package/dist/capability/manifest.d.ts +5 -0
  22. package/dist/capability/manifest.d.ts.map +1 -1
  23. package/dist/capability/personColumns.d.ts +28 -0
  24. package/dist/capability/personColumns.d.ts.map +1 -0
  25. package/dist/capability/personColumns.js +66 -0
  26. package/dist/capability/personRows.d.ts +62 -0
  27. package/dist/capability/personRows.d.ts.map +1 -0
  28. package/dist/capability/personRows.js +59 -0
  29. package/dist/capability/purge.d.ts +113 -4
  30. package/dist/capability/purge.d.ts.map +1 -1
  31. package/dist/capability/purge.js +138 -5
  32. package/dist/capability/settings.d.ts +10 -0
  33. package/dist/capability/settings.d.ts.map +1 -1
  34. package/dist/capability/vectorIndex.d.ts +36 -0
  35. package/dist/capability/vectorIndex.d.ts.map +1 -0
  36. package/dist/capability/vectorIndex.js +25 -0
  37. package/dist/cli/commandCatalog.generated.d.ts +434 -4
  38. package/dist/cli/commandCatalog.generated.d.ts.map +1 -1
  39. package/dist/cli/commandCatalog.generated.js +455 -2
  40. package/dist/cli/commandFacts.d.ts +8 -5
  41. package/dist/cli/commandFacts.d.ts.map +1 -1
  42. package/dist/cli/commandFacts.js +12 -3
  43. package/dist/consent/purpose.d.ts +70 -0
  44. package/dist/consent/purpose.d.ts.map +1 -0
  45. package/dist/consent/purpose.js +97 -0
  46. package/dist/consent/reader.d.ts +99 -0
  47. package/dist/consent/reader.d.ts.map +1 -0
  48. package/dist/consent/reader.js +33 -0
  49. package/dist/controlPlane/audit/actions.d.ts +15 -4
  50. package/dist/controlPlane/audit/actions.d.ts.map +1 -1
  51. package/dist/controlPlane/audit/actions.js +16 -5
  52. package/dist/controlPlane/capability.d.ts +10 -0
  53. package/dist/controlPlane/capability.d.ts.map +1 -1
  54. package/dist/controlPlane/capability.js +56 -8
  55. package/dist/controlPlane/context.d.ts +4 -0
  56. package/dist/controlPlane/context.d.ts.map +1 -1
  57. package/dist/controlPlane/context.js +3 -2
  58. package/dist/controlPlane/data/connection.d.ts +21 -2
  59. package/dist/controlPlane/data/connection.d.ts.map +1 -1
  60. package/dist/controlPlane/data/connection.js +13 -4
  61. package/dist/controlPlane/data/connections.d.ts +94 -0
  62. package/dist/controlPlane/data/connections.d.ts.map +1 -0
  63. package/dist/controlPlane/data/connections.js +151 -0
  64. package/dist/controlPlane/data/hold.d.ts +46 -0
  65. package/dist/controlPlane/data/hold.d.ts.map +1 -0
  66. package/dist/controlPlane/data/hold.js +36 -0
  67. package/dist/controlPlane/data/oidcTrust.d.ts +122 -0
  68. package/dist/controlPlane/data/oidcTrust.d.ts.map +1 -0
  69. package/dist/controlPlane/data/oidcTrust.js +173 -0
  70. package/dist/controlPlane/data/tables.d.ts +4 -0
  71. package/dist/controlPlane/data/tables.d.ts.map +1 -1
  72. package/dist/controlPlane/data/tables.js +9 -4
  73. package/dist/controlPlane/data/trustFirstCall.d.ts +16 -0
  74. package/dist/controlPlane/data/trustFirstCall.d.ts.map +1 -0
  75. package/dist/controlPlane/data/trustFirstCall.js +25 -0
  76. package/dist/controlPlane/discovery/adminRoute.d.ts +165 -2
  77. package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -1
  78. package/dist/controlPlane/discovery/adminRoute.js +32 -8
  79. package/dist/controlPlane/discovery/routeInput.d.ts +23 -0
  80. package/dist/controlPlane/discovery/routeInput.d.ts.map +1 -0
  81. package/dist/controlPlane/discovery/routeInput.js +80 -0
  82. package/dist/controlPlane/discovery/toolName.d.ts +21 -0
  83. package/dist/controlPlane/discovery/toolName.d.ts.map +1 -0
  84. package/dist/controlPlane/discovery/toolName.js +25 -0
  85. package/dist/controlPlane/erasure/attest.d.ts +78 -0
  86. package/dist/controlPlane/erasure/attest.d.ts.map +1 -0
  87. package/dist/controlPlane/erasure/attest.js +164 -0
  88. package/dist/controlPlane/erasure/read.d.ts +39 -0
  89. package/dist/controlPlane/erasure/read.d.ts.map +1 -0
  90. package/dist/controlPlane/erasure/read.js +140 -0
  91. package/dist/controlPlane/error/errors.d.ts +61 -2
  92. package/dist/controlPlane/error/errors.d.ts.map +1 -1
  93. package/dist/controlPlane/error/errors.js +13 -0
  94. package/dist/controlPlane/evidence/derive.d.ts +124 -0
  95. package/dist/controlPlane/evidence/derive.d.ts.map +1 -0
  96. package/dist/controlPlane/evidence/derive.js +343 -0
  97. package/dist/controlPlane/evidence/mapping.d.ts +85 -0
  98. package/dist/controlPlane/evidence/mapping.d.ts.map +1 -0
  99. package/dist/controlPlane/evidence/mapping.js +114 -0
  100. package/dist/controlPlane/evidence/pack.d.ts +46 -0
  101. package/dist/controlPlane/evidence/pack.d.ts.map +1 -0
  102. package/dist/controlPlane/evidence/pack.js +124 -0
  103. package/dist/controlPlane/http/connections.d.ts +96 -0
  104. package/dist/controlPlane/http/connections.d.ts.map +1 -0
  105. package/dist/controlPlane/http/connections.js +109 -0
  106. package/dist/controlPlane/http/guard.d.ts +23 -2
  107. package/dist/controlPlane/http/guard.d.ts.map +1 -1
  108. package/dist/controlPlane/http/guard.js +103 -7
  109. package/dist/controlPlane/http/handlers.d.ts +212 -10
  110. package/dist/controlPlane/http/handlers.d.ts.map +1 -1
  111. package/dist/controlPlane/http/handlers.js +117 -26
  112. package/dist/controlPlane/http/holds.d.ts +57 -0
  113. package/dist/controlPlane/http/holds.d.ts.map +1 -0
  114. package/dist/controlPlane/http/holds.js +98 -0
  115. package/dist/controlPlane/http/presence.d.ts +27 -0
  116. package/dist/controlPlane/http/presence.d.ts.map +1 -0
  117. package/dist/controlPlane/http/presence.js +67 -0
  118. package/dist/controlPlane/http/processing.d.ts +73 -0
  119. package/dist/controlPlane/http/processing.d.ts.map +1 -0
  120. package/dist/controlPlane/http/processing.js +17 -0
  121. package/dist/controlPlane/http/responses.d.ts +927 -3
  122. package/dist/controlPlane/http/responses.d.ts.map +1 -1
  123. package/dist/controlPlane/http/responses.js +283 -7
  124. package/dist/controlPlane/http/routes.d.ts +12 -2
  125. package/dist/controlPlane/http/routes.d.ts.map +1 -1
  126. package/dist/controlPlane/http/routes.js +182 -5
  127. package/dist/controlPlane/http/schemas.d.ts +63 -0
  128. package/dist/controlPlane/http/schemas.d.ts.map +1 -1
  129. package/dist/controlPlane/http/schemas.js +39 -1
  130. package/dist/controlPlane/http/verify.d.ts.map +1 -1
  131. package/dist/controlPlane/http/verify.js +13 -1
  132. package/dist/controlPlane/http/verifyTrust.d.ts +76 -0
  133. package/dist/controlPlane/http/verifyTrust.d.ts.map +1 -0
  134. package/dist/controlPlane/http/verifyTrust.js +75 -0
  135. package/dist/controlPlane/migrations/0004_connection_trusts.d.ts +15 -0
  136. package/dist/controlPlane/migrations/0004_connection_trusts.d.ts.map +1 -0
  137. package/dist/controlPlane/migrations/0004_connection_trusts.js +23 -0
  138. package/dist/controlPlane/migrations/0005_holds.d.ts +12 -0
  139. package/dist/controlPlane/migrations/0005_holds.d.ts.map +1 -0
  140. package/dist/controlPlane/migrations/0005_holds.js +26 -0
  141. package/dist/controlPlane/processing/derive.d.ts +77 -0
  142. package/dist/controlPlane/processing/derive.d.ts.map +1 -0
  143. package/dist/controlPlane/processing/derive.js +206 -0
  144. package/dist/controlPlane/processing/read.d.ts +10 -0
  145. package/dist/controlPlane/processing/read.d.ts.map +1 -0
  146. package/dist/controlPlane/processing/read.js +89 -0
  147. package/dist/controlPlane/scope/kind.d.ts +46 -0
  148. package/dist/controlPlane/scope/kind.d.ts.map +1 -0
  149. package/dist/controlPlane/scope/kind.js +52 -0
  150. package/dist/controlPlane/scope/scope.d.ts +58 -3
  151. package/dist/controlPlane/scope/scope.d.ts.map +1 -1
  152. package/dist/controlPlane/scope/scope.js +59 -4
  153. package/dist/controlPlane/token/jws.js +1 -1
  154. package/dist/controlPlane/token/mint.js +1 -1
  155. package/dist/controlPlane/wire.d.ts +23 -0
  156. package/dist/controlPlane/wire.d.ts.map +1 -1
  157. package/dist/controlPlane/wire.js +24 -1
  158. package/dist/createBackend.d.ts +13 -0
  159. package/dist/createBackend.d.ts.map +1 -1
  160. package/dist/createBackend.js +11 -3
  161. package/dist/createEntrypoint.d.ts +14 -1
  162. package/dist/createEntrypoint.d.ts.map +1 -1
  163. package/dist/createEntrypoint.js +19 -5
  164. package/dist/error/http.d.ts +216 -0
  165. package/dist/error/http.d.ts.map +1 -1
  166. package/dist/error/payload.d.ts +432 -0
  167. package/dist/error/payload.d.ts.map +1 -1
  168. package/dist/error/payload.js +144 -0
  169. package/dist/error/pithyError.d.ts +22 -0
  170. package/dist/error/pithyError.d.ts.map +1 -1
  171. package/dist/error/pithyError.js +31 -1
  172. package/dist/http/routeSpec.d.ts +46 -1
  173. package/dist/http/routeSpec.d.ts.map +1 -1
  174. package/dist/http/routeSpec.js +39 -5
  175. package/dist/http/validation.d.ts +11 -2
  176. package/dist/http/validation.d.ts.map +1 -1
  177. package/dist/http/validation.js +20 -3
  178. package/dist/http/verification.d.ts.map +1 -1
  179. package/dist/http/verification.js +1 -1
  180. package/dist/i18n/translator.d.ts +2 -1
  181. package/dist/i18n/translator.d.ts.map +1 -1
  182. package/dist/index.d.ts +1 -1
  183. package/dist/index.d.ts.map +1 -1
  184. package/dist/index.js +3 -3
  185. package/dist/logger/record.d.ts +126 -0
  186. package/dist/logger/record.d.ts.map +1 -1
  187. package/dist/mcp/annotations.d.ts +20 -0
  188. package/dist/mcp/annotations.d.ts.map +1 -0
  189. package/dist/mcp/annotations.js +23 -0
  190. package/dist/mcp/tools.d.ts +75 -0
  191. package/dist/mcp/tools.d.ts.map +1 -0
  192. package/dist/mcp/tools.js +118 -0
  193. package/dist/openapi/document.d.ts.map +1 -1
  194. package/dist/openapi/document.js +8 -26
  195. package/dist/openapi/operations.d.ts +35 -0
  196. package/dist/openapi/operations.d.ts.map +1 -0
  197. package/dist/openapi/operations.js +37 -0
  198. package/dist/presence/channel.d.ts +11 -0
  199. package/dist/presence/channel.d.ts.map +1 -0
  200. package/dist/presence/channel.js +65 -0
  201. package/dist/presence/declaration.d.ts +154 -0
  202. package/dist/presence/declaration.d.ts.map +1 -0
  203. package/dist/presence/declaration.js +164 -0
  204. package/dist/presence/durableObject.d.ts +61 -0
  205. package/dist/presence/durableObject.d.ts.map +1 -0
  206. package/dist/presence/durableObject.js +257 -0
  207. package/dist/presence/frames.d.ts +166 -0
  208. package/dist/presence/frames.d.ts.map +1 -0
  209. package/dist/presence/frames.js +90 -0
  210. package/dist/presence/http/guard.d.ts +11 -0
  211. package/dist/presence/http/guard.d.ts.map +1 -0
  212. package/dist/presence/http/guard.js +20 -0
  213. package/dist/presence/http/responses.d.ts +31 -0
  214. package/dist/presence/http/responses.d.ts.map +1 -0
  215. package/dist/presence/http/responses.js +34 -0
  216. package/dist/presence/http/routes.d.ts +24 -0
  217. package/dist/presence/http/routes.d.ts.map +1 -0
  218. package/dist/presence/http/routes.js +127 -0
  219. package/dist/presence/http/schemas.d.ts +29 -0
  220. package/dist/presence/http/schemas.d.ts.map +1 -0
  221. package/dist/presence/http/schemas.js +28 -0
  222. package/dist/presence/names.d.ts +23 -0
  223. package/dist/presence/names.d.ts.map +1 -0
  224. package/dist/presence/names.js +22 -0
  225. package/dist/presence/room.d.ts +95 -0
  226. package/dist/presence/room.d.ts.map +1 -0
  227. package/dist/presence/room.js +105 -0
  228. package/dist/presence/ticket.d.ts +55 -0
  229. package/dist/presence/ticket.d.ts.map +1 -0
  230. package/dist/presence/ticket.js +109 -0
  231. package/dist/privacy/classify.js +1 -1
  232. package/dist/privacy/encrypted.js +1 -1
  233. package/dist/processing/activity.d.ts +134 -0
  234. package/dist/processing/activity.d.ts.map +1 -0
  235. package/dist/processing/activity.js +161 -0
  236. package/dist/processing/composed.d.ts +18 -0
  237. package/dist/processing/composed.d.ts.map +1 -0
  238. package/dist/processing/composed.js +28 -0
  239. package/dist/processing/vocabulary.d.ts +26 -0
  240. package/dist/processing/vocabulary.d.ts.map +1 -0
  241. package/dist/processing/vocabulary.js +35 -0
  242. package/dist/queue/consumer.d.ts +59 -0
  243. package/dist/queue/consumer.d.ts.map +1 -0
  244. package/dist/queue/consumer.js +46 -0
  245. package/dist/retention/composed.d.ts +37 -0
  246. package/dist/retention/composed.d.ts.map +1 -0
  247. package/dist/retention/composed.js +66 -0
  248. package/dist/retention/holds.d.ts +61 -0
  249. package/dist/retention/holds.d.ts.map +1 -0
  250. package/dist/retention/holds.js +107 -0
  251. package/dist/retention/holdsPurge.d.ts +22 -0
  252. package/dist/retention/holdsPurge.d.ts.map +1 -0
  253. package/dist/retention/holdsPurge.js +50 -0
  254. package/dist/retention/policy.d.ts +132 -0
  255. package/dist/retention/policy.d.ts.map +1 -0
  256. package/dist/retention/policy.js +197 -0
  257. package/dist/session/rotated.d.ts +34 -0
  258. package/dist/session/rotated.d.ts.map +1 -0
  259. package/dist/session/rotated.js +25 -0
  260. package/dist/test-utils/connectionFixtures.d.ts +13 -0
  261. package/dist/test-utils/connectionFixtures.d.ts.map +1 -0
  262. package/dist/test-utils/connectionFixtures.js +58 -0
  263. package/dist/test-utils/interleave.d.ts +12 -0
  264. package/dist/test-utils/interleave.d.ts.map +1 -0
  265. package/dist/test-utils/interleave.js +26 -0
  266. package/dist/testWorker.d.ts +8 -0
  267. package/dist/testWorker.d.ts.map +1 -0
  268. package/dist/testWorker.js +9 -0
  269. package/dist/version.generated.d.ts +1 -1
  270. package/dist/version.generated.js +1 -1
  271. package/dist/workflow/dispatchRoute.js +1 -1
  272. package/package.json +1 -1
  273. package/src/audit/auditEvent.ts +1 -1
  274. package/src/audit/chain.ts +551 -0
  275. package/src/audit/citations.ts +63 -0
  276. package/src/audit/composed.ts +30 -0
  277. package/src/capability/bindings.ts +61 -0
  278. package/src/capability/capability.ts +166 -18
  279. package/src/capability/erasure.ts +82 -0
  280. package/src/capability/personColumns.ts +83 -0
  281. package/src/capability/personRows.ts +125 -0
  282. package/src/capability/purge.ts +208 -8
  283. package/src/capability/settings.ts +7 -0
  284. package/src/capability/vectorIndex.ts +60 -0
  285. package/src/cli/commandCatalog.generated.ts +488 -2
  286. package/src/cli/commandFacts.ts +12 -3
  287. package/src/cloudflare-test.d.ts +3 -1
  288. package/src/consent/purpose.ts +160 -0
  289. package/src/consent/reader.ts +134 -0
  290. package/src/controlPlane/audit/actions.ts +15 -4
  291. package/src/controlPlane/capability.ts +99 -20
  292. package/src/controlPlane/context.ts +10 -2
  293. package/src/controlPlane/data/connection.ts +16 -2
  294. package/src/controlPlane/data/connections.ts +231 -0
  295. package/src/controlPlane/data/hold.ts +52 -0
  296. package/src/controlPlane/data/oidcTrust.ts +249 -0
  297. package/src/controlPlane/data/tables.ts +7 -0
  298. package/src/controlPlane/data/trustFirstCall.ts +37 -0
  299. package/src/controlPlane/discovery/adminRoute.ts +71 -9
  300. package/src/controlPlane/discovery/routeInput.ts +86 -0
  301. package/src/controlPlane/discovery/toolName.ts +23 -0
  302. package/src/controlPlane/erasure/attest.ts +205 -0
  303. package/src/controlPlane/erasure/read.ts +169 -0
  304. package/src/controlPlane/error/errors.ts +69 -2
  305. package/src/controlPlane/evidence/derive.ts +426 -0
  306. package/src/controlPlane/evidence/mapping.ts +118 -0
  307. package/src/controlPlane/evidence/pack.ts +190 -0
  308. package/src/controlPlane/http/connections.ts +129 -0
  309. package/src/controlPlane/http/guard.ts +178 -10
  310. package/src/controlPlane/http/handlers.ts +172 -40
  311. package/src/controlPlane/http/holds.ts +108 -0
  312. package/src/controlPlane/http/presence.ts +71 -0
  313. package/src/controlPlane/http/processing.ts +19 -0
  314. package/src/controlPlane/http/responses.ts +590 -7
  315. package/src/controlPlane/http/routes.ts +302 -3
  316. package/src/controlPlane/http/schemas.ts +126 -0
  317. package/src/controlPlane/http/verify.ts +19 -2
  318. package/src/controlPlane/http/verifyTrust.ts +176 -0
  319. package/src/controlPlane/migrations/0004_connection_trusts.ts +30 -0
  320. package/src/controlPlane/migrations/0005_holds.ts +40 -0
  321. package/src/controlPlane/processing/derive.ts +359 -0
  322. package/src/controlPlane/processing/read.ts +102 -0
  323. package/src/controlPlane/scope/kind.ts +63 -0
  324. package/src/controlPlane/scope/scope.ts +65 -3
  325. package/src/controlPlane/wire.ts +26 -0
  326. package/src/createBackend.ts +31 -6
  327. package/src/createEntrypoint.ts +34 -2
  328. package/src/error/payload.ts +302 -0
  329. package/src/error/pithyError.ts +42 -0
  330. package/src/http/routeSpec.ts +75 -5
  331. package/src/http/validation.ts +35 -3
  332. package/src/http/verification.ts +3 -1
  333. package/src/i18n/translator.ts +2 -1
  334. package/src/index.ts +2 -0
  335. package/src/mcp/annotations.ts +38 -0
  336. package/src/mcp/tools.ts +220 -0
  337. package/src/openapi/document.ts +8 -28
  338. package/src/openapi/operations.ts +62 -0
  339. package/src/presence/channel.ts +46 -0
  340. package/src/presence/declaration.ts +283 -0
  341. package/src/presence/durableObject.ts +287 -0
  342. package/src/presence/frames.ts +153 -0
  343. package/src/presence/http/guard.ts +23 -0
  344. package/src/presence/http/responses.ts +63 -0
  345. package/src/presence/http/routes.ts +165 -0
  346. package/src/presence/http/schemas.ts +39 -0
  347. package/src/presence/names.ts +45 -0
  348. package/src/presence/room.ts +145 -0
  349. package/src/presence/ticket.ts +145 -0
  350. package/src/processing/activity.ts +289 -0
  351. package/src/processing/composed.ts +33 -0
  352. package/src/processing/vocabulary.ts +43 -0
  353. package/src/queue/consumer.ts +104 -0
  354. package/src/retention/composed.ts +75 -0
  355. package/src/retention/holds.ts +175 -0
  356. package/src/retention/holdsPurge.ts +50 -0
  357. package/src/retention/policy.ts +305 -0
  358. package/src/session/rotated.ts +53 -0
  359. package/src/test-utils/connectionFixtures.ts +58 -0
  360. package/src/test-utils/interleave.ts +31 -0
  361. package/src/testWorker.ts +13 -0
  362. package/src/version.generated.ts +1 -1
@@ -1,6 +1,8 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { z } from "zod";
4
+ import { ScopeKind } from "../scope/kind";
5
+ import { ControlPlaneScope } from "../scope/scope";
4
6
  /**
5
7
  * What a capability tells a management client about its own admin surface.
6
8
  *
@@ -28,6 +30,24 @@ export declare const AdminRouteMethod: z.ZodEnum<{
28
30
  PUT: "PUT";
29
31
  }>;
30
32
  export type AdminRouteMethod = z.infer<typeof AdminRouteMethod>;
33
+ /**
34
+ * An admin route's operation id (`docs/AGENT-ACCESS.md` §5): lowercase words joined by `.`, `_` or `-`.
35
+ *
36
+ * **Permanent once published.** An agent names a tool in prompts, saved workflows and its own record of what
37
+ * worked, so a renamed operation breaks callers silently — the same class of rule as a role name. Unique within
38
+ * its capability; `packages/cli/src/ci/adminOperations.test.ts` holds every kit capability's to a table.
39
+ */
40
+ export declare const AdminOperation: z.ZodString;
41
+ export type AdminOperation = z.infer<typeof AdminOperation>;
42
+ /**
43
+ * An admin route's input as JSON Schema: an object whose `path`, `query` and `body` properties are each
44
+ * the JSON Schema of the validator the route runs on that part of the request.
45
+ *
46
+ * A record rather than a modeled schema, because it is JSON Schema — a vocabulary this manifest relays, never
47
+ * one it defines — and an MCP client publishes it verbatim as a tool's `inputSchema`.
48
+ */
49
+ export declare const AdminRouteInput: z.ZodRecord<z.ZodString, z.ZodUnknown>;
50
+ export type AdminRouteInput = z.infer<typeof AdminRouteInput>;
31
51
  /** One admin route a capability contributes behind the `control-plane` strategy. */
32
52
  export declare const AdminRoute: z.ZodObject<{
33
53
  method: z.ZodEnum<{
@@ -40,8 +60,29 @@ export declare const AdminRoute: z.ZodObject<{
40
60
  path: z.ZodString;
41
61
  scope: z.ZodNullable<z.ZodString>;
42
62
  summary: z.ZodString;
63
+ kind: z.ZodOptional<z.ZodEnum<{
64
+ charges: "charges";
65
+ credentials: "credentials";
66
+ deletes: "deletes";
67
+ reads: "reads";
68
+ sends: "sends";
69
+ writes: "writes";
70
+ }>>;
71
+ operation: z.ZodOptional<z.ZodString>;
72
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
43
73
  }, z.core.$strip>;
44
74
  export type AdminRoute = z.infer<typeof AdminRoute>;
75
+ /**
76
+ * An admin route as a capability declares it: a scoped route states its kind, and a route with no scope has none.
77
+ * `Capability.adminRoutes` takes this, so a scoped route without a kind does not compile.
78
+ */
79
+ export type AdminRouteDeclaration = Omit<AdminRoute, "scope" | "kind"> & ({
80
+ scope: ControlPlaneScope;
81
+ kind: ScopeKind;
82
+ } | {
83
+ scope: null;
84
+ kind?: undefined;
85
+ });
45
86
  /**
46
87
  * One composed capability's declaration — everything about it that is the same for every caller.
47
88
  *
@@ -64,6 +105,16 @@ export declare const CapabilityDeclaration: z.ZodObject<{
64
105
  path: z.ZodString;
65
106
  scope: z.ZodNullable<z.ZodString>;
66
107
  summary: z.ZodString;
108
+ kind: z.ZodOptional<z.ZodEnum<{
109
+ charges: "charges";
110
+ credentials: "credentials";
111
+ deletes: "deletes";
112
+ reads: "reads";
113
+ sends: "sends";
114
+ writes: "writes";
115
+ }>>;
116
+ operation: z.ZodOptional<z.ZodString>;
117
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
67
118
  }, z.core.$strip>>;
68
119
  healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
69
120
  key: z.ZodString;
@@ -89,6 +140,14 @@ export declare const CapabilityDeclaration: z.ZodObject<{
89
140
  summary: z.ZodString;
90
141
  }, z.core.$strip>>>;
91
142
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
143
+ presenceRooms: z.ZodOptional<z.ZodArray<z.ZodObject<{
144
+ kind: z.ZodString;
145
+ scope: z.ZodString;
146
+ activities: z.ZodArray<z.ZodString>;
147
+ maxParticipants: z.ZodNumber;
148
+ sessionTicketPath: z.ZodNullable<z.ZodString>;
149
+ socketPath: z.ZodString;
150
+ }, z.core.$strip>>>;
92
151
  }, z.core.$strip>;
93
152
  export type CapabilityDeclaration = z.infer<typeof CapabilityDeclaration>;
94
153
  export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
@@ -106,6 +165,16 @@ export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
106
165
  path: z.ZodString;
107
166
  scope: z.ZodNullable<z.ZodString>;
108
167
  summary: z.ZodString;
168
+ kind: z.ZodOptional<z.ZodEnum<{
169
+ charges: "charges";
170
+ credentials: "credentials";
171
+ deletes: "deletes";
172
+ reads: "reads";
173
+ sends: "sends";
174
+ writes: "writes";
175
+ }>>;
176
+ operation: z.ZodOptional<z.ZodString>;
177
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
109
178
  }, z.core.$strip>>;
110
179
  healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
111
180
  key: z.ZodString;
@@ -131,6 +200,14 @@ export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
131
200
  summary: z.ZodString;
132
201
  }, z.core.$strip>>>;
133
202
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
203
+ presenceRooms: z.ZodOptional<z.ZodArray<z.ZodObject<{
204
+ kind: z.ZodString;
205
+ scope: z.ZodString;
206
+ activities: z.ZodArray<z.ZodString>;
207
+ maxParticipants: z.ZodNumber;
208
+ sessionTicketPath: z.ZodNullable<z.ZodString>;
209
+ socketPath: z.ZodString;
210
+ }, z.core.$strip>>>;
134
211
  health: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>>;
135
212
  healthUnavailable: z.ZodDefault<z.ZodBoolean>;
136
213
  }, z.core.$strip>, z.ZodObject<{
@@ -148,6 +225,16 @@ export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
148
225
  path: z.ZodString;
149
226
  scope: z.ZodNullable<z.ZodString>;
150
227
  summary: z.ZodString;
228
+ kind: z.ZodOptional<z.ZodEnum<{
229
+ charges: "charges";
230
+ credentials: "credentials";
231
+ deletes: "deletes";
232
+ reads: "reads";
233
+ sends: "sends";
234
+ writes: "writes";
235
+ }>>;
236
+ operation: z.ZodOptional<z.ZodString>;
237
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
151
238
  }, z.core.$strip>>;
152
239
  healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
153
240
  key: z.ZodString;
@@ -173,6 +260,14 @@ export declare const CapabilityDescriptor: z.ZodCodec<z.ZodObject<{
173
260
  summary: z.ZodString;
174
261
  }, z.core.$strip>>>;
175
262
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
263
+ presenceRooms: z.ZodOptional<z.ZodArray<z.ZodObject<{
264
+ kind: z.ZodString;
265
+ scope: z.ZodString;
266
+ activities: z.ZodArray<z.ZodString>;
267
+ maxParticipants: z.ZodNumber;
268
+ sessionTicketPath: z.ZodNullable<z.ZodString>;
269
+ socketPath: z.ZodString;
270
+ }, z.core.$strip>>>;
176
271
  health: z.ZodDiscriminatedUnion<[z.ZodObject<{
177
272
  state: z.ZodLiteral<"undeclared">;
178
273
  }, z.core.$strip>, z.ZodObject<{
@@ -193,7 +288,7 @@ export type CapabilityDescriptor = z.infer<typeof CapabilityDescriptor>;
193
288
  * now — so a capability that changed its paths or its scopes reports the change directly, and a schema
194
289
  * version would be a second source of truth to keep in sync with the first. That reasoning is unchanged.
195
290
  *
196
- * **And `capabilities[].version` travels with the package it belongs to** (#626). A version is only
291
+ * **And `capabilities[].version` travels with the package it belongs to**. A version is only
197
292
  * actionable joined against a release feed, a feed is keyed by package name, and a capability name is
198
293
  * not one — `controlplane` ships inside `@pithy-sh/core`. Reporting the version alone left every client
199
294
  * guessing the key, and the guess failed silently on the most frequently released package there is.
@@ -207,7 +302,7 @@ export type CapabilityDescriptor = z.infer<typeof CapabilityDescriptor>;
207
302
  * we just fixed", and "does this project predate the capability a pane needs". Reporting only one leaves
208
303
  * half the questions unanswerable, and they are the halves people actually ask.
209
304
  *
210
- * **And each entry carries a third thing: the configured facts that capability states** (#422). Knowing
305
+ * **And each entry carries a third thing: the configured facts that capability states**. Knowing
211
306
  * where a route is and which scope it needs is not always enough to call it — `POST
212
307
  * {base}/entitlements/grant` names a holder, and whether this project's holders are people or
213
308
  * organizations is a decision the adopter made in config. A client that cannot read the decision guesses
@@ -247,6 +342,38 @@ export declare const ControlPlaneManifest: z.ZodObject<{
247
342
  liveVersions: z.ZodNumber;
248
343
  }, z.core.$strip>>;
249
344
  }, z.core.$strip>>;
345
+ retention: z.ZodOptional<z.ZodObject<{
346
+ purgeWindows: z.ZodArray<z.ZodObject<{
347
+ subject: z.ZodEnum<{
348
+ organization: "organization";
349
+ user: "user";
350
+ }>;
351
+ days: z.ZodNumber;
352
+ source: z.ZodEnum<{
353
+ capability: "capability";
354
+ floor: "floor";
355
+ policy: "policy";
356
+ }>;
357
+ }, z.core.$strip>>;
358
+ audit: z.ZodObject<{
359
+ defaultDays: z.ZodNullable<z.ZodNumber>;
360
+ floorDays: z.ZodNumber;
361
+ rules: z.ZodArray<z.ZodObject<{
362
+ prefix: z.ZodString;
363
+ days: z.ZodNumber;
364
+ source: z.ZodEnum<{
365
+ capability: "capability";
366
+ floor: "floor";
367
+ policy: "policy";
368
+ }>;
369
+ }, z.core.$strip>>;
370
+ floored: z.ZodArray<z.ZodString>;
371
+ }, z.core.$strip>;
372
+ classAges: z.ZodArray<z.ZodObject<{
373
+ class: z.ZodString;
374
+ days: z.ZodNumber;
375
+ }, z.core.$strip>>;
376
+ }, z.core.$strip>>;
250
377
  capabilities: z.ZodArray<z.ZodCodec<z.ZodObject<{
251
378
  name: z.ZodString;
252
379
  version: z.ZodNullable<z.ZodString>;
@@ -262,6 +389,16 @@ export declare const ControlPlaneManifest: z.ZodObject<{
262
389
  path: z.ZodString;
263
390
  scope: z.ZodNullable<z.ZodString>;
264
391
  summary: z.ZodString;
392
+ kind: z.ZodOptional<z.ZodEnum<{
393
+ charges: "charges";
394
+ credentials: "credentials";
395
+ deletes: "deletes";
396
+ reads: "reads";
397
+ sends: "sends";
398
+ writes: "writes";
399
+ }>>;
400
+ operation: z.ZodOptional<z.ZodString>;
401
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
265
402
  }, z.core.$strip>>;
266
403
  healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
267
404
  key: z.ZodString;
@@ -287,6 +424,14 @@ export declare const ControlPlaneManifest: z.ZodObject<{
287
424
  summary: z.ZodString;
288
425
  }, z.core.$strip>>>;
289
426
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
427
+ presenceRooms: z.ZodOptional<z.ZodArray<z.ZodObject<{
428
+ kind: z.ZodString;
429
+ scope: z.ZodString;
430
+ activities: z.ZodArray<z.ZodString>;
431
+ maxParticipants: z.ZodNumber;
432
+ sessionTicketPath: z.ZodNullable<z.ZodString>;
433
+ socketPath: z.ZodString;
434
+ }, z.core.$strip>>>;
290
435
  health: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>>;
291
436
  healthUnavailable: z.ZodDefault<z.ZodBoolean>;
292
437
  }, z.core.$strip>, z.ZodObject<{
@@ -304,6 +449,16 @@ export declare const ControlPlaneManifest: z.ZodObject<{
304
449
  path: z.ZodString;
305
450
  scope: z.ZodNullable<z.ZodString>;
306
451
  summary: z.ZodString;
452
+ kind: z.ZodOptional<z.ZodEnum<{
453
+ charges: "charges";
454
+ credentials: "credentials";
455
+ deletes: "deletes";
456
+ reads: "reads";
457
+ sends: "sends";
458
+ writes: "writes";
459
+ }>>;
460
+ operation: z.ZodOptional<z.ZodString>;
461
+ input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
307
462
  }, z.core.$strip>>;
308
463
  healthKeys: z.ZodDefault<z.ZodArray<z.ZodObject<{
309
464
  key: z.ZodString;
@@ -329,6 +484,14 @@ export declare const ControlPlaneManifest: z.ZodObject<{
329
484
  summary: z.ZodString;
330
485
  }, z.core.$strip>>>;
331
486
  config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
487
+ presenceRooms: z.ZodOptional<z.ZodArray<z.ZodObject<{
488
+ kind: z.ZodString;
489
+ scope: z.ZodString;
490
+ activities: z.ZodArray<z.ZodString>;
491
+ maxParticipants: z.ZodNumber;
492
+ sessionTicketPath: z.ZodNullable<z.ZodString>;
493
+ socketPath: z.ZodString;
494
+ }, z.core.$strip>>>;
332
495
  health: z.ZodDiscriminatedUnion<[z.ZodObject<{
333
496
  state: z.ZodLiteral<"undeclared">;
334
497
  }, z.core.$strip>, z.ZodObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"adminRoute.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/discovery/adminRoute.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;;;;;;;;;;;;;;;GAiBG;AAEH,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB;;;;;;EAE8B,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE,oFAAoF;AACpF,eAAO,MAAM,UAAU;;;;;;;;;;;iBAmBpB,CAAC;AACJ,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqD/B,CAAC;AACJ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAiD1E,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsC9B,CAAC;AACJ,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiCkE,CAAC;AACpG,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
1
+ {"version":3,"file":"adminRoute.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/discovery/adminRoute.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAInD;;;;;;;;;;;;;;;;;GAiBG;AAEH,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB;;;;;;EAE8B,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,aAOgE,CAAC;AAC5F,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,wCAE+D,CAAC;AAC5F,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,oFAAoF;AACpF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;iBA+BpB,CAAC;AACJ,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CAAC,GACpE,CAAC;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AAEtF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6D/B,CAAC;AACJ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAiD1E,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAsC9B,CAAC;AACJ,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoCkE,CAAC;AACpG,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
@@ -1,8 +1,11 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { ControlPlaneScope } from "../scope/scope.js";
4
+ import { PresenceRoomDescriptor } from "../../presence/http/responses.js";
5
+ import { EffectiveRetention } from "../../retention/policy.js";
4
6
  import { CapabilityHealthReport, HealthSummary, HealthSummaryKey, healthReport, healthWire } from "./healthSummary.js";
5
7
  import { PrivacyPosture } from "../../privacy/posture.js";
8
+ import { ScopeKind } from "../scope/kind.js";
6
9
  import { ManifestConfigKey, ManifestConfigValues } from "./configuration.js";
7
10
  import { z } from "zod";
8
11
  //#region src/controlPlane/discovery/adminRoute.ts
@@ -32,12 +35,31 @@ const AdminRouteMethod = z.enum([
32
35
  "PATCH",
33
36
  "DELETE"
34
37
  ]).describe("The HTTP method this admin route answers on.");
38
+ /**
39
+ * An admin route's operation id (`docs/AGENT-ACCESS.md` §5): lowercase words joined by `.`, `_` or `-`.
40
+ *
41
+ * **Permanent once published.** An agent names a tool in prompts, saved workflows and its own record of what
42
+ * worked, so a renamed operation breaks callers silently — the same class of rule as a role name. Unique within
43
+ * its capability; `packages/cli/src/ci/adminOperations.test.ts` holds every kit capability's to a table.
44
+ */
45
+ const AdminOperation = z.string().max(64).regex(/^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/, "An operation is lowercase words joined by `.`, `_` or `-`, e.g. `threads.reply`.").describe("An admin route's permanent name within its capability, e.g. `threads.reply`.");
46
+ /**
47
+ * An admin route's input as JSON Schema: an object whose `path`, `query` and `body` properties are each
48
+ * the JSON Schema of the validator the route runs on that part of the request.
49
+ *
50
+ * A record rather than a modeled schema, because it is JSON Schema — a vocabulary this manifest relays, never
51
+ * one it defines — and an MCP client publishes it verbatim as a tool's `inputSchema`.
52
+ */
53
+ const AdminRouteInput = z.record(z.string().describe("A JSON Schema keyword."), z.unknown().describe("Its value.")).describe("A JSON Schema object describing the route's path parameters, query and body.");
35
54
  /** One admin route a capability contributes behind the `control-plane` strategy. */
36
55
  const AdminRoute = z.object({
37
56
  method: AdminRouteMethod.describe("The method to call this route with."),
38
57
  path: z.string().min(1).describe("The **fully mounted** path, with the capability's configured `basePath` already applied — `/billing/entitlements/grant`, not `/entitlements/grant`. Built by the capability at assembly, so an adopter who moved the mount point is reflected here rather than silently breaking a client that assumed the default."),
39
58
  scope: ControlPlaneScope.nullable().describe("The scope this route requires, or null when it needs only a verified caller (the seam's `ping`). A client compares it against the connection's granted scopes to know which operations it may actually offer, instead of discovering a 403 by trying."),
40
- summary: z.string().min(1).describe("One line describing what the route does, for a management client to render beside it.")
59
+ summary: z.string().min(1).describe("One line describing what the route does, for a management client to render beside it."),
60
+ kind: ScopeKind.optional().describe("What kind of operation the route's scope grants — `reads`, `writes`, `sends`, `charges`, `deletes` or `credentials` — declared by the capability that owns the scope. Every route sharing a scope declares the same kind, so a management client maps its own roles onto kinds rather than onto scopes. Absent for a route with no scope, and from an older Worker, which a client treats as `credentials`, the most restrictive."),
61
+ operation: AdminOperation.optional().describe("The route's permanent name within its capability — `threads.reply`, `users.suspend` — declared beside the route by the capability that owns it. Never derived from the path, which moves when an adopter moves a `basePath`, and never from the scope, which several routes share. An MCP tool is named `<capability>_<operation>`. Absent from a Worker that predates #723."),
62
+ input: AdminRouteInput.optional().describe("What the route takes, as one JSON Schema object with up to three properties — `path`, `query` and `body` — generated from the Zod schemas the route validates with, so it cannot drift from what the route accepts. Filled in by the seam from the composed router, never declared by hand. Absent from a Worker that predates #723.")
41
63
  }).describe("One admin route, described well enough for a management client to call it without holding any capability-specific knowledge.");
42
64
  /**
43
65
  * One composed capability's declaration — everything about it that is the same for every caller.
@@ -53,19 +75,20 @@ const CapabilityDeclaration = z.object({
53
75
  adminRoutes: z.array(AdminRoute).describe("Every admin route this capability contributes, or empty when it contributes none. Most capabilities are empty: having no management surface is the normal case, and saying so explicitly is what lets a client render a capability it cannot act on."),
54
76
  healthKeys: z.array(HealthSummaryKey).default([]).describe("The closed vocabulary of scalars this capability may report about its own state, or empty when it reports none — including when the Worker predates this field and says nothing at all. Declared alongside the routes so a client can render a key it has never heard of from what the Worker says about it — and so a *withheld* number is visible as a key with no value, rather than as silence."),
55
77
  configKeys: z.array(ManifestConfigKey).default([]).describe("The configured facts this capability states, or empty when it states none — including when the Worker predates this field. Declared alongside the routes, because a fact is what a client needs to *call* one: `POST /billing/entitlements/grant` names a holder and never assumes it, so a client that cannot learn what this project bills can only guess — and a guess writes a row nothing reads."),
56
- config: ManifestConfigValues.default({}).describe("What each declared fact resolved to for this deployment. The same answer for every caller, read off the capability's parsed config at assembly: there is no producer here, so no failure state, no per-request cost, and no staleness beyond the manifest itself.")
78
+ config: ManifestConfigValues.default({}).describe("What each declared fact resolved to for this deployment. The same answer for every caller, read off the capability's parsed config at assembly: there is no producer here, so no failure state, no per-request cost, and no staleness beyond the manifest itself."),
79
+ presenceRooms: z.array(PresenceRoomDescriptor).optional().describe("The presence room kinds this capability serves — who else has one of its records open, live — or empty when it serves none. Absent from a Worker that predates presence rooms. Mint a ticket into one at `POST /control-plane/presence/tickets` with the kind's own `scope`.")
57
80
  }).describe("One capability this Worker composes, the package and version it is at, the admin surface it exposes, the summary it may report, and the configured facts a client must respect to call any of it.");
58
81
  /**
59
82
  * One composed capability's manifest entry **as it goes over the wire**.
60
83
  *
61
84
  * Two flat fields, and neither is what a consumer reads: {@link CapabilityDescriptor} decodes them into
62
85
  * one value that says which of the four states it is in. They are flat here because the wire has an
63
- * older half to keep working. A Worker deployed before #350 sends no `healthUnavailable` and a Worker
64
- * deployed before #317 sends neither field, and both must still parse; and a client pinned to a build
86
+ * older half to keep working. An older Worker may send no `healthUnavailable`, or neither
87
+ * field, and both must still parse; and a client pinned to a build
65
88
  * older than the Worker it is reading strips the field it has never heard of and lands on `health:
66
89
  * null`, which renders as silence rather than as a zero. Putting the fourth state *inside* `health`
67
90
  * would have cost that client the whole manifest for one capability's bad afternoon, which is the
68
- * failure #352 is about.
91
+ * failure the defaults above exist to prevent.
69
92
  */
70
93
  const CapabilityDescriptorWire = CapabilityDeclaration.extend({
71
94
  health: HealthSummary.nullable().default(null).describe("Every declared value this caller may see, or null when there is none to give — either nothing is declared, or this connection lacks the scope the value is behind, or producing it failed, or the Worker predates this field. **Null is never zero.**"),
@@ -114,7 +137,7 @@ const CapabilityDescriptor = z.codec(CapabilityDescriptorWire, CapabilityDescrip
114
137
  * now — so a capability that changed its paths or its scopes reports the change directly, and a schema
115
138
  * version would be a second source of truth to keep in sync with the first. That reasoning is unchanged.
116
139
  *
117
- * **And `capabilities[].version` travels with the package it belongs to** (#626). A version is only
140
+ * **And `capabilities[].version` travels with the package it belongs to**. A version is only
118
141
  * actionable joined against a release feed, a feed is keyed by package name, and a capability name is
119
142
  * not one — `controlplane` ships inside `@pithy-sh/core`. Reporting the version alone left every client
120
143
  * guessing the key, and the guess failed silently on the most frequently released package there is.
@@ -128,7 +151,7 @@ const CapabilityDescriptor = z.codec(CapabilityDescriptorWire, CapabilityDescrip
128
151
  * we just fixed", and "does this project predate the capability a pane needs". Reporting only one leaves
129
152
  * half the questions unanswerable, and they are the halves people actually ask.
130
153
  *
131
- * **And each entry carries a third thing: the configured facts that capability states** (#422). Knowing
154
+ * **And each entry carries a third thing: the configured facts that capability states**. Knowing
132
155
  * where a route is and which scope it needs is not always enough to call it — `POST
133
156
  * {base}/entitlements/grant` names a holder, and whether this project's holders are people or
134
157
  * organizations is a decision the adopter made in config. A client that cannot read the decision guesses
@@ -141,8 +164,9 @@ const ControlPlaneManifest = z.object({
141
164
  version: z.string().nullable().describe("The Cloudflare version id of the build answering this call, from the `CF_VERSION_METADATA` binding, or null where the binding is absent. Opaque and per-deploy: it identifies which build is running, never which features it has. Null is honest — a Worker scaffolded before the binding was declared genuinely cannot say."),
142
165
  versionCreatedAt: z.iso.datetime().nullable().optional().describe("When the version answering this call was uploaded, ISO-8601, from the same `CF_VERSION_METADATA` binding as `version` — or null where the binding is absent. The id alone cannot tell a deploy from a rollback: a rollback reactivates an existing version, so the id returns to one already seen while this moves backwards. Relayed, never interpreted. Absent from a Worker older than #132."),
143
166
  privacy: PrivacyPosture.optional().describe("What this project declares about privacy and what its running code holds: classes and counts, never field names (`GET /control-plane/privacy` has those, behind `privacy:read`). Present on every Worker from #132, `declared` explicitly empty when nothing was declared; absent from an older Worker."),
167
+ retention: EffectiveRetention.optional().describe("How long this Worker keeps deleted accounts, the audit trail and each class of personal data, as its `retention` block takes effect: every window in days and where it came from. Absent from an older Worker."),
144
168
  capabilities: z.array(CapabilityDescriptor).describe("Every capability composed into this Worker, in composition order with the adopter's own app last. A capability absent here has no data to show, which is a fact the client discovers rather than a setting anybody maintains."),
145
169
  grantedScopes: z.array(ControlPlaneScope).describe("Every scope this connection holds. Together with each route's own `scope`, this is what tells a client which operations to offer and which to hide.")
146
170
  }).describe("What this Worker is, what it composes, and how to call the admin surface it exposes.");
147
171
  //#endregion
148
- export { AdminRoute, AdminRouteMethod, CapabilityDeclaration, CapabilityDescriptor, ControlPlaneManifest };
172
+ export { AdminOperation, AdminRoute, AdminRouteInput, AdminRouteMethod, CapabilityDeclaration, CapabilityDescriptor, ControlPlaneManifest };
@@ -0,0 +1,23 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { type RouteGroup } from "../../openapi/document";
4
+ import type { AdminRouteInput, CapabilityDeclaration } from "./adminRoute";
5
+ /**
6
+ * The JSON Schema of one route's input, built from the request contracts on its handlers. The app's own MCP tools
7
+ * (`../../mcp/tools.ts`) take their input from here too, so a tool on either server has one shape.
8
+ */
9
+ export declare function inputOf(handlers: readonly unknown[]): AdminRouteInput;
10
+ /**
11
+ * Every routed operation's input, keyed `METHOD path` as the manifest's admin routes are. Routes the groups do
12
+ * not hold are simply absent — an admin route the router does not serve is `missingAdminRoutes`'s finding, not
13
+ * this module's.
14
+ */
15
+ export declare function routeInputs(groups: readonly RouteGroup[]): ReadonlyMap<string, AdminRouteInput>;
16
+ /**
17
+ * The declarations with each admin route's `input` filled in from the router.
18
+ *
19
+ * Without route groups — an app `createBackend` did not assemble — the declarations go out as they are, and a
20
+ * client offers no tool for a route it was told nothing about. That is the same answer an older Worker gets.
21
+ */
22
+ export declare function withRouteInputs(declarations: readonly CapabilityDeclaration[], inputs: ReadonlyMap<string, AdminRouteInput> | undefined): CapabilityDeclaration[];
23
+ //# sourceMappingURL=routeInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routeInput.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/discovery/routeInput.ts"],"names":[],"mappings":"AAIA,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAErE,OAAO,KAAK,EAAc,eAAe,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAoBvF;;;GAGG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,eAAe,CAoBrE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAQ/F;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,SAAS,qBAAqB,EAAE,EAC9C,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,GACvD,qBAAqB,EAAE,CASzB"}
@@ -0,0 +1,80 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import { requestContractOf } from "../../http/validation.js";
4
+ import { operationsOf } from "../../openapi/operations.js";
5
+ import { jsonSchema } from "../../openapi/document.js";
6
+ //#region src/controlPlane/discovery/routeInput.ts
7
+ /**
8
+ * What each admin route takes, read off the composed router (#723, `docs/AGENT-ACCESS.md` §3).
9
+ *
10
+ * **Generated, never declared.** A route already states what it accepts on its own line — `validate("param",
11
+ * …)`, `validate("query", …)`, `validate("json", …)` — and that is the schema the request is actually parsed
12
+ * with. So the manifest's `input` is that schema, converted once, rather than a second description a capability
13
+ * would have to keep in step with the first. A route that changes its body changes its tool on the same commit.
14
+ *
15
+ * **One object, three parts.** An MCP tool takes one argument object, and a route reads three places, so the
16
+ * input is an object with a `path`, a `query` and a `body` property — each present only when the route
17
+ * validates that part. A client splits the arguments back out along the same three keys. A route that
18
+ * validates nothing still gets an input: an empty object, which says *this takes nothing* rather than *this
19
+ * Worker cannot say*.
20
+ */
21
+ /** The three parts of a request an admin route's input may carry, and the validator target each comes from. */
22
+ const PARTS = {
23
+ param: "path",
24
+ query: "query",
25
+ json: "body"
26
+ };
27
+ /**
28
+ * The JSON Schema of one route's input, built from the request contracts on its handlers. The app's own MCP tools
29
+ * (`../../mcp/tools.ts`) take their input from here too, so a tool on either server has one shape.
30
+ */
31
+ function inputOf(handlers) {
32
+ const properties = {};
33
+ const required = [];
34
+ for (const handler of handlers) {
35
+ const contract = requestContractOf(handler);
36
+ if (contract === void 0) continue;
37
+ const part = PARTS[contract.target];
38
+ if (part === void 0) continue;
39
+ properties[part] = jsonSchema(contract.schema, "input");
40
+ const absent = part === "query" ? {} : void 0;
41
+ if (part === "path" || !contract.schema.safeParse(absent).success) required.push(part);
42
+ }
43
+ return {
44
+ type: "object",
45
+ properties,
46
+ ...required.length > 0 ? { required } : {},
47
+ additionalProperties: false
48
+ };
49
+ }
50
+ /**
51
+ * Every routed operation's input, keyed `METHOD path` as the manifest's admin routes are. Routes the groups do
52
+ * not hold are simply absent — an admin route the router does not serve is `missingAdminRoutes`'s finding, not
53
+ * this module's.
54
+ */
55
+ function routeInputs(groups) {
56
+ const inputs = /* @__PURE__ */ new Map();
57
+ for (const group of groups) for (const operation of operationsOf(group.routes)) inputs.set(`${operation.method.toUpperCase()} ${operation.path}`, inputOf(operation.handlers));
58
+ return inputs;
59
+ }
60
+ /**
61
+ * The declarations with each admin route's `input` filled in from the router.
62
+ *
63
+ * Without route groups — an app `createBackend` did not assemble — the declarations go out as they are, and a
64
+ * client offers no tool for a route it was told nothing about. That is the same answer an older Worker gets.
65
+ */
66
+ function withRouteInputs(declarations, inputs) {
67
+ if (inputs === void 0) return [...declarations];
68
+ return declarations.map((declaration) => ({
69
+ ...declaration,
70
+ adminRoutes: declaration.adminRoutes.map((route) => {
71
+ const input = inputs.get(`${route.method} ${route.path}`);
72
+ return input === void 0 ? route : {
73
+ ...route,
74
+ input
75
+ };
76
+ })
77
+ }));
78
+ }
79
+ //#endregion
80
+ export { inputOf, routeInputs, withRouteInputs };
@@ -0,0 +1,21 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ /**
4
+ * The one place an MCP tool name is made (`docs/AGENT-ACCESS.md` §5) — for the control-plane server's tools, and
5
+ * for the app's own MCP endpoint's (`../../mcp/tools.ts`), so one rule names both servers' tools.
6
+ *
7
+ * **Derived, never hand-written.** A tool is `<capability>_<operation>`: the capability's name, which already
8
+ * partitions migrations, tables and error codes, and the operation the capability declared beside the route. Two
9
+ * capabilities both exposing `threads.list` cannot collide, and nothing about the route's path or scope — both of
10
+ * which move or are shared — reaches the name.
11
+ *
12
+ * **Neither existing separator survives.** MCP names conventionally allow `[a-z0-9_-]`, so a scope's `:`, an
13
+ * audit action's `/` and an operation's `.` all become `_`. Anything else outside that alphabet does too, so a
14
+ * name is always one a client accepts — but a kit operation never needs it, and `AdminOperation` refuses one that
15
+ * would.
16
+ *
17
+ * **Once published, a tool name is permanent.** An agent references it in prompts and saved workflows, so this
18
+ * function's output for a given pair must never change. `toolName.test.ts` pins it.
19
+ */
20
+ export declare function controlPlaneToolName(capability: string, operation: string): string;
21
+ //# sourceMappingURL=toolName.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolName.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/discovery/toolName.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAElF"}
@@ -0,0 +1,25 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ //#region src/controlPlane/discovery/toolName.ts
4
+ /**
5
+ * The one place an MCP tool name is made (`docs/AGENT-ACCESS.md` §5) — for the control-plane server's tools, and
6
+ * for the app's own MCP endpoint's (`../../mcp/tools.ts`), so one rule names both servers' tools.
7
+ *
8
+ * **Derived, never hand-written.** A tool is `<capability>_<operation>`: the capability's name, which already
9
+ * partitions migrations, tables and error codes, and the operation the capability declared beside the route. Two
10
+ * capabilities both exposing `threads.list` cannot collide, and nothing about the route's path or scope — both of
11
+ * which move or are shared — reaches the name.
12
+ *
13
+ * **Neither existing separator survives.** MCP names conventionally allow `[a-z0-9_-]`, so a scope's `:`, an
14
+ * audit action's `/` and an operation's `.` all become `_`. Anything else outside that alphabet does too, so a
15
+ * name is always one a client accepts — but a kit operation never needs it, and `AdminOperation` refuses one that
16
+ * would.
17
+ *
18
+ * **Once published, a tool name is permanent.** An agent references it in prompts and saved workflows, so this
19
+ * function's output for a given pair must never change. `toolName.test.ts` pins it.
20
+ */
21
+ function controlPlaneToolName(capability, operation) {
22
+ return `${capability}_${operation}`.toLowerCase().replace(/[^a-z0-9_-]/g, "_");
23
+ }
24
+ //#endregion
25
+ export { controlPlaneToolName };
@@ -0,0 +1,78 @@
1
+ // SPDX-FileCopyrightText: 2026 Pithy
2
+ // SPDX-License-Identifier: MIT
3
+ import type { AuditCitation } from "../../audit/citations";
4
+ import type { ErasureAuditActions, ErasureHistoryRow } from "../../capability/erasure";
5
+ import type { PurgeSubject } from "../../capability/purge";
6
+ import type { ErasureAttestation, ErasurePeriodEntry } from "../http/responses";
7
+ /**
8
+ * **The erasure attestation, assembled (#823)** — pure functions over a subject's lifecycle rows and the audit events
9
+ * that name it, so every rule here is tested without a database.
10
+ *
11
+ * ## Which deletion
12
+ *
13
+ * A subject can be deleted, restored, and deleted again. The attestation is about the **deletion in force**: the
14
+ * first `deleted` row after the last `restored`. A subject whose last act was a restore has no erasure to attest.
15
+ * A hard deletion that brought a soft one forward writes a second `deleted` row in the same cycle, so the deletion
16
+ * reads as `hard` and comes due when the later row says.
17
+ *
18
+ * ## Where the purge stands
19
+ *
20
+ * `complete` once a `purged` row is written. `failed` when the last thing the purge wrote was its failure — a later
21
+ * pass that runs a step again puts it back `in_progress`. `scheduled` while nothing has run and the window is still
22
+ * open. `in_progress` otherwise. **Overdue** is not a state: a purge not complete two days after it came due has
23
+ * missed a daily pass, whatever it last wrote, and is named with the step it stopped at.
24
+ *
25
+ * ## A step run twice
26
+ *
27
+ * The daily pass is the purge's outer retry, so a failed purge's steps run again the next day and record again.
28
+ * Each capability is shown once, in the order it first ran, as it last finished.
29
+ */
30
+ /** How long after coming due a purge that has not completed is overdue: two daily passes. */
31
+ export declare const ERASURE_OVERDUE_AFTER_MS: number;
32
+ /** The step a purge that has run nothing is named as having stopped at. */
33
+ export declare const ERASURE_NOT_STARTED = "due";
34
+ /** The rows of the deletion in force, or `null` when there is none — never deleted, or restored since. */
35
+ export declare function deletionInForce(rows: readonly ErasureHistoryRow[]): ErasureHistoryRow[] | null;
36
+ /** What one subject's attestation is assembled from. */
37
+ export interface AttestInput {
38
+ /** The kind of subject. */
39
+ readonly subject: PurgeSubject;
40
+ /** Its id. */
41
+ readonly subjectId: string;
42
+ /** Its lifecycle rows, oldest first. */
43
+ readonly rows: readonly ErasureHistoryRow[];
44
+ /** The audit events naming it, or `null` when no audit is composed. */
45
+ readonly citations: readonly AuditCitation[] | null;
46
+ /** The actions its purge records. */
47
+ readonly actions: ErasureAuditActions;
48
+ /** Now. */
49
+ readonly now: Date;
50
+ }
51
+ /** One subject's attestation, or `null` when it has no deletion in force. */
52
+ export declare function attest(input: AttestInput): ErasureAttestation | null;
53
+ /** One attestation, summarized for the period read. */
54
+ export declare function periodEntry(attestation: ErasureAttestation): ErasurePeriodEntry;
55
+ /** The period's counts and the purges that need someone, from its entries. */
56
+ export declare function summarize(entries: readonly ErasurePeriodEntry[]): {
57
+ counts: {
58
+ scheduled: number;
59
+ inProgress: number;
60
+ complete: number;
61
+ failed: number;
62
+ overdue: number;
63
+ };
64
+ attention: {
65
+ subject: {
66
+ type: "organization" | "user";
67
+ id: string;
68
+ };
69
+ state: "complete" | "failed" | "in_progress" | "scheduled";
70
+ overdue: boolean;
71
+ purgeAfter: string | null;
72
+ completedAt: string | null;
73
+ stoppedAt: string | null;
74
+ }[];
75
+ };
76
+ /** Every entry, oldest due first; a deletion recorded before #823 has no due instant and sorts last. */
77
+ export declare function byDue(entries: readonly ErasurePeriodEntry[]): ErasurePeriodEntry[];
78
+ //# sourceMappingURL=attest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attest.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/erasure/attest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EACV,kBAAkB,EAElB,kBAAkB,EAGnB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,6FAA6F;AAC7F,eAAO,MAAM,wBAAwB,QAAiB,CAAC;AAEvD,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC,0GAA0G;AAC1G,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,iBAAiB,EAAE,GAAG,iBAAiB,EAAE,GAAG,IAAI,CAQ9F;AAwBD,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,2BAA2B;IAC3B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,cAAc;IACd,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wCAAwC;IACxC,QAAQ,CAAC,IAAI,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC5C,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAAC;IACpD,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,WAAW;IACX,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;CACpB;AAED,6EAA6E;AAC7E,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,kBAAkB,GAAG,IAAI,CA8DpE;AAiBD,uDAAuD;AACvD,wBAAgB,WAAW,CAAC,WAAW,EAAE,kBAAkB,GAAG,kBAAkB,CAS/E;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE;;;;;;;;;;;;;;;;;;;EAW/D;AAED,wGAAwG;AACxG,wBAAgB,KAAK,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,kBAAkB,EAAE,CAIlF"}