primitive-admin 1.1.0-alpha.9 → 1.1.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 (591) hide show
  1. package/README.md +523 -109
  2. package/assets/skill/skills/primitive-platform/SKILL.md +289 -0
  3. package/dist/bin/primitive.d.ts +2 -0
  4. package/dist/bin/primitive.js +372 -21
  5. package/dist/bin/primitive.js.map +1 -1
  6. package/dist/src/commands/admins.d.ts +2 -0
  7. package/dist/src/commands/admins.js +136 -30
  8. package/dist/src/commands/admins.js.map +1 -1
  9. package/dist/src/commands/analytics.d.ts +2 -0
  10. package/dist/src/commands/analytics.js +713 -55
  11. package/dist/src/commands/analytics.js.map +1 -1
  12. package/dist/src/commands/apps.d.ts +2 -0
  13. package/dist/src/commands/apps.js +65 -100
  14. package/dist/src/commands/apps.js.map +1 -1
  15. package/dist/src/commands/auth-sessions.d.ts +7 -0
  16. package/dist/src/commands/auth-sessions.js +144 -0
  17. package/dist/src/commands/auth-sessions.js.map +1 -0
  18. package/dist/src/commands/auth.d.ts +2 -0
  19. package/dist/src/commands/auth.js +238 -108
  20. package/dist/src/commands/auth.js.map +1 -1
  21. package/dist/src/commands/blob-buckets.d.ts +2 -0
  22. package/dist/src/commands/blob-buckets.js +331 -0
  23. package/dist/src/commands/blob-buckets.js.map +1 -0
  24. package/dist/src/commands/catalog.d.ts +2 -0
  25. package/dist/src/commands/catalog.js +63 -48
  26. package/dist/src/commands/catalog.js.map +1 -1
  27. package/dist/src/commands/collection-type-configs.d.ts +2 -0
  28. package/dist/src/commands/collection-type-configs.js +85 -0
  29. package/dist/src/commands/collection-type-configs.js.map +1 -0
  30. package/dist/src/commands/collections.d.ts +2 -0
  31. package/dist/src/commands/collections.js +1282 -0
  32. package/dist/src/commands/collections.js.map +1 -0
  33. package/dist/src/commands/comparisons.d.ts +2 -0
  34. package/dist/src/commands/comparisons.js +6 -6
  35. package/dist/src/commands/comparisons.js.map +1 -1
  36. package/dist/src/commands/config.d.ts +46 -0
  37. package/dist/src/commands/config.js +465 -0
  38. package/dist/src/commands/config.js.map +1 -0
  39. package/dist/src/commands/connections.d.ts +2 -0
  40. package/dist/src/commands/connections.js +99 -0
  41. package/dist/src/commands/connections.js.map +1 -0
  42. package/dist/src/commands/cron-triggers.d.ts +2 -0
  43. package/dist/src/commands/cron-triggers.js +266 -0
  44. package/dist/src/commands/cron-triggers.js.map +1 -0
  45. package/dist/src/commands/database-type-configs.d.ts +2 -0
  46. package/dist/src/commands/database-type-configs.js +164 -0
  47. package/dist/src/commands/database-type-configs.js.map +1 -0
  48. package/dist/src/commands/database-types.d.ts +2 -0
  49. package/dist/src/commands/database-types.js +471 -0
  50. package/dist/src/commands/database-types.js.map +1 -0
  51. package/dist/src/commands/databases.d.ts +65 -0
  52. package/dist/src/commands/databases.js +1887 -243
  53. package/dist/src/commands/databases.js.map +1 -1
  54. package/dist/src/commands/documents.d.ts +60 -0
  55. package/dist/src/commands/documents.js +2888 -22
  56. package/dist/src/commands/documents.js.map +1 -1
  57. package/dist/src/commands/email-templates.d.ts +2 -0
  58. package/dist/src/commands/email-templates.js +175 -0
  59. package/dist/src/commands/email-templates.js.map +1 -0
  60. package/dist/src/commands/env.d.ts +23 -0
  61. package/dist/src/commands/env.js +395 -0
  62. package/dist/src/commands/env.js.map +1 -0
  63. package/dist/src/commands/feature-flags.d.ts +14 -0
  64. package/dist/src/commands/feature-flags.js +117 -0
  65. package/dist/src/commands/feature-flags.js.map +1 -0
  66. package/dist/src/commands/functions.d.ts +20 -0
  67. package/dist/src/commands/functions.js +1630 -0
  68. package/dist/src/commands/functions.js.map +1 -0
  69. package/dist/src/commands/group-type-configs.d.ts +2 -0
  70. package/dist/src/commands/group-type-configs.js +87 -0
  71. package/dist/src/commands/group-type-configs.js.map +1 -0
  72. package/dist/src/commands/groups.d.ts +2 -0
  73. package/dist/src/commands/groups.js +65 -113
  74. package/dist/src/commands/groups.js.map +1 -1
  75. package/dist/src/commands/guides.d.ts +223 -0
  76. package/dist/src/commands/guides.js +627 -69
  77. package/dist/src/commands/guides.js.map +1 -1
  78. package/dist/src/commands/init.d.ts +37 -0
  79. package/dist/src/commands/init.js +1693 -208
  80. package/dist/src/commands/init.js.map +1 -1
  81. package/dist/src/commands/integrations.d.ts +2 -0
  82. package/dist/src/commands/integrations.js +428 -187
  83. package/dist/src/commands/integrations.js.map +1 -1
  84. package/dist/src/commands/llm.d.ts +2 -0
  85. package/dist/src/commands/llm.js +4 -2
  86. package/dist/src/commands/llm.js.map +1 -1
  87. package/dist/src/commands/locks.d.ts +8 -0
  88. package/dist/src/commands/locks.js +175 -0
  89. package/dist/src/commands/locks.js.map +1 -0
  90. package/dist/src/commands/metadata-category-configs.d.ts +12 -0
  91. package/dist/src/commands/metadata-category-configs.js +113 -0
  92. package/dist/src/commands/metadata-category-configs.js.map +1 -0
  93. package/dist/src/commands/metadata.d.ts +2 -0
  94. package/dist/src/commands/metadata.js +288 -0
  95. package/dist/src/commands/metadata.js.map +1 -0
  96. package/dist/src/commands/prompts.d.ts +2 -0
  97. package/dist/src/commands/prompts.js +322 -634
  98. package/dist/src/commands/prompts.js.map +1 -1
  99. package/dist/src/commands/rule-sets.d.ts +3 -0
  100. package/dist/src/commands/rule-sets.js +139 -148
  101. package/dist/src/commands/rule-sets.js.map +1 -1
  102. package/dist/src/commands/scripts.d.ts +30 -0
  103. package/dist/src/commands/scripts.js +688 -0
  104. package/dist/src/commands/scripts.js.map +1 -0
  105. package/dist/src/commands/secrets.d.ts +2 -0
  106. package/dist/src/commands/secrets.js +109 -0
  107. package/dist/src/commands/secrets.js.map +1 -0
  108. package/dist/src/commands/sessions.d.ts +2 -0
  109. package/dist/src/commands/sessions.js +76 -0
  110. package/dist/src/commands/sessions.js.map +1 -0
  111. package/dist/src/commands/skill.d.ts +2 -0
  112. package/dist/src/commands/skill.js +29 -0
  113. package/dist/src/commands/skill.js.map +1 -0
  114. package/dist/src/commands/sync-app-settings.d.ts +158 -0
  115. package/dist/src/commands/sync-app-settings.js +328 -0
  116. package/dist/src/commands/sync-app-settings.js.map +1 -0
  117. package/dist/src/commands/sync.d.ts +2670 -0
  118. package/dist/src/commands/sync.js +17144 -834
  119. package/dist/src/commands/sync.js.map +1 -1
  120. package/dist/src/commands/tokens.d.ts +2 -0
  121. package/dist/src/commands/tokens.js +132 -22
  122. package/dist/src/commands/tokens.js.map +1 -1
  123. package/dist/src/commands/users.d.ts +2 -0
  124. package/dist/src/commands/users.js +542 -24
  125. package/dist/src/commands/users.js.map +1 -1
  126. package/dist/src/commands/vars.d.ts +8 -0
  127. package/dist/src/commands/vars.js +97 -0
  128. package/dist/src/commands/vars.js.map +1 -0
  129. package/dist/src/commands/waitlist.d.ts +2 -0
  130. package/dist/src/commands/waitlist.js +12 -11
  131. package/dist/src/commands/waitlist.js.map +1 -1
  132. package/dist/src/commands/webhooks.d.ts +31 -0
  133. package/dist/src/commands/webhooks.js +633 -0
  134. package/dist/src/commands/webhooks.js.map +1 -0
  135. package/dist/src/commands/workflows.d.ts +88 -0
  136. package/dist/src/commands/workflows.js +1568 -742
  137. package/dist/src/commands/workflows.js.map +1 -1
  138. package/dist/src/lib/access-rule-display.d.ts +21 -0
  139. package/dist/src/lib/access-rule-display.js +34 -0
  140. package/dist/src/lib/access-rule-display.js.map +1 -0
  141. package/dist/src/lib/api-client.d.ts +2550 -0
  142. package/dist/src/lib/api-client.js +2503 -160
  143. package/dist/src/lib/api-client.js.map +1 -1
  144. package/dist/src/lib/app-settings-descriptor.d.ts +263 -0
  145. package/dist/src/lib/app-settings-descriptor.js +583 -0
  146. package/dist/src/lib/app-settings-descriptor.js.map +1 -0
  147. package/dist/src/lib/auth-flow.d.ts +8 -0
  148. package/dist/src/lib/batch.d.ts +26 -0
  149. package/dist/src/lib/batch.js +32 -0
  150. package/dist/src/lib/batch.js.map +1 -0
  151. package/dist/src/lib/block-layout.d.ts +160 -0
  152. package/dist/src/lib/block-layout.js +451 -0
  153. package/dist/src/lib/block-layout.js.map +1 -0
  154. package/dist/src/lib/block-selector.d.ts +58 -0
  155. package/dist/src/lib/block-selector.js +92 -0
  156. package/dist/src/lib/block-selector.js.map +1 -0
  157. package/dist/src/lib/canonical-json.d.ts +12 -0
  158. package/dist/src/lib/canonical-json.js +35 -0
  159. package/dist/src/lib/canonical-json.js.map +1 -0
  160. package/dist/src/lib/channel.d.ts +30 -0
  161. package/dist/src/lib/channel.js +68 -0
  162. package/dist/src/lib/channel.js.map +1 -0
  163. package/dist/src/lib/cli-manifest.d.ts +68 -0
  164. package/dist/src/lib/cli-manifest.js +71 -0
  165. package/dist/src/lib/cli-manifest.js.map +1 -0
  166. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +101 -0
  167. package/dist/src/lib/codegen-shared/generatedFiles.js +191 -0
  168. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -0
  169. package/dist/src/lib/codegen-shared/prettierStable.d.ts +262 -0
  170. package/dist/src/lib/codegen-shared/prettierStable.js +610 -0
  171. package/dist/src/lib/codegen-shared/prettierStable.js.map +1 -0
  172. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +38 -0
  173. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +46 -0
  174. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -0
  175. package/dist/src/lib/collection-export.d.ts +184 -0
  176. package/dist/src/lib/collection-export.js +252 -0
  177. package/dist/src/lib/collection-export.js.map +1 -0
  178. package/dist/src/lib/config-json-field.d.ts +28 -0
  179. package/dist/src/lib/config-json-field.js +56 -0
  180. package/dist/src/lib/config-json-field.js.map +1 -0
  181. package/dist/src/lib/config-object-descriptor.d.ts +127 -0
  182. package/dist/src/lib/config-object-descriptor.js +740 -0
  183. package/dist/src/lib/config-object-descriptor.js.map +1 -0
  184. package/dist/src/lib/config-payload.d.ts +92 -0
  185. package/dist/src/lib/config-payload.js +161 -0
  186. package/dist/src/lib/config-payload.js.map +1 -0
  187. package/dist/src/lib/config-surface.d.ts +141 -0
  188. package/dist/src/lib/config-surface.js +368 -0
  189. package/dist/src/lib/config-surface.js.map +1 -0
  190. package/dist/src/lib/config-toml.d.ts +10 -0
  191. package/dist/src/lib/config-toml.js +42 -0
  192. package/dist/src/lib/config-toml.js.map +1 -0
  193. package/dist/src/lib/config.d.ts +71 -0
  194. package/dist/src/lib/config.js +71 -68
  195. package/dist/src/lib/config.js.map +1 -1
  196. package/dist/src/lib/confirm-prompt.d.ts +83 -0
  197. package/dist/src/lib/confirm-prompt.js +110 -0
  198. package/dist/src/lib/confirm-prompt.js.map +1 -0
  199. package/dist/src/lib/constants.d.ts +11 -0
  200. package/dist/src/lib/constants.js +12 -0
  201. package/dist/src/lib/constants.js.map +1 -0
  202. package/dist/src/lib/crash-handlers.d.ts +20 -0
  203. package/dist/src/lib/crash-handlers.js +49 -0
  204. package/dist/src/lib/crash-handlers.js.map +1 -0
  205. package/dist/src/lib/credentials-store.d.ts +104 -0
  206. package/dist/src/lib/credentials-store.js +336 -0
  207. package/dist/src/lib/credentials-store.js.map +1 -0
  208. package/dist/src/lib/csv.d.ts +47 -0
  209. package/dist/src/lib/csv.js +172 -0
  210. package/dist/src/lib/csv.js.map +1 -0
  211. package/dist/src/lib/data-input.d.ts +23 -0
  212. package/dist/src/lib/data-input.js +50 -0
  213. package/dist/src/lib/data-input.js.map +1 -0
  214. package/dist/src/lib/db-codegen/dbFingerprint.d.ts +10 -0
  215. package/dist/src/lib/db-codegen/dbFingerprint.js +17 -0
  216. package/dist/src/lib/db-codegen/dbFingerprint.js.map +1 -0
  217. package/dist/src/lib/db-codegen/dbGenerator.d.ts +67 -0
  218. package/dist/src/lib/db-codegen/dbGenerator.js +170 -0
  219. package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -0
  220. package/dist/src/lib/db-codegen/dbNaming.d.ts +87 -0
  221. package/dist/src/lib/db-codegen/dbNaming.js +180 -0
  222. package/dist/src/lib/db-codegen/dbNaming.js.map +1 -0
  223. package/dist/src/lib/db-codegen/dbTemplates.d.ts +272 -0
  224. package/dist/src/lib/db-codegen/dbTemplates.js +480 -0
  225. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -0
  226. package/dist/src/lib/db-codegen/dbTsTypes.d.ts +73 -0
  227. package/dist/src/lib/db-codegen/dbTsTypes.js +139 -0
  228. package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -0
  229. package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
  230. package/dist/src/lib/db-codegen/dbTypeIR.js +525 -0
  231. package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
  232. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +112 -0
  233. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +211 -0
  234. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
  235. package/dist/src/lib/deprecation.d.ts +22 -0
  236. package/dist/src/lib/deprecation.js +43 -0
  237. package/dist/src/lib/deprecation.js.map +1 -0
  238. package/dist/src/lib/document-export-permissions.d.ts +30 -0
  239. package/dist/src/lib/document-export-permissions.js +54 -0
  240. package/dist/src/lib/document-export-permissions.js.map +1 -0
  241. package/dist/src/lib/document-ingest-artifact.d.ts +120 -0
  242. package/dist/src/lib/document-ingest-artifact.js +505 -0
  243. package/dist/src/lib/document-ingest-artifact.js.map +1 -0
  244. package/dist/src/lib/document-ingest-input.d.ts +51 -0
  245. package/dist/src/lib/document-ingest-input.js +132 -0
  246. package/dist/src/lib/document-ingest-input.js.map +1 -0
  247. package/dist/src/lib/document-ingest-rows.d.ts +137 -0
  248. package/dist/src/lib/document-ingest-rows.js +181 -0
  249. package/dist/src/lib/document-ingest-rows.js.map +1 -0
  250. package/dist/src/lib/document-ingest.d.ts +101 -0
  251. package/dist/src/lib/document-ingest.js +384 -0
  252. package/dist/src/lib/document-ingest.js.map +1 -0
  253. package/dist/src/lib/env-resolver-core.d.ts +258 -0
  254. package/dist/src/lib/env-resolver-core.js +447 -0
  255. package/dist/src/lib/env-resolver-core.js.map +1 -0
  256. package/dist/src/lib/env-resolver.d.ts +99 -0
  257. package/dist/src/lib/env-resolver.js +153 -0
  258. package/dist/src/lib/env-resolver.js.map +1 -0
  259. package/dist/src/lib/fetch.d.ts +5 -0
  260. package/dist/src/lib/function-bundle.d.ts +147 -0
  261. package/dist/src/lib/function-bundle.js +341 -0
  262. package/dist/src/lib/function-bundle.js.map +1 -0
  263. package/dist/src/lib/function-collect.d.ts +123 -0
  264. package/dist/src/lib/function-collect.js +610 -0
  265. package/dist/src/lib/function-collect.js.map +1 -0
  266. package/dist/src/lib/function-db-types.d.ts +202 -0
  267. package/dist/src/lib/function-db-types.js +870 -0
  268. package/dist/src/lib/function-db-types.js.map +1 -0
  269. package/dist/src/lib/function-document-types.d.ts +144 -0
  270. package/dist/src/lib/function-document-types.js +370 -0
  271. package/dist/src/lib/function-document-types.js.map +1 -0
  272. package/dist/src/lib/function-grants-preflight.d.ts +64 -0
  273. package/dist/src/lib/function-grants-preflight.js +105 -0
  274. package/dist/src/lib/function-grants-preflight.js.map +1 -0
  275. package/dist/src/lib/function-log-lines.d.ts +76 -0
  276. package/dist/src/lib/function-log-lines.js +160 -0
  277. package/dist/src/lib/function-log-lines.js.map +1 -0
  278. package/dist/src/lib/function-log-row.d.ts +29 -0
  279. package/dist/src/lib/function-log-row.js +73 -0
  280. package/dist/src/lib/function-log-row.js.map +1 -0
  281. package/dist/src/lib/function-log-tail.d.ts +132 -0
  282. package/dist/src/lib/function-log-tail.js +262 -0
  283. package/dist/src/lib/function-log-tail.js.map +1 -0
  284. package/dist/src/lib/function-run.d.ts +289 -0
  285. package/dist/src/lib/function-run.js +389 -0
  286. package/dist/src/lib/function-run.js.map +1 -0
  287. package/dist/src/lib/function-schema-codegen.d.ts +143 -0
  288. package/dist/src/lib/function-schema-codegen.js +420 -0
  289. package/dist/src/lib/function-schema-codegen.js.map +1 -0
  290. package/dist/src/lib/function-sync.d.ts +459 -0
  291. package/dist/src/lib/function-sync.js +1258 -0
  292. package/dist/src/lib/function-sync.js.map +1 -0
  293. package/dist/src/lib/function-trigger-listing.d.ts +27 -0
  294. package/dist/src/lib/function-trigger-listing.js +70 -0
  295. package/dist/src/lib/function-trigger-listing.js.map +1 -0
  296. package/dist/src/lib/function-typecheck.d.ts +86 -0
  297. package/dist/src/lib/function-typecheck.js +370 -0
  298. package/dist/src/lib/function-typecheck.js.map +1 -0
  299. package/dist/src/lib/function-versions.d.ts +122 -0
  300. package/dist/src/lib/function-versions.js +182 -0
  301. package/dist/src/lib/function-versions.js.map +1 -0
  302. package/dist/src/lib/generated-allowlist.d.ts +28 -0
  303. package/dist/src/lib/generated-allowlist.js +281 -0
  304. package/dist/src/lib/generated-allowlist.js.map +1 -0
  305. package/dist/src/lib/generated-config-surfaces.d.ts +2936 -0
  306. package/dist/src/lib/generated-config-surfaces.js +10569 -0
  307. package/dist/src/lib/generated-config-surfaces.js.map +1 -0
  308. package/dist/src/lib/generated-sdk-types.d.ts +12 -0
  309. package/dist/src/lib/generated-sdk-types.js +13 -0
  310. package/dist/src/lib/generated-sdk-types.js.map +1 -0
  311. package/dist/src/lib/generated-template-lint.d.ts +212 -0
  312. package/dist/src/lib/generated-template-lint.js +624 -0
  313. package/dist/src/lib/generated-template-lint.js.map +1 -0
  314. package/dist/src/lib/init-adopt.d.ts +16 -0
  315. package/dist/src/lib/init-adopt.js +34 -0
  316. package/dist/src/lib/init-adopt.js.map +1 -0
  317. package/dist/src/lib/init-assets.d.ts +39 -0
  318. package/dist/src/lib/init-assets.js +97 -0
  319. package/dist/src/lib/init-assets.js.map +1 -0
  320. package/dist/src/lib/init-client-platforms.d.ts +14 -0
  321. package/dist/src/lib/init-client-platforms.js +71 -0
  322. package/dist/src/lib/init-client-platforms.js.map +1 -0
  323. package/dist/src/lib/init-config.d.ts +98 -0
  324. package/dist/src/lib/init-config.js +186 -0
  325. package/dist/src/lib/init-config.js.map +1 -0
  326. package/dist/src/lib/init-email-redirect-uris.d.ts +37 -0
  327. package/dist/src/lib/init-email-redirect-uris.js +46 -0
  328. package/dist/src/lib/init-email-redirect-uris.js.map +1 -0
  329. package/dist/src/lib/init-ios-links.d.ts +91 -0
  330. package/dist/src/lib/init-ios-links.js +219 -0
  331. package/dist/src/lib/init-ios-links.js.map +1 -0
  332. package/dist/src/lib/init-plan.d.ts +80 -0
  333. package/dist/src/lib/init-plan.js +95 -0
  334. package/dist/src/lib/init-plan.js.map +1 -0
  335. package/dist/src/lib/init-production-env.d.ts +48 -0
  336. package/dist/src/lib/init-production-env.js +59 -0
  337. package/dist/src/lib/init-production-env.js.map +1 -0
  338. package/dist/src/lib/init-schema.d.ts +74 -0
  339. package/dist/src/lib/init-schema.js +358 -0
  340. package/dist/src/lib/init-schema.js.map +1 -0
  341. package/dist/src/lib/init-xcode.d.ts +34 -0
  342. package/dist/src/lib/init-xcode.js +138 -0
  343. package/dist/src/lib/init-xcode.js.map +1 -0
  344. package/dist/src/lib/integration-request-config.d.ts +30 -0
  345. package/dist/src/lib/integration-request-config.js +145 -0
  346. package/dist/src/lib/integration-request-config.js.map +1 -0
  347. package/dist/src/lib/integration-selector.d.ts +42 -0
  348. package/dist/src/lib/integration-selector.js +46 -0
  349. package/dist/src/lib/integration-selector.js.map +1 -0
  350. package/dist/src/lib/ios-app-id.d.ts +34 -0
  351. package/dist/src/lib/ios-app-id.js +69 -0
  352. package/dist/src/lib/ios-app-id.js.map +1 -0
  353. package/dist/src/lib/list-options.d.ts +68 -0
  354. package/dist/src/lib/list-options.js +89 -0
  355. package/dist/src/lib/list-options.js.map +1 -0
  356. package/dist/src/lib/local-state.d.ts +55 -0
  357. package/dist/src/lib/local-state.js +167 -0
  358. package/dist/src/lib/local-state.js.map +1 -0
  359. package/dist/src/lib/local-test-cases.d.ts +63 -0
  360. package/dist/src/lib/local-test-cases.js +136 -0
  361. package/dist/src/lib/local-test-cases.js.map +1 -0
  362. package/dist/src/lib/log-inspection.d.ts +715 -0
  363. package/dist/src/lib/log-inspection.js +816 -0
  364. package/dist/src/lib/log-inspection.js.map +1 -0
  365. package/dist/src/lib/logout-admin-session.d.ts +33 -0
  366. package/dist/src/lib/logout-admin-session.js +70 -0
  367. package/dist/src/lib/logout-admin-session.js.map +1 -0
  368. package/dist/src/lib/migration-nag.d.ts +49 -0
  369. package/dist/src/lib/migration-nag.js +163 -0
  370. package/dist/src/lib/migration-nag.js.map +1 -0
  371. package/dist/src/lib/object-status-filter.d.ts +22 -0
  372. package/dist/src/lib/object-status-filter.js +45 -0
  373. package/dist/src/lib/object-status-filter.js.map +1 -0
  374. package/dist/src/lib/output.d.ts +124 -0
  375. package/dist/src/lib/output.js +219 -8
  376. package/dist/src/lib/output.js.map +1 -1
  377. package/dist/src/lib/package-manager.d.ts +140 -0
  378. package/dist/src/lib/package-manager.js +305 -0
  379. package/dist/src/lib/package-manager.js.map +1 -0
  380. package/dist/src/lib/paginate.d.ts +98 -0
  381. package/dist/src/lib/paginate.js +112 -0
  382. package/dist/src/lib/paginate.js.map +1 -0
  383. package/dist/src/lib/platform-owned.d.ts +63 -0
  384. package/dist/src/lib/platform-owned.js +85 -0
  385. package/dist/src/lib/platform-owned.js.map +1 -0
  386. package/dist/src/lib/project-config.d.ts +122 -0
  387. package/dist/src/lib/project-config.js +244 -0
  388. package/dist/src/lib/project-config.js.map +1 -0
  389. package/dist/src/lib/prompt-cost-format.d.ts +11 -0
  390. package/dist/src/lib/prompt-cost-format.js +41 -0
  391. package/dist/src/lib/prompt-cost-format.js.map +1 -0
  392. package/dist/src/lib/prompt-schema-codegen.d.ts +147 -0
  393. package/dist/src/lib/prompt-schema-codegen.js +462 -0
  394. package/dist/src/lib/prompt-schema-codegen.js.map +1 -0
  395. package/dist/src/lib/query-operators.d.ts +43 -0
  396. package/dist/src/lib/query-operators.js +80 -0
  397. package/dist/src/lib/query-operators.js.map +1 -0
  398. package/dist/src/lib/record-filter.d.ts +18 -0
  399. package/dist/src/lib/record-filter.js +55 -0
  400. package/dist/src/lib/record-filter.js.map +1 -0
  401. package/dist/src/lib/refresh-admin-credentials.d.ts +73 -0
  402. package/dist/src/lib/refresh-admin-credentials.js +123 -0
  403. package/dist/src/lib/refresh-admin-credentials.js.map +1 -0
  404. package/dist/src/lib/resolve-init-dev-port.d.ts +56 -0
  405. package/dist/src/lib/resolve-init-dev-port.js +55 -0
  406. package/dist/src/lib/resolve-init-dev-port.js.map +1 -0
  407. package/dist/src/lib/resolve-init-server.d.ts +64 -0
  408. package/dist/src/lib/resolve-init-server.js +77 -0
  409. package/dist/src/lib/resolve-init-server.js.map +1 -0
  410. package/dist/src/lib/resolve-owner.d.ts +19 -0
  411. package/dist/src/lib/resolve-owner.js +20 -0
  412. package/dist/src/lib/resolve-owner.js.map +1 -0
  413. package/dist/src/lib/resolve-platform.d.ts +74 -0
  414. package/dist/src/lib/resolve-platform.js +105 -0
  415. package/dist/src/lib/resolve-platform.js.map +1 -0
  416. package/dist/src/lib/run-status.d.ts +19 -0
  417. package/dist/src/lib/run-status.generated.d.ts +39 -0
  418. package/dist/src/lib/run-status.generated.js +66 -0
  419. package/dist/src/lib/run-status.generated.js.map +1 -0
  420. package/dist/src/lib/run-status.js +19 -0
  421. package/dist/src/lib/run-status.js.map +1 -0
  422. package/dist/src/lib/server-text-normalization.d.ts +51 -0
  423. package/dist/src/lib/server-text-normalization.js +90 -0
  424. package/dist/src/lib/server-text-normalization.js.map +1 -0
  425. package/dist/src/lib/server-url.d.ts +22 -0
  426. package/dist/src/lib/server-url.js +33 -0
  427. package/dist/src/lib/server-url.js.map +1 -0
  428. package/dist/src/lib/signing-secret-status.d.ts +81 -0
  429. package/dist/src/lib/signing-secret-status.js +116 -0
  430. package/dist/src/lib/signing-secret-status.js.map +1 -0
  431. package/dist/src/lib/skill-installer.d.ts +71 -0
  432. package/dist/src/lib/skill-installer.js +441 -0
  433. package/dist/src/lib/skill-installer.js.map +1 -0
  434. package/dist/src/lib/snapshot-audit-source.d.ts +45 -0
  435. package/dist/src/lib/snapshot-audit-source.js +58 -0
  436. package/dist/src/lib/snapshot-audit-source.js.map +1 -0
  437. package/dist/src/lib/snapshot-audit-store.d.ts +52 -0
  438. package/dist/src/lib/snapshot-audit-store.js +196 -0
  439. package/dist/src/lib/snapshot-audit-store.js.map +1 -0
  440. package/dist/src/lib/snapshot-audit.d.ts +207 -0
  441. package/dist/src/lib/snapshot-audit.js +431 -0
  442. package/dist/src/lib/snapshot-audit.js.map +1 -0
  443. package/dist/src/lib/snapshot-build-rows.d.ts +60 -0
  444. package/dist/src/lib/snapshot-build-rows.js +87 -0
  445. package/dist/src/lib/snapshot-build-rows.js.map +1 -0
  446. package/dist/src/lib/snapshot-build.d.ts +50 -0
  447. package/dist/src/lib/snapshot-build.js +111 -0
  448. package/dist/src/lib/snapshot-build.js.map +1 -0
  449. package/dist/src/lib/snapshot-manifest-layout.d.ts +61 -0
  450. package/dist/src/lib/snapshot-manifest-layout.js +70 -0
  451. package/dist/src/lib/snapshot-manifest-layout.js.map +1 -0
  452. package/dist/src/lib/snapshots.d.ts +98 -0
  453. package/dist/src/lib/snapshots.js +294 -0
  454. package/dist/src/lib/snapshots.js.map +1 -0
  455. package/dist/src/lib/step-run-table.d.ts +43 -0
  456. package/dist/src/lib/step-run-table.js +129 -0
  457. package/dist/src/lib/step-run-table.js.map +1 -0
  458. package/dist/src/lib/storage-pending-retry.d.ts +26 -0
  459. package/dist/src/lib/storage-pending-retry.js +42 -0
  460. package/dist/src/lib/storage-pending-retry.js.map +1 -0
  461. package/dist/src/lib/swift-codegen/agentGenerator.d.ts +42 -0
  462. package/dist/src/lib/swift-codegen/agentGenerator.js +118 -0
  463. package/dist/src/lib/swift-codegen/agentGenerator.js.map +1 -0
  464. package/dist/src/lib/swift-codegen/banners.d.ts +24 -0
  465. package/dist/src/lib/swift-codegen/banners.js +25 -0
  466. package/dist/src/lib/swift-codegen/banners.js.map +1 -0
  467. package/dist/src/lib/swift-codegen/dbGenerator.d.ts +113 -0
  468. package/dist/src/lib/swift-codegen/dbGenerator.js +926 -0
  469. package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
  470. package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
  471. package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
  472. package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
  473. package/dist/src/lib/swift-codegen/functionGenerator.d.ts +139 -0
  474. package/dist/src/lib/swift-codegen/functionGenerator.js +462 -0
  475. package/dist/src/lib/swift-codegen/functionGenerator.js.map +1 -0
  476. package/dist/src/lib/swift-codegen/generator.d.ts +100 -0
  477. package/dist/src/lib/swift-codegen/generator.js +457 -0
  478. package/dist/src/lib/swift-codegen/generator.js.map +1 -0
  479. package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +87 -0
  480. package/dist/src/lib/swift-codegen/schemaToSwift.js +661 -0
  481. package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
  482. package/dist/src/lib/swift-codegen/siblingSymbols.d.ts +94 -0
  483. package/dist/src/lib/swift-codegen/siblingSymbols.js +155 -0
  484. package/dist/src/lib/swift-codegen/siblingSymbols.js.map +1 -0
  485. package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
  486. package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
  487. package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
  488. package/dist/src/lib/sync-dir-selector.d.ts +21 -0
  489. package/dist/src/lib/sync-dir-selector.js +30 -0
  490. package/dist/src/lib/sync-dir-selector.js.map +1 -0
  491. package/dist/src/lib/sync-paths.d.ts +128 -0
  492. package/dist/src/lib/sync-paths.js +195 -0
  493. package/dist/src/lib/sync-paths.js.map +1 -0
  494. package/dist/src/lib/sync-resource-types.d.ts +563 -0
  495. package/dist/src/lib/sync-resource-types.js +1073 -0
  496. package/dist/src/lib/sync-resource-types.js.map +1 -0
  497. package/dist/src/lib/sync-selectors.d.ts +138 -0
  498. package/dist/src/lib/sync-selectors.js +289 -0
  499. package/dist/src/lib/sync-selectors.js.map +1 -0
  500. package/dist/src/lib/template.d.ts +170 -0
  501. package/dist/src/lib/template.js +484 -68
  502. package/dist/src/lib/template.js.map +1 -1
  503. package/dist/src/lib/test-case-file-names.d.ts +40 -0
  504. package/dist/src/lib/test-case-file-names.js +91 -0
  505. package/dist/src/lib/test-case-file-names.js.map +1 -0
  506. package/dist/src/lib/test-case-keys.d.ts +29 -0
  507. package/dist/src/lib/test-case-keys.js +55 -0
  508. package/dist/src/lib/test-case-keys.js.map +1 -0
  509. package/dist/src/lib/test-case-variables.d.ts +29 -0
  510. package/dist/src/lib/test-case-variables.js +71 -0
  511. package/dist/src/lib/test-case-variables.js.map +1 -0
  512. package/dist/src/lib/token-inject.d.ts +56 -0
  513. package/dist/src/lib/token-inject.js +204 -0
  514. package/dist/src/lib/token-inject.js.map +1 -0
  515. package/dist/src/lib/toml-database-config.d.ts +123 -0
  516. package/dist/src/lib/toml-database-config.js +544 -0
  517. package/dist/src/lib/toml-database-config.js.map +1 -0
  518. package/dist/src/lib/toml-metadata-config.d.ts +151 -0
  519. package/dist/src/lib/toml-metadata-config.js +476 -0
  520. package/dist/src/lib/toml-metadata-config.js.map +1 -0
  521. package/dist/src/lib/toml-native-form.d.ts +46 -0
  522. package/dist/src/lib/toml-native-form.js +78 -0
  523. package/dist/src/lib/toml-native-form.js.map +1 -0
  524. package/dist/src/lib/toml-params-validator.d.ts +129 -0
  525. package/dist/src/lib/toml-params-validator.js +298 -0
  526. package/dist/src/lib/toml-params-validator.js.map +1 -0
  527. package/dist/src/lib/toml-scalar-edit.d.ts +43 -0
  528. package/dist/src/lib/toml-scalar-edit.js +283 -0
  529. package/dist/src/lib/toml-scalar-edit.js.map +1 -0
  530. package/dist/src/lib/user-selector.d.ts +24 -0
  531. package/dist/src/lib/user-selector.js +33 -0
  532. package/dist/src/lib/user-selector.js.map +1 -0
  533. package/dist/src/lib/version-check.d.ts +35 -0
  534. package/dist/src/lib/version-check.js +241 -0
  535. package/dist/src/lib/version-check.js.map +1 -0
  536. package/dist/src/lib/watch.d.ts +121 -0
  537. package/dist/src/lib/watch.js +169 -0
  538. package/dist/src/lib/watch.js.map +1 -0
  539. package/dist/src/lib/web-url.d.ts +40 -0
  540. package/dist/src/lib/web-url.js +76 -0
  541. package/dist/src/lib/web-url.js.map +1 -0
  542. package/dist/src/lib/webhook-deliver.d.ts +209 -0
  543. package/dist/src/lib/webhook-deliver.js +519 -0
  544. package/dist/src/lib/webhook-deliver.js.map +1 -0
  545. package/dist/src/lib/workflow-apply.d.ts +110 -0
  546. package/dist/src/lib/workflow-apply.js +164 -0
  547. package/dist/src/lib/workflow-apply.js.map +1 -0
  548. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.d.ts +129 -0
  549. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js +269 -0
  550. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js.map +1 -0
  551. package/dist/src/lib/workflow-codegen/generator.d.ts +96 -0
  552. package/dist/src/lib/workflow-codegen/generator.js +361 -0
  553. package/dist/src/lib/workflow-codegen/generator.js.map +1 -0
  554. package/dist/src/lib/workflow-codegen/invokerIR.d.ts +94 -0
  555. package/dist/src/lib/workflow-codegen/invokerIR.js +76 -0
  556. package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
  557. package/dist/src/lib/workflow-codegen/naming.d.ts +33 -0
  558. package/dist/src/lib/workflow-codegen/naming.js +81 -0
  559. package/dist/src/lib/workflow-codegen/naming.js.map +1 -0
  560. package/dist/src/lib/workflow-codegen/schemaToTs.d.ts +80 -0
  561. package/dist/src/lib/workflow-codegen/schemaToTs.js +303 -0
  562. package/dist/src/lib/workflow-codegen/schemaToTs.js.map +1 -0
  563. package/dist/src/lib/workflow-config-apply.d.ts +70 -0
  564. package/dist/src/lib/workflow-config-apply.js +137 -0
  565. package/dist/src/lib/workflow-config-apply.js.map +1 -0
  566. package/dist/src/lib/workflow-config-sidecar.d.ts +63 -0
  567. package/dist/src/lib/workflow-config-sidecar.js +96 -0
  568. package/dist/src/lib/workflow-config-sidecar.js.map +1 -0
  569. package/dist/src/lib/workflow-defaults.d.ts +29 -0
  570. package/dist/src/lib/workflow-defaults.js +41 -0
  571. package/dist/src/lib/workflow-defaults.js.map +1 -0
  572. package/dist/src/lib/workflow-fragments.d.ts +64 -0
  573. package/dist/src/lib/workflow-fragments.js +342 -0
  574. package/dist/src/lib/workflow-fragments.js.map +1 -0
  575. package/dist/src/lib/workflow-include-preserve.d.ts +76 -0
  576. package/dist/src/lib/workflow-include-preserve.js +286 -0
  577. package/dist/src/lib/workflow-include-preserve.js.map +1 -0
  578. package/dist/src/lib/workflow-payload.d.ts +98 -0
  579. package/dist/src/lib/workflow-payload.js +178 -0
  580. package/dist/src/lib/workflow-payload.js.map +1 -0
  581. package/dist/src/lib/workflow-toml-validator.d.ts +211 -0
  582. package/dist/src/lib/workflow-toml-validator.js +770 -0
  583. package/dist/src/lib/workflow-toml-validator.js.map +1 -0
  584. package/dist/src/lib/workflow-usage.d.ts +196 -0
  585. package/dist/src/lib/workflow-usage.js +310 -0
  586. package/dist/src/lib/workflow-usage.js.map +1 -0
  587. package/dist/src/types/index.d.ts +591 -0
  588. package/dist/src/validators.d.ts +65 -0
  589. package/dist/src/validators.js +64 -0
  590. package/dist/src/validators.js.map +1 -0
  591. package/package.json +34 -9
@@ -0,0 +1,2936 @@
1
+ /**
2
+ * GENERATED FILE — DO NOT EDIT BY HAND.
3
+ *
4
+ * Vendored from the canonical server modules under `src/config-surface/` — the
5
+ * ONE definition per configuration object (issue #2644). The server's
6
+ * create/update handlers and this copy read the same field surface, so the CLI's
7
+ * push payloads, pull serializers and TOML key validation cannot drift from what
8
+ * the server accepts.
9
+ *
10
+ * Regenerate with:
11
+ * node cli/scripts/gen-config-surfaces.mjs (runs automatically at CLI prebuild)
12
+ *
13
+ * A freshness guard (`gen-config-surfaces.mjs --check`, asserted by
14
+ * `cli/tests/unit/config-surface-drift-guard.test.ts`) fails if this committed
15
+ * copy does not match the source.
16
+ */
17
+ /**
18
+ * The one definition per configuration object (issue #2644).
19
+ *
20
+ * A "configuration object" is anything `primitive config` round-trips as
21
+ * config-as-code: workflows, prompts, integrations, webhooks, cron triggers,
22
+ * blob buckets, database types, rule sets, email templates, and the type
23
+ * configs. Every one of them used to write its field surface out by hand in at
24
+ * least three places — the server's create/update handler, the CLI's push
25
+ * payload builder, and the CLI's pull serializer — so adding a field to one and
26
+ * not the others failed silently: the field was simply absent, `config diff` could
27
+ * not see it, and a pull → push cycle cleared it server-side (#571, #807, #1081,
28
+ * #1172, #1177, #1972, #2635).
29
+ *
30
+ * These types describe that surface ONCE. The definitions live here on the
31
+ * server; the CLI vendors them at build time into
32
+ * `cli/src/lib/generated-config-surfaces.ts`
33
+ * (`cli/scripts/gen-config-surfaces.mjs`), the same server→CLI vendoring
34
+ * `gen-operation-def-descriptor.mjs` (#1544) already uses, so the published CLI
35
+ * still imports no server code at runtime.
36
+ *
37
+ * ── Scope: declarative classification and coverage ONLY ──────────────────
38
+ * Decision of record (#1976, 2026-07-23, carried forward at #2644's design
39
+ * gate): a definition records WHICH fields exist, whether each is part of the
40
+ * TOML surface, which modes the server accepts it in, and — for a field with
41
+ * real behavior — the NAME of the handler that owns that behavior. It never
42
+ * encodes the behavior itself, and no handler source is ever regex-scanned for
43
+ * field names. `pickWritableFields` replaces the key list, not the validation.
44
+ *
45
+ * ── Purity ───────────────────────────────────────────────────────────────
46
+ * Everything under `src/config-surface/` must stay importable by a build-time
47
+ * Node script with no Workers runtime: no `getAppModels`, no `withAppContext`,
48
+ * no `src/do-routing.ts`, no `env`. `cli/tests/unit/config-surface-drift-guard.test.ts`
49
+ * asserts the directory's import graph stays empty of those modules.
50
+ */
51
+ /** Value shape of a field on the wire and in TOML. Descriptive, not a parser. */
52
+ export type FieldType = "string" | "number" | "boolean" | "string[]" | "json";
53
+ /**
54
+ * Why a persisted field is not part of the TOML surface. `note` is required —
55
+ * absence from a hand-written list is never a decision (#2644 criterion 4).
56
+ */
57
+ export type NotExposed = {
58
+ kind: "server-owned";
59
+ note: string;
60
+ } | {
61
+ kind: "structural";
62
+ note: string;
63
+ /**
64
+ * Which create/update modes carry this key IN THE REQUEST BODY — the same
65
+ * statement `ConfigField.writableOn` makes about a field, for a key that
66
+ * is not part of the TOML field surface.
67
+ *
68
+ * Omitted means both, the common case for a sub-tree the body always
69
+ * carries (`rules`, `metadataManifest`, `config`). `[]` says the key
70
+ * never travels in the body at all: it is in the URL path or comes from
71
+ * the file name, so no request schema admits it. Being structural is a
72
+ * statement about the TOML surface and does not by itself make a key
73
+ * writable — a mode whose handler never reads the key is not declared
74
+ * for it, or the schema would accept a key the handler drops, which is
75
+ * the silent 200 criterion 9 exists to end.
76
+ */
77
+ requestModes?: readonly ("create" | "update")[];
78
+ } | {
79
+ kind: "secret";
80
+ note: string;
81
+ } | {
82
+ kind: "deprecated";
83
+ note: string;
84
+ };
85
+ export interface ConfigField {
86
+ /** `models.yaml` field name === the wire key on create/update. */
87
+ field: string;
88
+ /** Key inside the TOML table (often identical to `field`). */
89
+ tomlKey: string;
90
+ /**
91
+ * The SUB-TABLE inside this field's table that the key is authored under
92
+ * (#3626) — `tomlGroup: "chat"` means `[configs.chat].systemPrompt` rather
93
+ * than `systemPrompt` at the `[[configs]]` root.
94
+ *
95
+ * A statement of WHERE a key is authored and nothing else (#1976): the pull
96
+ * projection writes it there, the push builder reads it from there, the
97
+ * unknown-key check stops accepting it at the root, and the declared-type
98
+ * check labels it with the group. No behavior is attached, and the WIRE stays
99
+ * flat — the admin and app API bodies carry `systemPrompt` beside `questions`
100
+ * exactly as before, each its own typed column.
101
+ *
102
+ * Prompts are the first object to need it: a prompt declares a `kind` and a
103
+ * `[[configs]]` entry may carry only the block named by that kind, so the
104
+ * next kind (embeddings, rerank) is a group declaration plus its fields
105
+ * rather than another round of implicit discrimination.
106
+ *
107
+ * The group must be declared in the table's `tomlGroups`
108
+ * (`findBadTomlGroupDeclarations`).
109
+ *
110
+ * #3798 — a LIST names a key authored under more than one block: the six
111
+ * model settings an agent shares with chat are `["chat", "agent"]`. Push
112
+ * reads the key from whichever of its blocks the entry carries, and pull
113
+ * writes it under the block the caller names (the prompt's kind), the first
114
+ * one otherwise. Read it through `tomlGroupsOf`, never directly.
115
+ */
116
+ tomlGroup?: string | readonly string[];
117
+ type: FieldType;
118
+ /** "whenSet" omits the key on pull when the value is empty; see #1033's `emit`. */
119
+ emit: "always" | "whenSet";
120
+ /**
121
+ * Modes the SERVER accepts the field in — a statement about the handler's
122
+ * `hasOwnProperty` branches and nothing else. `["create"]` means update
123
+ * genuinely rejects/ignores it (e.g. an immutable key). It is NOT a place to
124
+ * record CLI call ordering: `syncCallable` is accepted on both create and
125
+ * update (`src/admin-api.ts` `createAppWorkflow` / `updateAppWorkflow`); the
126
+ * CLI's create-only send is a *sequencing* invariant owned by
127
+ * `applyWorkflowBody` (#807 — the deferred second PATCH is itself an update
128
+ * call, and would break if update rejected the field).
129
+ */
130
+ writableOn: readonly ("create" | "update")[];
131
+ /**
132
+ * Classification, not dispatch. "passthrough" = the accepted value is stored
133
+ * as-is. Otherwise the named handler owns validation, normalization and
134
+ * serialization for this field; the guard only asserts the export exists.
135
+ *
136
+ * A handler is named `"<repo-relative module path>#<exported name>"`, e.g.
137
+ * `"src/workflows/config/workflow-field-handlers.ts#normalizeWorkflowStatus"`.
138
+ * `cli/tests/unit/config-surface-drift-guard.test.ts` fails when the module or
139
+ * the export is missing (#2644 behavior 2b).
140
+ *
141
+ * `stage` says WHEN the handler runs, with exactly the meaning `RuleStage`
142
+ * gives a cross-field rule (#3375). Until this issue the slot named an owner
143
+ * and never said when, so intent criterion 5 — "a rule declared `preflight`
144
+ * is provably reached before the first mutating call" — could not cover a
145
+ * single-field rule at all. It is REQUIRED, so a new field handler cannot be
146
+ * declared without answering the question, and
147
+ * `findMalformedFieldValidationStages` closes the key set at
148
+ * `handler`/`stage`: the slot stays declarative like the field entry itself.
149
+ */
150
+ validation: "passthrough" | {
151
+ handler: string;
152
+ stage: RuleStage;
153
+ };
154
+ /**
155
+ * This field's declared type genuinely admits more than one TOML spelling
156
+ * (#2880 criterion 5).
157
+ *
158
+ * The declared type is the contract: a quoted number for a declared number
159
+ * is a validation error `config diff` and `config push` report identically,
160
+ * and neither coerces. A handful of fields are genuinely dual-encoded
161
+ * anyway — `temperature` and `topP` are `StringField`s the server stores as
162
+ * strings and returns parsed (#2869), so `"0.2"` and `0.2` describe one
163
+ * value — and for those the two spellings must compare EQUAL, or diff
164
+ * reports a `Modified` no push can clear.
165
+ *
166
+ * Recorded here rather than inferred from the type, so the carve-out is a
167
+ * decision with a reason attached instead of a rule that quietly widens to
168
+ * every number in the surface.
169
+ */
170
+ dualEncoded?: {
171
+ note: string;
172
+ };
173
+ /**
174
+ * The field is still accepted but deprecated, and `note` says what to use
175
+ * instead (#1815). Unlike `NotExposed`'s `deprecated` kind, the field stays
176
+ * on the TOML surface: it round-trips on pull and push exactly as before.
177
+ * The generated request schema marks the key `deprecated: true` in the
178
+ * published OpenAPI spec. `config push` does not read this note; any push
179
+ * warning for the field lives in the CLI's push preflight.
180
+ */
181
+ deprecated?: {
182
+ note: string;
183
+ };
184
+ /**
185
+ * The value the SERVER materializes when a create omits this key (#2880
186
+ * DSO-002).
187
+ *
188
+ * A hand-authored file that omits an optional field the server defaults —
189
+ * an integration's `timeoutMs`, a cron trigger's `timezone` — creates fine
190
+ * and then reads `Modified` forever: the server holds the default, the file
191
+ * holds nothing, and push's payload builder drops the absent key so the
192
+ * difference can never converge. Recording the default here lets the LOCAL
193
+ * side of the comparison apply the same value the server did.
194
+ *
195
+ * Only for a default the server assigns on CREATE and returns on read.
196
+ */
197
+ serverDefault?: string | number | boolean;
198
+ }
199
+ export interface ConfigTable {
200
+ /** TOML path, e.g. ["workflow"] for [workflow], ["configs"] for [[configs]]. */
201
+ tomlPath: readonly string[];
202
+ repeated: boolean;
203
+ /** The `models.yaml` model backing this table — the coverage anchor. */
204
+ model: string;
205
+ fields: readonly ConfigField[];
206
+ /**
207
+ * The CLOSED set of sub-table names this table's fields may be authored under
208
+ * (#3626), each with the reason it exists. A field's `tomlGroup` must name
209
+ * one of these, and a name declared here that no field uses is a failure —
210
+ * both checked by `findBadTomlGroupDeclarations`, the same rule `notExposed`
211
+ * follows one level down: absence from a hand-written list is never a
212
+ * decision.
213
+ *
214
+ * Omitted on every table whose keys are all authored at its root, which is
215
+ * all of them but `prompt`'s `[[configs]]`.
216
+ */
217
+ tomlGroups?: Readonly<Record<string, {
218
+ note: string;
219
+ }>>;
220
+ /** Every model field not in `fields`, with its reason. Coverage is exhaustive. */
221
+ notExposed: Readonly<Record<string, NotExposed>>;
222
+ /**
223
+ * TOML keys accepted inside this table that are NOT part of the write field
224
+ * surface — an author writes them, but some other machinery consumes them.
225
+ * Declared here so `config push`'s unrecognized-key rejection (#2644 criterion
226
+ * 6) does not reject a key the CLI itself emits, and so the reason is visible
227
+ * rather than implied.
228
+ */
229
+ tomlOnlyKeys: Readonly<Record<string, NotExposed>>;
230
+ /**
231
+ * Keys the create/update BODY carries that are not `models.yaml` fields at
232
+ * all — protocol keys such as the `expectedModifiedAt` optimistic-concurrency
233
+ * token. Declared here so phase 5's generated request schemas
234
+ * (`request-schema.ts`) accept them, with the reason visible rather than
235
+ * implied. Optional: most objects have none.
236
+ *
237
+ * `modes` records which handlers actually read the key, the same statement
238
+ * `ConfigField.writableOn` makes about a field. Omitted means both — the
239
+ * common case. A key the handler in this mode does not read is NOT declared
240
+ * for that mode: the schema would accept it and the handler would drop it,
241
+ * which is the silent 200 criterion 9 exists to end.
242
+ */
243
+ requestOnlyKeys?: Readonly<Record<string, {
244
+ note: string;
245
+ modes?: readonly ("create" | "update")[];
246
+ }>>;
247
+ /**
248
+ * Keys the server's GET response carries that are not `models.yaml` fields —
249
+ * derived flags and related payloads. Declared here so `config pull`'s
250
+ * unrecognized-key warning (#2644 criterion 6) reports genuinely unknown keys
251
+ * rather than every computed one.
252
+ */
253
+ responseOnlyKeys: Readonly<Record<string, NotExposed>>;
254
+ }
255
+ /**
256
+ * When a rule is decided (#3373, project `cli-server-rule-parity`).
257
+ *
258
+ * `preflight` = decidable from the authored files ALONE and enforced before the
259
+ * first mutating call on that surface's push path — which implies the handler's
260
+ * module lives under `src/config-surface/`, so the CLI runs the server's own
261
+ * copy through the vendored artifact rather than a second implementation.
262
+ * `apply` = it needs app state (does this secret exist, is this scheme's config
263
+ * valid under the environment's JWKS policy, per-app caps, key collisions) or
264
+ * has path semantics only the server can decide.
265
+ *
266
+ * Stage is a property of the (surface, rule) PAIR, not of the predicate: the
267
+ * same file-decidable check is `preflight` on a surface whose CLI path runs it
268
+ * and `apply` on one whose CLI path does not. Declaring `preflight` where no
269
+ * CLI call exists would make the registry promise a refusal that in fact lands
270
+ * mid-apply.
271
+ */
272
+ export type RuleStage = "preflight" | "apply";
273
+ /**
274
+ * The cross-field spelling of `RuleStage`, kept as an exported alias.
275
+ *
276
+ * #3373 named the type for the only slot that had a stage. #3375 gave
277
+ * `ConfigField.validation` one too, with the same meaning, so the canonical
278
+ * name is the general one — and this alias stays because it is part of the
279
+ * registry's published surface (`CrossFieldRule.stage`, the guard, every
280
+ * `crossFieldRulesForStage` caller) and renaming it would be a breaking change
281
+ * to buy a shorter name.
282
+ */
283
+ export type CrossFieldRuleStage = RuleStage;
284
+ /**
285
+ * One rule of a configuration object that spans more than one field — `durable
286
+ * = true` beside a webhook trigger, `runAs = "system"` beside a non-empty
287
+ * `accessRule`, an HMAC scheme with no `signingSecret`.
288
+ *
289
+ * Such a rule belongs to no single field, so `ConfigField.validation` has
290
+ * nowhere to put it; attaching it to one field arbitrarily would make the
291
+ * coverage claim a lie. Declaring it here makes the SET of a surface's rules
292
+ * enumerable, which is what lets `config push`'s two-stage contract be derived
293
+ * from the registry (`crossFieldRulesForStage`) instead of maintained by hand.
294
+ *
295
+ * Classification, not dispatch (#1976 decision of record, carried at #2644 and
296
+ * again here): the declaration names the ONE export that enforces the rule and
297
+ * says when it runs. Nothing reads it to decide what to call.
298
+ */
299
+ export interface CrossFieldRule {
300
+ /** Stable, kebab-case, unique within the surface: `^[a-z0-9][a-z0-9-]*$`. */
301
+ id: string;
302
+ /** One author-facing sentence: what the rule refuses, and why. */
303
+ description: string;
304
+ stage: CrossFieldRuleStage;
305
+ /**
306
+ * The ONE enforcement point, as `"<repo-relative module>#<export>"` — the
307
+ * same spelling `ConfigField.validation` uses, written with `enforcedBy()`.
308
+ * The module is repo-relative, starts with `src/` and ends in `.ts`; a
309
+ * `preflight` handler's module is under `src/config-surface/`.
310
+ */
311
+ handler: string;
312
+ }
313
+ /**
314
+ * ── The migrated-module convention (#3373) ────────────────────────────────
315
+ *
316
+ * Naming a handler cannot catch a NEW refusal added inside an already-claimed
317
+ * function: a ninth refusal inside an existing export changes no export, no
318
+ * type and no declaration. A rules module therefore carries an anchor, and
319
+ * `cli/tests/unit/config-surface-rules-guard-3373.test.ts` checks it:
320
+ *
321
+ * 1. The module exports exactly one `export const <NAME>_RULE_IDS = [...] as
322
+ * const;` — a literal array, because the union of its members is the whole
323
+ * point; `readonly string[]` widens it back to any string.
324
+ * 2. It derives `type <Name>RuleId = (typeof <NAME>_RULE_IDS)[number]` and
325
+ * defines ONE module-local constructor whose id parameter has that type.
326
+ * Every refusal is built through it, so a ninth refusal cannot compile
327
+ * without a ninth id, which must be in the list, which must match the
328
+ * surface declarations — checked in both directions.
329
+ * 3. No `throw` statement and no `message` object-literal key — in any of its
330
+ * three spellings, `message:`, `"message":` and the `{ ruleId, message }`
331
+ * shorthand — appears anywhere outside that constructor's body. This is
332
+ * the half the type system cannot carry: `throw new Error(...)` or
333
+ * `errors.push({ message })` bypasses the constructor while changing no
334
+ * export. Reading a refusal apart (`const { message } = refusal`) or
335
+ * passing one on (`refuse(id, message)`) is not building one, and passes.
336
+ *
337
+ * Migrating the existing rules modules to it is #3374's and later siblings'
338
+ * work; every new rules module ships with it.
339
+ */
340
+ export interface ConfigObjectSurface {
341
+ /** Matches the CLI's `SyncResourceType.label` — e.g. "workflow", "prompt". */
342
+ label: string;
343
+ tables: readonly ConfigTable[];
344
+ /**
345
+ * Top-level TOML keys the object's FILE carries besides its field tables —
346
+ * the authored sub-trees that travel on their own channel (`[[steps]]`,
347
+ * `[requestConfig]`, `[rules]`, `[models.*]`) and the declared-access
348
+ * manifest's `[metadata]` / `secrets` / `vars` fragments.
349
+ *
350
+ * `tomlOnlyKeys` says which keys are accepted INSIDE a table; this says which
351
+ * keys are accepted at the document root. Together they make `config push`'s
352
+ * rejection total (design gate, 2026-08-12: push rejects everything
353
+ * unrecognized): without it a typo'd table header — `[integraton]` — parsed
354
+ * to a root key nothing checked, so the file pushed as though the real table
355
+ * were empty and the TOML-owned fields inside it were CLEARED server-side.
356
+ *
357
+ * Every entry carries its reason, the same rule `notExposed` follows: a table
358
+ * that is simply absent from this map must not read as a decision.
359
+ */
360
+ tomlDocumentKeys: Readonly<Record<string, NotExposed>>;
361
+ /**
362
+ * Declares that this object HAS no TOML field table, with the reason —
363
+ * required when `tables` is empty and forbidden otherwise.
364
+ *
365
+ * `transform` is the case: a `.rhai` file's authored surface is the script
366
+ * body, so there is no key/value table to define. Saying so here is the same
367
+ * rule `notExposed` applies to a field, one level up: "absent from the
368
+ * registry" and "deliberately fieldless" must not look the same (#2644
369
+ * criterion 4).
370
+ */
371
+ noFieldTable?: {
372
+ note: string;
373
+ };
374
+ /**
375
+ * Every cross-field rule of this object (#3373). Non-empty when present, and
376
+ * mutually exclusive with `noCrossFieldRules`.
377
+ */
378
+ crossFieldRules?: readonly CrossFieldRule[];
379
+ /**
380
+ * Declares that this object HAS no cross-field rule, with the reason — the
381
+ * same rule `noFieldTable` applies to a field table, one level up. Absence of
382
+ * both slots means "not declared yet", which is what
383
+ * `CROSS_FIELD_RULES_UNMIGRATED` inventories; it must never read as "no
384
+ * rules".
385
+ */
386
+ noCrossFieldRules?: {
387
+ note: string;
388
+ };
389
+ }
390
+ /**
391
+ * Shared spellings used by every configuration-object definition (issue #2644).
392
+ *
393
+ * These live in one module for a mechanical reason as much as a stylistic one:
394
+ * `cli/scripts/gen-config-surfaces.mjs` concatenates the whole directory into a
395
+ * single vendored artifact, so a `const handler = …` declared per definition
396
+ * module would collide as a duplicate identifier the moment a second object was
397
+ * migrated.
398
+ *
399
+ * Pure: no models, no tenant context, no `env` (see `types.ts` §Purity).
400
+ */
401
+ /** Both write modes — the common case, spelled once. */
402
+ export declare const BOTH: readonly ("create" | "update")[];
403
+ /** Create only: an immutable key or a field the update handler ignores. */
404
+ export declare const CREATE_ONLY: readonly ("create" | "update")[];
405
+ /** Update only: a field the create handler assigns itself. */
406
+ export declare const UPDATE_ONLY: readonly ("create" | "update")[];
407
+ /**
408
+ * Name the handler that owns a field's validation, normalization and
409
+ * serialization, as `"<repo-relative module>#<export>"`. Classification only —
410
+ * the definition never dispatches through it (#1976 decision of record); the
411
+ * guard asserts the export exists so a renamed handler fails the CLI unit suite
412
+ * instead of leaving a dangling reference (#2644 behavior 2b).
413
+ *
414
+ * `stage` is REQUIRED (#3375): a field handler that does not say when it runs
415
+ * makes the same empty promise the cross-field slot made before #3373 — it
416
+ * names an owner, and criterion 5 has nothing to check. A `preflight` handler
417
+ * is reached from `cli/src/commands/sync.ts#runConfigPushPreflight` before the
418
+ * first mutating call, which `findUnreachedPreflightRules` proves statically;
419
+ * an `apply` handler is everything else.
420
+ */
421
+ export declare function handledBy(modulePath: string, exportName: string, stage: RuleStage): ConfigField["validation"];
422
+ /**
423
+ * Name the ONE export that enforces a cross-field rule, as
424
+ * `"<repo-relative module>#<export>"` — the sibling of `handledBy` for a rule
425
+ * that belongs to no single field (#3373). Classification only: the declaration
426
+ * never dispatches through it, and the guard asserts the export exists.
427
+ */
428
+ export declare function enforcedBy(modulePath: string, exportName: string): string;
429
+ /**
430
+ * The shape a migrated rules module builds its refusals in (#3373).
431
+ *
432
+ * `Id` is the union of the module's `*_RULE_IDS` list, so a new refusal branch
433
+ * cannot compile without naming an id — and a new id fails `cli-unit-tests`
434
+ * until a surface declares it. See `types.ts` §"The migrated-module convention".
435
+ */
436
+ export interface RuleRefusal<Id extends string = string> {
437
+ ruleId: Id;
438
+ message: string;
439
+ }
440
+ /**
441
+ * The declared-access manifest's top-level TOML keys (#1304, #1364).
442
+ *
443
+ * Five objects carry the same three-key fragment beside their field table —
444
+ * workflows, database types, and the group / collection / metadata-category
445
+ * configs — parsed by the one `parseDeclaredAccessManifestToml`. Spelling it
446
+ * once here keeps `config push`'s document-level rejection from disagreeing with
447
+ * itself object by object.
448
+ */
449
+ export declare const DECLARED_ACCESS_MANIFEST_KEYS: Readonly<Record<string, NotExposed>>;
450
+ /**
451
+ * The accepted-key half of a configuration object's definition (issue #2644).
452
+ *
453
+ * `pickWritableFields` answers exactly one question — "is this key writable on
454
+ * this object in this mode" — so a server handler stops naming the keys it
455
+ * accepts. What a present key MEANS stays with the per-field handler the
456
+ * definition names (spec §Contracts, decision of record #1976): the workflow
457
+ * `status` enum, the non-negative-integer coercion of the queue limits,
458
+ * `runAs`'s caller|system check, `parseWorkflowLock`, the `capabilities` array
459
+ * shape and the CEL parse of `accessRule` all stay where they are. The
460
+ * mechanical win is that a field can no longer be *absent* from the accepted
461
+ * set.
462
+ *
463
+ * Pure: no models, no tenant context, no `env` (see `types.ts` §Purity).
464
+ */
465
+ export type WriteMode = "create" | "update";
466
+ /** The field names this table accepts on the wire in `mode`, in declaration order. */
467
+ export declare function writableFieldNames(table: ConfigTable, mode: WriteMode): string[];
468
+ /**
469
+ * The field names the server PERSISTS for this table in `mode`: the writable
470
+ * fields, plus the `deprecated` classifications — "still writable, superseded
471
+ * by another field" is what that kind means (`types.ts`), so a superseded key
472
+ * a handler still honors (`accessPolicy`, `passkeyRpId`) belongs in every
473
+ * accepted set, and a field that is NOT writable belongs in none of them.
474
+ *
475
+ * Stated once here because three consumers need the same answer: the generated
476
+ * request schemas, `PUT /settings`'s write allow-list, and the guards.
477
+ */
478
+ export declare function acceptedWriteFieldNames(table: ConfigTable, mode: WriteMode): string[];
479
+ /**
480
+ * Split a request body into the keys this table accepts in `mode` and the keys
481
+ * it does not.
482
+ *
483
+ * `accepted` preserves the caller's values verbatim — including an explicit
484
+ * `null` or `false`, which are meaningful (clear / opt-out) and must not be
485
+ * coalesced away. Only keys the body actually carries appear, so a handler can
486
+ * keep using presence (`hasOwnProperty`) to distinguish "leave unset" from
487
+ * "set to null".
488
+ *
489
+ * `rejected` is every other key the body carried. Today it is informational;
490
+ * #2644 phase 5 turns it into a 400 through the generated request schemas.
491
+ */
492
+ export declare function pickWritableFields(body: Record<string, unknown>, table: ConfigTable, mode: WriteMode): {
493
+ accepted: Record<string, unknown>;
494
+ rejected: string[];
495
+ };
496
+ /**
497
+ * The PASSTHROUGH half of the accepted body: the keys this table declares
498
+ * `validation: "passthrough"`, writable in `mode`, that the body actually
499
+ * carries — with their values verbatim.
500
+ *
501
+ * This is what makes criterion 1 true rather than aspirational. A handler that
502
+ * only picked its accepted set still had to name each field again when it built
503
+ * the row to persist, so a scalar field added to a definition alone was
504
+ * accepted on the wire and then dropped on the floor. Handlers spread this into
505
+ * the create/update payload FIRST, so a field with real behavior still lands
506
+ * through its named handler (whose assignment comes after and wins), and a
507
+ * plain scalar needs no handler edit at all.
508
+ *
509
+ * Values are passed through untouched — including an explicit `null` or
510
+ * `false`, which are meaningful (clear / opt-out). "Stored as-is" is exactly
511
+ * what the `passthrough` classification promises.
512
+ */
513
+ export declare function passthroughFields(body: Record<string, unknown>, table: ConfigTable, mode: WriteMode, options?: {
514
+ /**
515
+ * Fields whose PRESENCE semantics this handler owns — it decides, per
516
+ * value, whether the key is written at all (a falsy `displayName` that
517
+ * means "leave the stored name alone"). Listing one here keeps the generic
518
+ * copy from changing what it means.
519
+ *
520
+ * This is never a place to list a field the handler does not assign: a
521
+ * field named here and dropped by the handler is written nowhere, which is
522
+ * the silent loss the definition exists to prevent. A NEW field needs no
523
+ * entry — omission is what makes it flow through.
524
+ */
525
+ handledHere?: readonly string[];
526
+ }): Record<string, unknown>;
527
+ /** `true` when the body carries `field` and this table accepts it in `mode`. */
528
+ export declare function hasWritableField(accepted: Record<string, unknown>, field: string): boolean;
529
+ /**
530
+ * Coverage checks over a configuration object's definition (issue #2644,
531
+ * criteria 2 and 4).
532
+ *
533
+ * A definition claims to describe its model's WHOLE field surface. These
534
+ * functions are what make that claim mean something: every `models.yaml` field
535
+ * is either exposed in TOML or classified `notExposed` with a reason, in both
536
+ * directions — a new field nobody classified, and a classification for a field
537
+ * that no longer exists. `cli/tests/unit/config-surface-drift-guard.test.ts`
538
+ * asserts them over every registered object, so coverage follows from being a
539
+ * configuration object rather than from someone adding a per-type guard.
540
+ *
541
+ * Pure: no models, no tenant context, no `env` (see `types.ts` §Purity).
542
+ */
543
+ /**
544
+ * `models.yaml` field names per model — the coverage anchor, passed in rather
545
+ * than read here so this module stays pure (the CLI's vendored artifact carries
546
+ * it as `GENERATED_CONFIG_MODEL_FIELDS`).
547
+ */
548
+ export type ModelFieldMap = Readonly<Record<string, readonly string[]>>;
549
+ /**
550
+ * Whether a value counts as unset for an `emit: "whenSet"` field, so `config pull`
551
+ * omits the key instead of writing a noisy empty one (and `config diff` does not
552
+ * report a difference that is not there).
553
+ *
554
+ * Carried over verbatim from #1033's shipped app-settings descriptor
555
+ * (`cli/src/lib/app-settings-descriptor.ts`): an empty array and an empty
556
+ * object are unset, while `false` and `0` are meaningful values and never are.
557
+ */
558
+ export declare function isEmptyForEmit(value: unknown, type: ConfigField["type"]): boolean;
559
+ /**
560
+ * A field name whose shape says it carries a credential. Such a field must be
561
+ * classified explicitly — exposed with a stated reference-only contract, or
562
+ * `notExposed: { kind: "secret" }` — because a mechanical generalization that
563
+ * merely omits it would read as "not decided" (#2254, #2256).
564
+ */
565
+ export declare const SECRETISH_FIELD: RegExp;
566
+ /** Model fields the table neither exposes nor classifies. Non-empty is a failure. */
567
+ export declare function findUnclassifiedFields(table: ConfigTable, modelFields: readonly string[]): string[];
568
+ /**
569
+ * Classifications that no longer correspond to a model field — i.e. a field
570
+ * removed from `models.yaml` while the definition still names it. Also a
571
+ * failure: a stale classification must not silently pass, or the coverage claim
572
+ * quietly stops meaning anything.
573
+ */
574
+ export declare function findStaleClassifications(table: ConfigTable, modelFields: readonly string[]): string[];
575
+ /** The models this surface's tables project, in declaration order, deduped. */
576
+ export declare function surfaceModels(surface: ConfigObjectSurface): string[];
577
+ /**
578
+ * Model fields the whole surface neither exposes nor classifies. Non-empty is
579
+ * a failure: the CLI would silently ignore them and a pull → push cycle would
580
+ * clear them (#2644 criterion 2).
581
+ */
582
+ export declare function findUnclassifiedSurfaceFields(surface: ConfigObjectSurface, modelFields: ModelFieldMap): string[];
583
+ /**
584
+ * Classifications naming a field the model no longer has — the other direction,
585
+ * and equally a failure: a stale entry quietly stops meaning anything.
586
+ */
587
+ export declare function findStaleSurfaceClassifications(surface: ConfigObjectSurface, modelFields: ModelFieldMap): string[];
588
+ /** Fields the surface both exposes and classifies `notExposed`. Ambiguous. */
589
+ export declare function findDoubleClassifiedSurfaceFields(surface: ConfigObjectSurface): string[];
590
+ /**
591
+ * Secret-adjacent model fields the surface leaves undecided — neither exposed
592
+ * with a stated contract nor classified `notExposed` (#2254, #2256).
593
+ */
594
+ export declare function findUnclassifiedSecretishSurfaceFields(surface: ConfigObjectSurface, modelFields: ModelFieldMap): string[];
595
+ /** Fields classified twice — exposed AND `notExposed`. Ambiguous, so a failure. */
596
+ export declare function findDoubleClassifiedFields(table: ConfigTable): string[];
597
+ /**
598
+ * `notExposed` / `tomlOnlyKeys` / `responseOnlyKeys` entries whose `note` is
599
+ * missing or blank. A reason is the whole point of the classification.
600
+ */
601
+ export declare function findReasonlessClassifications(table: ConfigTable): string[];
602
+ /**
603
+ * Secret-adjacent model fields with no explicit decision — neither an exposed
604
+ * entry nor a `notExposed` classification. A bare omission is the failure mode
605
+ * this catches.
606
+ */
607
+ export declare function findUnclassifiedSecretishFields(table: ConfigTable, modelFields: readonly string[]): string[];
608
+ /**
609
+ * Every distinct handler reference the table names, as
610
+ * `"<repo-relative module>#<export>"`. The guard resolves each one and fails
611
+ * when the module or the export is missing (#2644 behavior 2b).
612
+ */
613
+ export declare function handlerReferences(table: ConfigTable): string[];
614
+ /**
615
+ * The blocks a field is authored under, in declaration order: `[]` for a root
616
+ * key, one name for most grouped keys, several for a key two blocks share
617
+ * (#3798). Every reader of `tomlGroup` goes through this.
618
+ */
619
+ export declare function tomlGroupsOf(field: ConfigField): readonly string[];
620
+ /** The group names this table declares, sorted. Empty for an ungrouped table. */
621
+ export declare function tomlGroupNames(table: ConfigTable): string[];
622
+ /** The TOML keys accepted INSIDE `group`: every field that declares it. */
623
+ export declare function acceptedGroupTomlKeys(table: ConfigTable, group: string): Set<string>;
624
+ /**
625
+ * TOML keys this table accepts AT ITS ROOT: the UNGROUPED fields, the declared
626
+ * group names, and the declared extras.
627
+ *
628
+ * A grouped leaf written at the root (`questions` directly under `[[configs]]`)
629
+ * is therefore an unknown key rather than one the payload builder silently
630
+ * ignores (SO3626-013) — the builder reads a grouped field only from
631
+ * `source[group][tomlKey]`, so accepting it here would drop the author's value
632
+ * without a word. The nine deprecated flat chat keys stay accepted through
633
+ * their `tomlOnlyKeys` declarations, which is what keeps old files pushing.
634
+ */
635
+ export declare function acceptedTomlKeys(table: ConfigTable): Set<string>;
636
+ /**
637
+ * Keys inside a group table that no field declares under it, as
638
+ * `"<group>.<key>"` — plus the bare `"<group>"` for a group value that is not a
639
+ * table at all (`chat = "yes"`), which has no keys to check and would otherwise
640
+ * be read as an empty block.
641
+ */
642
+ export declare function findUnknownGroupedTomlKeys(tomlTable: unknown, table: ConfigTable): string[];
643
+ /**
644
+ * Group declarations that do not hold together: a field naming a group the
645
+ * table does not declare, a declared group no field is authored under, and a
646
+ * declaration with no reason. All three are failures, for the reason
647
+ * `notExposed` carries a note — a name in a list with nothing behind it reads
648
+ * as a decision and is not one.
649
+ */
650
+ export declare function findBadTomlGroupDeclarations(table: ConfigTable): string[];
651
+ /** Top-level TOML keys this object's file accepts: its tables plus the extras. */
652
+ export declare function acceptedTomlDocumentKeys(surface: ConfigObjectSurface): Set<string>;
653
+ /**
654
+ * `tomlDocumentKeys` entries with no reason, and any that merely restate a
655
+ * field table. Both are failures: a reason is the whole point of the
656
+ * classification, and a duplicate would let a table's shape check be bypassed
657
+ * by declaring it twice.
658
+ */
659
+ export declare function findBadDocumentKeyDeclarations(surface: ConfigObjectSurface): string[];
660
+ /** Root keys of `tomlData` the surface does not declare. `config push` rejects these. */
661
+ export declare function findUnknownTomlDocumentKeys(surface: ConfigObjectSurface, tomlData: unknown): string[];
662
+ export declare function findMisshapenTomlTables(surface: ConfigObjectSurface, tomlData: unknown): Array<{
663
+ key: string;
664
+ expected: "table" | "array of tables";
665
+ }>;
666
+ /**
667
+ * Server-response keys this table recognizes: every model field (exposed or
668
+ * not) plus the declared response-only keys. `config pull` warns about anything
669
+ * else instead of dropping it silently (#2644 criterion 6).
670
+ */
671
+ export declare function recognizedResponseKeys(table: ConfigTable, modelFields: readonly string[]): Set<string>;
672
+ /**
673
+ * Checks over a configuration object's CROSS-FIELD rule declarations (issue
674
+ * #3373, project `cli-server-rule-parity` phase 1).
675
+ *
676
+ * `coverage.ts` is the field-level twin: it makes "this definition describes the
677
+ * whole field surface" mean something. These functions do the same job one level
678
+ * up for rules — a declaration that is malformed, a rule id a module's
679
+ * `*_RULE_IDS` list does not carry, a list entry no surface declares, a refusal
680
+ * built outside its module's typed constructor, and a surface that has declared
681
+ * neither slot while being absent from the unmigrated inventory each return a
682
+ * failure line. `cli/tests/unit/config-surface-rules-guard-3373.test.ts` asserts
683
+ * them over the real registry and proves their teeth on synthetic inputs.
684
+ *
685
+ * Everything here is a PURE function over values and over module SOURCE TEXT
686
+ * passed in by the caller: the guard does the filesystem walk, so this module
687
+ * stays vendorable (see `types.ts` §Purity). Reading source text is the same
688
+ * kind of structural check the field guard already makes when it confirms a
689
+ * handler's export is declared — it never scans a handler for field names to
690
+ * infer behavior (#1976 decision of record).
691
+ */
692
+ /** The two stages a rule can be declared at, spelled once. */
693
+ export declare const CROSS_FIELD_RULE_STAGES: readonly CrossFieldRuleStage[];
694
+ /** A rule declaration's closed key set — it may not grow behavior knobs. */
695
+ export declare const CROSS_FIELD_RULE_KEYS: readonly string[];
696
+ /** Every rule handler lives on the server, under `src/`, in a `.ts` module. */
697
+ export declare const RULE_HANDLER_MODULE_PREFIX = "src/";
698
+ /** A `preflight` handler is vendored into the CLI, so it lives here. */
699
+ export declare const PREFLIGHT_HANDLER_MODULE_PREFIX = "src/config-surface/";
700
+ /** Rule ids are kebab-case and stable: they are cited in declarations. */
701
+ export declare const CROSS_FIELD_RULE_ID_PATTERN: RegExp;
702
+ /** The suffix that makes a module a rules module for the unclaimed-export check. */
703
+ export declare const RULES_MODULE_SUFFIX = "-rules.ts";
704
+ /**
705
+ * Is this module a rules module of THIS registry — `<name>-rules.ts` under
706
+ * `src/config-surface/`?
707
+ *
708
+ * The name is the opt-in: everything a rules module exports is a rule, so an
709
+ * export no surface declares is a rule with no declaration
710
+ * (`findUnclaimedRuleModuleExports`). Shared predicates and constants therefore
711
+ * live in a module that is not named `*-rules.ts` —
712
+ * `webhook-signing-secret.ts` exports `isWholeSecretReference` and its refusal
713
+ * codes, and must keep being able to.
714
+ *
715
+ * The directory is the other half of the key, and it is load-bearing:
716
+ * `src/services/app-secrets-rules.ts` is the app-secrets store's own key/value
717
+ * shape rules, written long before this convention and belonging to no
718
+ * configuration surface. The registry's rules modules live where the registry
719
+ * lives (project intent §Decisions, "Where does the registry live?"), which is
720
+ * also where a `preflight` handler has to be, so the name means one thing in
721
+ * one place instead of catching every module in the tree that ends in the same
722
+ * eight characters.
723
+ */
724
+ export declare function isRulesModulePath(modulePath: string): boolean;
725
+ /** One string literal of a module: where it sits, and what it says. */
726
+ export interface RuleModuleStringLiteral {
727
+ /** Index of the opening quote. */
728
+ start: number;
729
+ /** Index just past the closing quote. */
730
+ end: number;
731
+ /** The literal's raw content — escapes are left as written. */
732
+ value: string;
733
+ /** `"`, `'` or a backtick. */
734
+ quote: string;
735
+ }
736
+ /** A module's masked source plus every string literal the masker blanked. */
737
+ export interface RuleModuleLexis {
738
+ /** Comments, string contents and regex literals blanked, positions kept. */
739
+ masked: string;
740
+ /** The literals, in source order — a blanked `"message"` key is still one. */
741
+ strings: RuleModuleStringLiteral[];
742
+ }
743
+ /**
744
+ * Blank out comments, string-literal CONTENTS and regex literals, preserving
745
+ * every character position and every newline, so a regex over the result
746
+ * reports the same line numbers as the original and can never match prose, a
747
+ * quoted example, or a pattern.
748
+ *
749
+ * Regex literals are tracked because a perfectly ordinary validation pattern
750
+ * carries quotes — `/'/`, `/["']/` — and a masker that read that apostrophe as
751
+ * a string would blank the rest of the module, hiding every `throw` after it.
752
+ * That is a guard that silently stops looking, which is worse than no guard.
753
+ * A `/` that opens what turns out not to be a regex (no closing `/` before the
754
+ * line ends) is treated as division, so the masker never runs away.
755
+ *
756
+ * Template literals are scanned with their `${…}` interpolations lexed as code,
757
+ * so a nested backtick cannot end the literal early either.
758
+ */
759
+ export declare function lexRuleModuleSource(source: string): RuleModuleLexis;
760
+ /**
761
+ * The module's source with comments, string contents and regex literals blanked
762
+ * — the view every structural check reads, positions and line numbers intact.
763
+ */
764
+ export declare function maskRuleModuleSource(source: string): string;
765
+ /**
766
+ * Every fault in one surface's rule declaration, each naming the surface and
767
+ * what is wrong. `[]` means the declaration is well-formed — INCLUDING a
768
+ * surface that has declared neither slot, which is the unmigrated list's
769
+ * business (`findUnmigratedListDrift`), not a malformed declaration.
770
+ */
771
+ export declare function findMalformedRuleDeclarations(surface: ConfigObjectSurface): string[];
772
+ /**
773
+ * The same rule id declared on two surfaces with DIFFERENT handlers.
774
+ *
775
+ * One id naming one handler on two surfaces is deliberate — the signing-secret
776
+ * rule is one rule the webhook and function objects share — but one id naming
777
+ * two implementations is the drift this registry exists to end.
778
+ */
779
+ export declare function findCrossSurfaceRuleIdConflicts(surfaces: readonly ConfigObjectSurface[]): string[];
780
+ /** Declared rule ids per handler module — the declaration side of the anchor. */
781
+ export declare function declaredRuleIdsByModule(surfaces: readonly ConfigObjectSurface[]): Map<string, string[]>;
782
+ /** Every distinct `<module>#<export>` a surface's rules name, sorted. */
783
+ export declare function ruleHandlerReferences(surface: ConfigObjectSurface): string[];
784
+ /**
785
+ * Read every `export const X_RULE_IDS = [...] as const` out of module SOURCE.
786
+ *
787
+ * Static on purpose: an `apply`-stage handler lives in a server module the CLI's
788
+ * unit test must never import, and the list has to be readable anyway.
789
+ *
790
+ * The declaration is walked, not matched against one regex, for two reasons a
791
+ * guard cares about. A list is found whether or not the statement ends in a
792
+ * semicolon — under automatic semicolon insertion `…] as const` is the same
793
+ * declaration, and a module that dropped the semicolon must not drop out of
794
+ * discovery. And the ids are the module's real STRING LITERALS, so an id that
795
+ * has been commented out inside the array is not read as one: it is absent from
796
+ * the runtime list and from the union type, so a declaration still citing it
797
+ * has to fail.
798
+ */
799
+ export declare function parseRuleIdExports(source: string): {
800
+ lists: Array<{
801
+ name: string;
802
+ ids: string[];
803
+ }>;
804
+ errors: string[];
805
+ };
806
+ /**
807
+ * Refusals a migrated module builds OUTSIDE its typed constructor (DSO-001).
808
+ *
809
+ * The type-level half of the rule-id anchor — a constructor whose id parameter
810
+ * is the list's union — cannot see `throw new Error("ninth refusal")` or
811
+ * `errors.push({ message })`: both change no export and no type. This is the
812
+ * source-level half, and it applies only to a MIGRATED module (one that exports
813
+ * a `*_RULE_IDS` list), so an unmigrated module is untouched until its sibling
814
+ * issue migrates it.
815
+ *
816
+ * A refusal literal is caught in all three spellings a `message` property has —
817
+ * `message:`, `"message":` and the `{ ruleId, message }` shorthand — because a
818
+ * bypass that only had to be quoted differently would not be a guard.
819
+ */
820
+ export declare function findUnanchoredRefusals(source: string, listName?: string): string[];
821
+ /**
822
+ * Drift between the rule ids modules EXPORT and the ids surfaces DECLARE, in
823
+ * both directions. The first direction is the ninth-refusal case: a new id in a
824
+ * module's list that no surface declares fails until it is declared.
825
+ */
826
+ export declare function findRuleIdDrift(declared: ReadonlyMap<string, readonly string[]>, exported: ReadonlyMap<string, readonly string[]>): string[];
827
+ /**
828
+ * Exported rule functions in a registry rules module that no surface claims
829
+ * (intent §Success criteria 1). A rules module is where rules live; an export
830
+ * nothing declares is a rule running with no declaration. `[]` for anything
831
+ * `isRulesModulePath` does not recognize.
832
+ *
833
+ * Both spellings of an export count: `export function check()` and a later
834
+ * `export { check }` clause, alias included — how a rule reaches the module's
835
+ * surface is a style choice, and a guard that only saw one of the two would be
836
+ * satisfied by rewriting the other.
837
+ */
838
+ export declare function findUnclaimedRuleModuleExports(modulePath: string, source: string, claimedExports: readonly string[]): string[];
839
+ /**
840
+ * Drift between the shrink-only unmigrated inventory and the registry, in both
841
+ * directions: a listed label that is not a surface, a listed label that has
842
+ * already declared, a surface that has declared neither slot and is not listed,
843
+ * and a duplicate entry.
844
+ */
845
+ export declare function findUnmigratedListDrift(surfaces: readonly ConfigObjectSurface[], unmigrated: readonly string[]): string[];
846
+ /** Whether this surface has declared its cross-field rules either way. */
847
+ export declare function hasDeclaredCrossFieldRules(surface: ConfigObjectSurface): boolean;
848
+ /**
849
+ * The surface's declared rules for one stage, in declaration order — the
850
+ * derivation `config push`'s two-stage contract replaces its hand-maintained
851
+ * ordering with (#3375 is the consumer).
852
+ *
853
+ * Throws for a surface that has declared neither slot, rather than returning
854
+ * `[]`: "not declared yet" must never be read as "has no rules" (principle 6).
855
+ */
856
+ export declare function crossFieldRulesForStage(surface: ConfigObjectSurface, stage: CrossFieldRuleStage): readonly CrossFieldRule[];
857
+ /**
858
+ * Is a rule declared `preflight` actually reached before `config push` mutates
859
+ * anything? (issue #3375, project phase 3, intent §Success criteria 5.)
860
+ *
861
+ * #3373 gave a rule a `stage`; #3374 declared three surfaces' rules. Both left
862
+ * the string a PROMISE. "This runs before the first mutating call" was
863
+ * satisfied by typing `preflight` beside a rule that is not on the preflight
864
+ * path at all, because the push preflight was an inline block inside the
865
+ * command's `.action()` callback with no exported symbol — so "reached from the
866
+ * preflight" had nothing to resolve against.
867
+ *
868
+ * #3375 extracts that block into `cli/src/commands/sync.ts#runConfigPushPreflight`
869
+ * and this module answers the question statically, from the declared
870
+ * `<module>#<export>`:
871
+ *
872
+ * - `reachableExports` walks the call graph from one entry symbol over module
873
+ * SOURCE TEXT and returns what it reached — plus what it could NOT resolve,
874
+ * so silence is never a pass.
875
+ * - `findUnreachedPreflightRules` reports every `preflight` declaration,
876
+ * cross-field or single-field, whose handler is missing from that set.
877
+ * - `findMalformedFieldValidationStages` is the field-level twin of #3373's
878
+ * `findMalformedRuleDeclarations`: `ConfigField["validation"]` gained a
879
+ * `stage` here, and it must be well-formed to mean anything.
880
+ *
881
+ * Everything is a PURE function over values and over source text the caller
882
+ * passes in: `cli/tests/unit/config-surface-preflight-staging-3375.test.ts`
883
+ * does the filesystem walk, so this module stays vendorable (`types.ts`
884
+ * §Purity), exactly the split `rules.ts` already uses.
885
+ *
886
+ * ── Two things this check is NOT ──────────────────────────────────────────
887
+ *
888
+ * It is NECESSARY, not sufficient, and there is deliberately no converse. A
889
+ * handler reached on one surface's leg satisfies a `preflight` declaration on
890
+ * another (the residual the intent accepts and #3379 records), and asking "is
891
+ * this `apply` rule reached from the preflight?" would be wrong by
892
+ * construction: `validateSigningSecretDeclaration` IS reached on the function
893
+ * leg and IS correctly `apply` on the webhook surface, where no CLI call
894
+ * exists.
895
+ *
896
+ * The walk is identifier-based over masked source, so it over-approximates in
897
+ * the PASSING direction: a local variable shadowing an imported handler's name
898
+ * reads as a call. That is the safe direction for a guard whose failure mode
899
+ * must be "a promise you did not keep", not "a promise you did keep, reported
900
+ * as broken".
901
+ */
902
+ /** A field's `validation` object may carry these keys and no others (#3375). */
903
+ export declare const FIELD_VALIDATION_KEYS: readonly string[];
904
+ /**
905
+ * The modules a walk may read, and how a specifier resolves between them.
906
+ *
907
+ * The caller owns resolution because it owns the filesystem: the CLI test maps
908
+ * both spellings of the vendored artifact onto the `src/config-surface/`
909
+ * modules it is a copy of, which is the whole point of DSO-3375-002 — the
910
+ * generator strips every intra-directory import before concatenating, so the
911
+ * artifact itself carries no edges between its sections.
912
+ */
913
+ export interface StaticModuleGraph {
914
+ /** Repo-relative module path → that module's SOURCE TEXT. */
915
+ modules: ReadonlyMap<string, string>;
916
+ /**
917
+ * Candidate modules a specifier names, seen from `fromModule`.
918
+ *
919
+ * `null` = a bare package specifier: deliberately not followed, and never
920
+ * reported. `[]` = a relative specifier that resolves to no module in the
921
+ * graph, which IS reported — a guard that silently stops looking is worse
922
+ * than no guard.
923
+ */
924
+ resolve(fromModule: string, specifier: string): readonly string[] | null;
925
+ }
926
+ /** What one walk found, and what it could not resolve on the way. */
927
+ export interface ReachabilityWalk {
928
+ /** `<module>#<export>` for every symbol reached, module = where it is DECLARED. */
929
+ reached: ReadonlySet<string>;
930
+ /** Specifiers and entry symbols the graph could not answer for, sorted. */
931
+ unresolved: string[];
932
+ }
933
+ /**
934
+ * Walk the call graph from `entry` and return every symbol it reaches.
935
+ *
936
+ * An identifier inside a reached declaration's span is followed when it names
937
+ * another top-level declaration of the same module, or a value import — which
938
+ * resolves through the graph to whichever candidate module DECLARES the name,
939
+ * following `export { x } from` and `export * from` on the way. A symbol is
940
+ * recorded under the module that declares it, never under a barrel that merely
941
+ * re-exports it: a declaration that names the barrel is reported unreached,
942
+ * because the point of the string is to name the one implementation.
943
+ */
944
+ export declare function reachableExports(entry: string, graph: StaticModuleGraph): ReachabilityWalk;
945
+ /**
946
+ * Every fault in one surface's FIELD validation declarations, each naming the
947
+ * surface and the field. `[]` means every field is well-formed.
948
+ *
949
+ * Runs over every surface in the registry, migrated or not: field declarations
950
+ * exist independently of the cross-field slot, so the
951
+ * `CROSS_FIELD_RULES_UNMIGRATED` ratchet does not — and must not — stand
952
+ * between a field-level `preflight` declaration and this check (DSO-3375-001).
953
+ */
954
+ export declare function findMalformedFieldValidationStages(surface: ConfigObjectSurface): string[];
955
+ /**
956
+ * Every `preflight` declaration on this surface whose handler the walk did not
957
+ * reach, each naming the surface, the rule (or field), the handler and the
958
+ * entry point.
959
+ *
960
+ * The FIELD half runs on every surface. The CROSS-FIELD half runs only where a
961
+ * surface has declared, because `crossFieldRulesForStage` throws for one that
962
+ * has not — "not declared yet" is never "rule-free" (#3373), and asking it
963
+ * here would turn an unmigrated surface into a crash rather than a skip.
964
+ */
965
+ export declare function findUnreachedPreflightRules(surface: ConfigObjectSurface, reached: ReadonlySet<string>, entry: string): string[];
966
+ /**
967
+ * Request schemas generated from the configuration-object definitions
968
+ * (issue #2644, phase 5 / criterion 9).
969
+ *
970
+ * Every create/update handler in this family used to drop, in silence, any body
971
+ * key it did not read. A client sending `timoutMs` for `timeoutMs` got a 200 and
972
+ * no timeout change. These schemas close that: one per object and mode,
973
+ * `additionalProperties: false`, properties = the keys that object accepts on
974
+ * the wire in that mode, so an unknown key is a 400 naming it.
975
+ *
976
+ * **Breaking change, named**: a client that sends a stray key and gets a 200
977
+ * today will get a 400. The CLI never hits it — `config push` already rejects
978
+ * unrecognized TOML keys locally (criterion 6).
979
+ *
980
+ * ── What the schema says, and what it deliberately does not ──────────────
981
+ * It states the KEY SET only: each property is the empty schema (or carries
982
+ * only the `deprecated` annotation, #1815), so no value is type-checked here. That is the decision of record (#1976, carried forward at
983
+ * #2644's design gate): the definition classifies, handlers behave. The
984
+ * `status` enum, the queue limits' integer coercion, `runAs`'s caller|system
985
+ * check, the CEL parse of `accessRule` — all stay in the handlers the
986
+ * definition names, with their existing messages. Adding type gates here would
987
+ * duplicate them and start rejecting values the handlers accept.
988
+ *
989
+ * ── Which keys are in the set ────────────────────────────────────────────
990
+ * Derived, not listed:
991
+ *
992
+ * - every field the definition says is writable in this mode;
993
+ * - every field classified `structural` — the authored sub-trees that travel
994
+ * on their own channel (`rules`, `steps`, `metadataManifest`, `schema`,
995
+ * `triggers`) but are still sent in the body — in the modes that entry
996
+ * declares (`requestModes`; omitted means both, `[]` means the key travels
997
+ * in the URL path and no schema admits it);
998
+ * - every field classified `deprecated` — still writable server-side, by
999
+ * definition of that classification;
1000
+ * - the table's `requestOnlyKeys`, in the modes each declares: protocol keys
1001
+ * that are not model fields at all, such as the `expectedModifiedAt`
1002
+ * optimistic-concurrency token or a create-only alias.
1003
+ *
1004
+ * `server-owned` and `secret` classifications are the two the schema excludes:
1005
+ * the first is assigned by the server, the second never travels in readable
1006
+ * form.
1007
+ *
1008
+ * Pure: no models, no tenant context, no `env` (see `types.ts` §Purity).
1009
+ */
1010
+ /**
1011
+ * A generated request schema. Shaped for the app API's `meta.request` slot and
1012
+ * the runtime validator it feeds (`src/app-api/request-validation.ts`), which
1013
+ * reports an unknown key as `value.<key> is not allowed`.
1014
+ */
1015
+ export interface ConfigRequestSchema {
1016
+ type: "object";
1017
+ /**
1018
+ * Each property is the empty schema, or `{ deprecated: true }` for a field
1019
+ * the definition marks `deprecated` (#1815). `deprecated` is an OpenAPI
1020
+ * annotation: it constrains no value, so the schema still states the key set
1021
+ * and nothing more.
1022
+ */
1023
+ properties: Record<string, {
1024
+ deprecated?: true;
1025
+ }>;
1026
+ additionalProperties: false;
1027
+ /**
1028
+ * Structural-typing escape hatch: the app API's `meta.request` slot is a
1029
+ * `Record<string, unknown>` (`JsonSchema`), and an interface with no index
1030
+ * signature is not assignable to one. Declaring the index here keeps the
1031
+ * generated schema usable as a route schema without an `as any` at every
1032
+ * call site.
1033
+ */
1034
+ [key: string]: unknown;
1035
+ }
1036
+ /**
1037
+ * Protocol keys every config UPDATE accepts, whichever object it is.
1038
+ *
1039
+ * `expectedModifiedAt` is the optimistic-concurrency token `config push` attaches
1040
+ * to an update body when it has a baseline from the last pull; a handler that
1041
+ * does not implement conflict detection ignores it. It is a property of the
1042
+ * sync protocol rather than of any one object, which is why it is stated once
1043
+ * here instead of in thirteen definitions.
1044
+ */
1045
+ export declare const UPDATE_PROTOCOL_KEYS: readonly string[];
1046
+ /** The body keys this table accepts in `mode`, in a stable order. */
1047
+ export declare function requestSchemaKeys(table: ConfigTable, mode: "create" | "update"): string[];
1048
+ /**
1049
+ * The request schema for one object and mode. Generated from the definition, so
1050
+ * a schema permitting a key the definition does not is unrepresentable: there
1051
+ * is no place to write one.
1052
+ */
1053
+ export declare function configRequestSchema(table: ConfigTable, mode: "create" | "update"): ConfigRequestSchema;
1054
+ /**
1055
+ * The retired-key guidance for a generated schema, keyed by body key — or
1056
+ * `undefined` when the schema's object has none. Consumed by the app API's
1057
+ * request validator (`src/app-api/request-validation.ts`).
1058
+ */
1059
+ export declare function retiredRequestKeys(schema: object | undefined): Readonly<Record<string, string>> | undefined;
1060
+ /**
1061
+ * One schema for an endpoint whose body spans MORE than one table.
1062
+ *
1063
+ * `POST …/prompts` is the case: it creates the prompt AND seeds its first
1064
+ * config, so the body carries `[prompt]` fields and `[[configs]]` fields
1065
+ * together. Both halves still come from their definitions — this only says the
1066
+ * endpoint accepts the union, in the one place that is true.
1067
+ */
1068
+ export declare function mergeRequestSchemas(...schemas: readonly ConfigRequestSchema[]): ConfigRequestSchema;
1069
+ /**
1070
+ * The body keys `table` does not accept in `mode` — the 400's subject.
1071
+ *
1072
+ * Used by the admin API, which has no request-schema middleware: its handlers
1073
+ * call this directly so both APIs reject the same key set for the same object.
1074
+ */
1075
+ export declare function unknownRequestKeys(body: unknown, table: ConfigTable, mode: "create" | "update"): string[];
1076
+ /** The 400 message naming the unknown key(s), shared by both APIs. */
1077
+ export declare function unknownRequestKeysMessage(keys: readonly string[]): string;
1078
+ /**
1079
+ * Keys deliberately RETIRED from a configuration object's write surface.
1080
+ *
1081
+ * A retired key is not an unknown key. The generic hint for an unrecognized
1082
+ * TOML key — "check the spelling, or upgrade the CLI" — is exactly backwards
1083
+ * for one this CLI removed on purpose, and the generic 400 for an unaccepted
1084
+ * request key says only that the key is not allowed, not where the value moved
1085
+ * to. Both surfaces need the same sentence, and neither should invent it.
1086
+ *
1087
+ * So the guidance lives here, next to the definitions, with one entry per
1088
+ * retired key: the TOML wording for `config push` (which can tell the author to
1089
+ * delete a line) and the request wording for the API handlers (which cannot).
1090
+ *
1091
+ * Keyed by the table's TOML path prefix (`workflow`, `cronTrigger`, …), because
1092
+ * that is the identifier both consumers already have in hand.
1093
+ *
1094
+ * Pure: no models, no tenant context, no `env` (see `types.ts` §Purity).
1095
+ */
1096
+ export interface RetiredConfigKey {
1097
+ /** What `config push` says about a file that still carries the key. */
1098
+ toml: string;
1099
+ /** What a create/update handler says about a body that still sends it. */
1100
+ request: string;
1101
+ }
1102
+ export declare const RETIRED_CONFIG_KEYS: Record<string, Record<string, RetiredConfigKey>>;
1103
+ /** The retired-key entry for `key` under `prefix`, or null when it is simply unknown. */
1104
+ export declare function retiredConfigKey(prefix: string, key: string): RetiredConfigKey | null;
1105
+ /**
1106
+ * The capability grammar for server functions — #3182 phase 1, rewritten by
1107
+ * #3279 (project `server-functions` phase 3).
1108
+ *
1109
+ * A function declares in its own TOML what it may CONFIGURE:
1110
+ *
1111
+ * capabilities = ["integration:stripe", "secret:STRIPE_KEY", "databases:delete"]
1112
+ *
1113
+ * ── Why the grammar is this small ────────────────────────────────────────
1114
+ *
1115
+ * The intent's decision (2026-09-09, "Authorization inside a function?"):
1116
+ * function code acts as the system. The invocation gate is the authorization,
1117
+ * and inside a function every platform call carries the app's own authority in
1118
+ * every family. A capability is therefore never a statement about DATA — a
1119
+ * model, a prompt, a channel, a member — because the function may reach all of
1120
+ * it. It is declared only where it configures something:
1121
+ *
1122
+ * `integration:<key>` the egress allowlist — which upstream hosts the
1123
+ * function's outbound calls may reach;
1124
+ * `secret:<NAME>` credential least privilege — which secret VALUES may
1125
+ * cross into the sandbox at all;
1126
+ * the high-blast list {@link HIGH_BLAST_CAPABILITIES} — the operations
1127
+ * whose blast radius the intent keeps opt-in.
1128
+ *
1129
+ * Every other string a function used to declare is RETIRED, and the grammar
1130
+ * says so by name: an author who still writes `database:orders/Order:read`
1131
+ * is told the model changed and what stays, not "unknown family", which would
1132
+ * send them to check their spelling.
1133
+ *
1134
+ * ── Why the components have a charset ────────────────────────────────────
1135
+ *
1136
+ * A keyed grant's key must match `[A-Za-z0-9_-]+`, so neither `:` nor `/` can
1137
+ * enter a component and the string is INJECTIVE — one string, one object. An
1138
+ * integration or secret whose key carries a delimiter is simply unreachable
1139
+ * from functions, with an error that says why (D3182-001's argument, kept).
1140
+ *
1141
+ * ── Why this module is pure ──────────────────────────────────────────────
1142
+ *
1143
+ * Capabilities are validated twice — by `config push`'s preflight, so an
1144
+ * author sees the error against their own file, and by the server, which is
1145
+ * authoritative because the raw admin API exists. Two enforcement points must
1146
+ * not be two grammars, so the grammar lives here, in the dependency-free
1147
+ * `src/config-surface/` tree the CLI vendors at build time
1148
+ * (`cli/scripts/gen-config-surfaces.mjs`). The server imports this module; the
1149
+ * CLI imports the generated copy; the drift guard fails if they differ.
1150
+ */
1151
+ /** Every component of a grant. Injectivity depends on this. */
1152
+ export declare const GRANT_COMPONENT_PATTERN: RegExp;
1153
+ /** `ServerFunctionConfig.capabilities` is a StringSet with these bounds. */
1154
+ export declare const MAX_CAPABILITY_ENTRIES = 100;
1155
+ export declare const MAX_CAPABILITY_ENTRY_LENGTH = 200;
1156
+ /**
1157
+ * The two keyed families the intent keeps: one component under
1158
+ * {@link GRANT_COMPONENT_PATTERN}, naming a single object. Every key format the
1159
+ * platform issues fits: an integration key is `^[a-z0-9][a-z0-9-_]{2,}$` and a
1160
+ * secret name is `^[A-Z][A-Z0-9_]{0,63}$`.
1161
+ */
1162
+ export declare const KEYED_GRANT_FAMILIES: readonly ["integration", "secret"];
1163
+ /**
1164
+ * The high-blast-radius opt-ins — #3279, criterion 5 (CR3279-001, D3279-003).
1165
+ *
1166
+ * Since function code acts as the system, admission to a family is no longer
1167
+ * an authority statement: everything the gateway lets through runs with the
1168
+ * app's own authority. Most operations are fine that way — that is the whole
1169
+ * decision. A short list is not, and the intent names its categories: delete a
1170
+ * database, app or user; role changes; secret changes; resource provisioning.
1171
+ * Those stay opt-in, so a function that can do them says so in a reviewable
1172
+ * line of its TOML.
1173
+ *
1174
+ * The strings are EXACT and 1:1 with the operation id, so there is nothing to
1175
+ * look up: `users.setRole` needs `users:setRole`. They parse with the verb as
1176
+ * their KEY, because two exact capabilities in one family must not cover each
1177
+ * other — `databases:create` is not permission to delete a database.
1178
+ *
1179
+ * The database ROLE mutations are here because they hand out persistent
1180
+ * authority: a group grant assigns the manager role (D3279-003). App deletion
1181
+ * and secret writes have no app-API route today; they are recorded, not gated,
1182
+ * and the profile generator refuses to admit a future such route without a row
1183
+ * here (`HIGH_BLAST_WATCH` in `scripts/lib/function-profile.mjs`).
1184
+ */
1185
+ export declare const HIGH_BLAST_CAPABILITIES: readonly ["databases:create", "databases:delete", "databases:transferOwnership", "databases:addManager", "databases:revokePermission", "databases:grantGroupPermission", "databases:revokeGroupPermission", "users:remove", "users:setRole", "blobBuckets:createBucket", "blobBuckets:deleteBucket"];
1186
+ /** The exact strings, which since #3279 are exactly the high-blast list. */
1187
+ export declare const EXACT_GRANT_STRINGS: readonly ["databases:create", "databases:delete", "databases:transferOwnership", "databases:addManager", "databases:revokePermission", "databases:grantGroupPermission", "databases:revokeGroupPermission", "users:remove", "users:setRole", "blobBuckets:createBucket", "blobBuckets:deleteBucket"];
1188
+ export type GrantFamily = (typeof KEYED_GRANT_FAMILIES)[number] | "databases" | "users" | "blobBuckets";
1189
+ /**
1190
+ * The retired FAMILIES (#3279), each with the reason it is gone.
1191
+ *
1192
+ * The value is what the family used to authorize, phrased as what a function
1193
+ * now reaches without it. A refusal names the authored string, says it is
1194
+ * retired, gives this reason, tells the author to delete the entry, and lists
1195
+ * what stays.
1196
+ */
1197
+ export declare const RETIRED_GRANT_FAMILIES: Record<string, string>;
1198
+ /** The retired EXACT strings (#3279), on the same terms. */
1199
+ export declare const RETIRED_GRANT_STRINGS: Record<string, string>;
1200
+ /**
1201
+ * The retirement sentence for one authored string, or null when the string is
1202
+ * not a retired one.
1203
+ *
1204
+ * Exported so the enforcement-time reader (`loadConfigGrants`) can tell a
1205
+ * retired string on a pre-change row — tolerated, logged — from a string that
1206
+ * was never a grant at all, which still authorizes nothing.
1207
+ */
1208
+ export declare function retiredGrantRefusal(raw: string): string | null;
1209
+ /**
1210
+ * Any grant, in one flat shape.
1211
+ *
1212
+ * Flat rather than a discriminated union because this module is vendored into
1213
+ * the CLI, which compiles with `strict: false`: a caller reads `family` and
1214
+ * then `key`, and the fields another family would have used are simply absent.
1215
+ */
1216
+ export interface FunctionGrant {
1217
+ family: GrantFamily;
1218
+ /**
1219
+ * The single component of a keyed family — the integration key or the
1220
+ * secret name — or the VERB of a high-blast string (`delete` for
1221
+ * `databases:delete`), so that no two exact capabilities in one family read
1222
+ * as the same grant.
1223
+ */
1224
+ key: string;
1225
+ /** The authored string, so an error or a log line can quote it. */
1226
+ raw: string;
1227
+ }
1228
+ export interface ParsedFunctionGrant {
1229
+ grant?: FunctionGrant;
1230
+ error?: string;
1231
+ }
1232
+ /**
1233
+ * A channel name's ceiling, and the reason it has one.
1234
+ *
1235
+ * The name rides in a `ConnectionMapping` row's document-id slot as
1236
+ * `ch:<appId>:<channel>` and in every grant token's claims, so an unbounded
1237
+ * name would be an unbounded key and an unbounded credential. 200 characters
1238
+ * is {@link MAX_CAPABILITY_ENTRY_LENGTH}, kept for continuity with the rows
1239
+ * #3184 already wrote.
1240
+ */
1241
+ export declare const MAX_CHANNEL_NAME_LENGTH = 200;
1242
+ export interface ParsedChannelName {
1243
+ /** The segment before the first `:`. Absent when the name is refused. */
1244
+ namespace?: string;
1245
+ error?: string;
1246
+ }
1247
+ /**
1248
+ * A channel NAME, and its namespace.
1249
+ *
1250
+ * The grammar is the grant component charset applied per segment: one or more
1251
+ * `[A-Za-z0-9_-]+` segments joined by `:`. The `channel:<namespace>` GRANT
1252
+ * that used to cover a name is retired (#3279); the name grammar stays because
1253
+ * the authorize and publish routes answer 400 about a name outside it before
1254
+ * anything else, and the connection worker keys membership by it.
1255
+ *
1256
+ * Refusals name the segment that failed, because "channel name is invalid" on
1257
+ * a name like `orders:a::b` tells an author nothing they cannot already see.
1258
+ */
1259
+ export declare function parseChannelName(value: unknown): ParsedChannelName;
1260
+ /**
1261
+ * One capability entry as a grant, or the reason it is not one.
1262
+ *
1263
+ * The single entry point the enforcement path and both preflights use: a
1264
+ * caller holds one authored string and asks what it grants, without having to
1265
+ * know which of the shapes to try. Every diagnosis is specific — a retired
1266
+ * string gets the retirement and what stays; a near miss in a kept family gets
1267
+ * the family's own strings; a keyed family gets its charset rule.
1268
+ */
1269
+ export declare function parseFunctionGrant(entry: unknown): ParsedFunctionGrant;
1270
+ /**
1271
+ * One shape rather than a discriminated union: this module is vendored into
1272
+ * the CLI, which compiles with `strict: false`, where narrowing on a boolean
1273
+ * literal discriminant does not hold. Both callers read `ok` and then the
1274
+ * field they want, and the unused half is empty rather than absent.
1275
+ */
1276
+ export interface ParsedCapabilities {
1277
+ ok: boolean;
1278
+ /** Deduped, in authored order — what the config row stores. Empty when refused. */
1279
+ capabilities: string[];
1280
+ /** Every grant, in authored order. */
1281
+ allGrants: FunctionGrant[];
1282
+ /**
1283
+ * The retired strings that were SKIPPED, in authored order — populated only
1284
+ * under `tolerateRetired` (see {@link parseCapabilities}); a strict parse
1285
+ * refuses them instead and leaves this empty.
1286
+ */
1287
+ retired: string[];
1288
+ /** Empty when accepted. */
1289
+ errors: string[];
1290
+ }
1291
+ export interface ParseCapabilitiesOptions {
1292
+ /**
1293
+ * Skip retired strings instead of refusing them — #3279 edge 25.
1294
+ *
1295
+ * The PUSH path is strict: a file that still declares a retired grant is
1296
+ * refused with the retirement, because a line that is accepted and ignored
1297
+ * is a line the author believes means something. The ENFORCEMENT path is
1298
+ * tolerant: a config version pushed before #3279 carries retired strings in
1299
+ * a row that can never be re-pushed to fix (its envelope is immutable), and
1300
+ * refusing it there would break every function pushed before the change.
1301
+ * Such a row authorizes exactly what it keeps, and the skipped strings are
1302
+ * reported in `retired` so the caller can log them.
1303
+ */
1304
+ tolerateRetired?: boolean;
1305
+ }
1306
+ /**
1307
+ * A whole `capabilities` list: shape, bounds, grammar, duplicates.
1308
+ *
1309
+ * The model's own caps are checked HERE rather than left to the StringSet
1310
+ * field, so an over-long entry is a named push error instead of a late model
1311
+ * throw after the R2 object has already been written (principle 6).
1312
+ */
1313
+ export declare function parseCapabilities(value: unknown, options?: ParseCapabilitiesOptions): ParsedCapabilities;
1314
+ /**
1315
+ * The config-tree objects an `integration:` grant may name.
1316
+ *
1317
+ * Only the one family whose target is CONFIG-TREE state. `secret:` is absent
1318
+ * on purpose (D3183-002): its values are provisioned per environment, out of
1319
+ * band, and are not part of the reviewed tree at all, so the ordinary order of
1320
+ * work is to push the function and then provision the value. Refusing an
1321
+ * unprovisioned name at push would break that; a missing value at CALL time is
1322
+ * a structured runtime error instead. The high-blast strings name no object.
1323
+ *
1324
+ * `null` means "this enforcement point could not find out". The CLI reads the
1325
+ * tree and, when it can, a live listing; when neither is available it defers
1326
+ * rather than guessing, because a preflight that refused a valid tree for
1327
+ * being offline would be worse than one that lets the server have the last
1328
+ * word. The server never passes null — it can always read its own rows.
1329
+ */
1330
+ export interface KnownGrantTargets {
1331
+ /** Non-archived integration keys, or null when unknown. */
1332
+ integrations: ReadonlySet<string> | null;
1333
+ }
1334
+ /**
1335
+ * Grants naming an integration the app does not have.
1336
+ *
1337
+ * One message per offending grant, quoting the whole authored string AND the
1338
+ * key on its own, so an operator reading the line knows both what to fix in
1339
+ * the file and what to create in the app.
1340
+ *
1341
+ * The rule is here, beside the grammar, for the reason the whole module
1342
+ * exists: `config push`'s preflight and the authoritative server check read
1343
+ * different sources for the same facts — a `.toml` in the tree versus a row
1344
+ * in DynamoDB — and it is the RULE that must not differ between them.
1345
+ */
1346
+ export declare function validateKeyedGrantsAgainstTargets(grants: readonly FunctionGrant[], known: KnownGrantTargets): string[];
1347
+ /**
1348
+ * The query manifest's grammar, and the read rule it unlocks — #3187, project
1349
+ * `server-functions` phase 5.
1350
+ *
1351
+ * A pushed config version may carry a MANIFEST: the queries and mutations the
1352
+ * tree registered at module scope, collected by the CLI (`function-collect.ts`)
1353
+ * by running the tree with `primitive-functions` aliased to a recording stub.
1354
+ *
1355
+ * ── What the manifest is for ─────────────────────────────────────────────
1356
+ *
1357
+ * Observability, and nothing else. `primitive functions get` and the admin
1358
+ * get list what a version registered, so an operator can see it without
1359
+ * reading the bundle (principle 8). The read rule it used to be decided from
1360
+ * (#3187's `$caller` relaxation of `unscopedReads`) is retired by #3279:
1361
+ * function code acts as the system, so there is no per-model grant for a
1362
+ * binding to waive. The intent says so in as many words — "the models a
1363
+ * function touches are collected at push as a reviewable manifest, not an
1364
+ * authorization".
1365
+ *
1366
+ * It is HONEST-CODE evidence and the design doc says so: a hostile bundle can
1367
+ * register whatever it likes, because the collector runs the tenant's own
1368
+ * code. Nothing security-relevant at runtime reads it — parameter injection
1369
+ * and cache verification happen in the platform-owned SDK inside the isolate,
1370
+ * and the invocation gate remains the adversarial boundary.
1371
+ *
1372
+ * ── Why the grammar is here ──────────────────────────────────────────────
1373
+ *
1374
+ * Same reason as `function-grants.ts`: the CLI validates at push preflight so
1375
+ * an author sees the error against their own tree, and the server validates
1376
+ * authoritatively because the raw admin API exists. Two enforcement points,
1377
+ * one rule, in the dependency-free tree the CLI vendors.
1378
+ */
1379
+ /**
1380
+ * The manifest encoding, versioned with the envelope that carries it.
1381
+ *
1382
+ * Version 2 (#3279 behavior 10) adds what a function TOUCHES beside what it
1383
+ * registers: the deduplicated `models` its code names and the `families` of
1384
+ * `ctx.api` and the ctx helpers it reaches, collected by a static scan of the
1385
+ * built bundle, plus a `dynamicModels` marker for a model name the scan
1386
+ * could not resolve — distinct from an empty list, which means "names none".
1387
+ * A version-1 manifest still parses: it records registrations only.
1388
+ */
1389
+ export declare const FUNCTION_MANIFEST_SCHEMA_VERSION = 2;
1390
+ export declare const FUNCTION_MANIFEST_SCHEMA_VERSIONS: readonly [1, 2];
1391
+ /** Bounds, so a manifest cannot be a way to store an unbounded blob. */
1392
+ export declare const MAX_MANIFEST_QUERIES = 200;
1393
+ export declare const MAX_MANIFEST_NAME_LENGTH = 120;
1394
+ export declare const MAX_MANIFEST_MODELS = 200;
1395
+ export declare const MAX_MANIFEST_FAMILIES = 40;
1396
+ export interface ManifestParam {
1397
+ type?: string;
1398
+ /** `type: "array"` — the element type, when declared (#3281). */
1399
+ items?: {
1400
+ type: string;
1401
+ };
1402
+ caller?: boolean;
1403
+ optional?: boolean;
1404
+ default?: unknown;
1405
+ }
1406
+ /** The scalar parameter types a registration may declare, and an array's element types. */
1407
+ export declare const QUERY_PARAM_SCALAR_TYPES: readonly ["string", "number", "boolean", "any"];
1408
+ /**
1409
+ * Coerce one value to a declared parameter type the way the SDK coerces a
1410
+ * SUPPLIED value: a digit string becomes a number, `"true"`/`"false"` a
1411
+ * boolean, an array's elements each by the `items` type. Applied to a
1412
+ * declared `default` at registration (D3281-SO-005) so what `run` receives is
1413
+ * what the declaration promises — here at push (the collect stub and this
1414
+ * grammar) and in the SDK at the first load. ONE rule, spelled in the SDK's
1415
+ * source a second time because that module is baked text; the tests hold the
1416
+ * two together.
1417
+ */
1418
+ export declare function coerceParamDefault(spec: {
1419
+ type?: string;
1420
+ items?: {
1421
+ type?: string;
1422
+ };
1423
+ }, value: unknown): {
1424
+ ok: true;
1425
+ value: unknown;
1426
+ } | {
1427
+ ok: false;
1428
+ reason: string;
1429
+ };
1430
+ export interface ManifestQuery {
1431
+ name: string;
1432
+ kind: "query" | "mutation";
1433
+ models: string[];
1434
+ params: Record<string, ManifestParam>;
1435
+ cache: {
1436
+ ttlMs: number;
1437
+ } | null;
1438
+ /** True when a `$caller` binding scopes this registration. */
1439
+ callerScoped: boolean;
1440
+ }
1441
+ export interface FunctionManifest {
1442
+ schemaVersion: number;
1443
+ queries: ManifestQuery[];
1444
+ /**
1445
+ * Every model name the bundle names, deduplicated and sorted: registration
1446
+ * declarations, literal `.model("…")` calls, and literal `modelName`/`model`
1447
+ * arguments of the direct records and documents calls (#3279). Empty for a
1448
+ * version-1 manifest, and for a function that names none.
1449
+ */
1450
+ models: string[];
1451
+ /** Every `ctx.api.<family>` and ctx-helper family the bundle reaches. */
1452
+ families: string[];
1453
+ /**
1454
+ * The scan met a model name it could not resolve — a computed
1455
+ * `modelName`, a `.model(variable)`. Says "and possibly more", which an
1456
+ * empty `models` list does not.
1457
+ */
1458
+ dynamicModels: boolean;
1459
+ }
1460
+ export interface ParsedManifest {
1461
+ ok: boolean;
1462
+ manifest: FunctionManifest | null;
1463
+ errors: string[];
1464
+ }
1465
+ /**
1466
+ * Validate a manifest's grammar and normalize it.
1467
+ *
1468
+ * Deliberately strict about SHAPE and silent about meaning: whether the models
1469
+ * exist, whether the queries are the ones the sandbox will really register,
1470
+ * and whether the author meant any of it are questions this cannot answer.
1471
+ */
1472
+ export declare function parseFunctionManifest(value: unknown): ParsedManifest;
1473
+ /**
1474
+ * The runtime keys a `functions/<key>.toml` no longer decides anything with —
1475
+ * #3482, project `server-functions` phase 4.
1476
+ *
1477
+ * The sponsor settled it on 2026-09-15 (the intent, "Mode vocabulary?",
1478
+ * amended again): the config says NOTHING about how a function runs. A
1479
+ * function is a function; the caller picks the runtime at each call, cron
1480
+ * fires always start a task run, webhook deliveries always run as a request,
1481
+ * and a function that must not run under one runtime tests for it in code with
1482
+ * `assertRuntime`.
1483
+ *
1484
+ * ── Why these keys are accepted, not refused ──────────────────────────────
1485
+ *
1486
+ * Every tree pushed since #3454 that declares a cron trigger carries
1487
+ * `mode = …` ON THE ENTRY, because `cron-trigger-mode-required` demanded it;
1488
+ * plenty carry a top-level `mode` or the older `durable`. Removing the keys
1489
+ * from the accepted set outright would refuse those trees with an unknown-key
1490
+ * error one day after the platform insisted on them, which is the opposite of
1491
+ * principle 5 inside a non-breaking phase.
1492
+ *
1493
+ * So through phase 4 they are ACCEPTED and IGNORED, with one warning per key
1494
+ * naming it and the line to delete; from phase 5 (#3188) they are refused with
1495
+ * the rest of the retirement matrix. The value is not validated — there is
1496
+ * nothing left to validate it against, and refusing a bad value for a key
1497
+ * nobody reads would be a refusal about spelling alone.
1498
+ *
1499
+ * Pure: no models, no tenant context, no `env` (see `types.ts` §Purity). Both
1500
+ * the CLI preflight (vendored by `cli/scripts/gen-config-surfaces.mjs`) and the
1501
+ * admin config-version route read this one scanner, so the warning an author
1502
+ * sees from `config push` is the sentence the API answers with.
1503
+ */
1504
+ /** The two `[function]` keys that no longer say anything (#3482). */
1505
+ export declare const RETIRED_FUNCTION_RUNTIME_KEYS: readonly ["mode", "durable"];
1506
+ export type RetiredFunctionRuntimeKey = (typeof RETIRED_FUNCTION_RUNTIME_KEYS)[number];
1507
+ /** One ignored key met in a `[function]` table. */
1508
+ export interface IgnoredFunctionKey {
1509
+ /**
1510
+ * Where it was: `mode`, `durable`, or `triggers.cron.<name>.mode`. Never
1511
+ * rendered on its own — a reader that wants to branch reads this, and every
1512
+ * printer reads `message`.
1513
+ */
1514
+ path: string;
1515
+ /** The sentence the author is owed, with no file prefix (the caller adds it). */
1516
+ message: string;
1517
+ }
1518
+ /**
1519
+ * Every retired runtime key a `[function]` table still carries.
1520
+ *
1521
+ * Reads the table the way the author wrote it: the two top-level keys, and a
1522
+ * `mode` on each `[[function.triggers.cron]]` entry. A cron entry's sentence
1523
+ * says the extra thing its author needs to hear — that the schedule no longer
1524
+ * chooses, because every fire starts a task run (#3334's runner branch is
1525
+ * gone).
1526
+ *
1527
+ * Order is the order an author reads their file in: the top-level keys first,
1528
+ * then the cron entries in declaration order.
1529
+ */
1530
+ export declare function ignoredFunctionKeys(functionTable: unknown): IgnoredFunctionKey[];
1531
+ /**
1532
+ * The database types a `[function]` table's retired trigger block names —
1533
+ * #3483.
1534
+ *
1535
+ * Beside `ignoredFunctionKeys` because it answers the same question about the
1536
+ * same table, for the same reader: `config pull` writes a version's AUTHORED
1537
+ * bytes, and a version pushed before the removal carries the block. Without
1538
+ * this the pulled tree would be refused on its next push — a tree an author
1539
+ * cannot get back into a working state, which is the failure D3482-007 already
1540
+ * had to close for the runtime keys.
1541
+ *
1542
+ * This is NOT a refusal and shares nothing with one. The block is refused on
1543
+ * input by `normalizeTriggerDeclaration`; what a strip needs is the list of
1544
+ * entries it is taking out so it can say so, which is why an entry whose
1545
+ * `type` is unreadable still counts as one entry (the empty string). It is the
1546
+ * block's PRESENCE that goes, not its contents.
1547
+ *
1548
+ * TOML spells the block three ways — an array of tables, a single table, and
1549
+ * an inline array — and a scan that missed one would leave a key behind
1550
+ * (CR3482-002's lesson, applied to a whole table).
1551
+ */
1552
+ export declare function retiredDatabaseTriggerTypes(functionTable: unknown): string[];
1553
+ /**
1554
+ * Whether the block is THERE at all — the question a strip has to ask, which
1555
+ * the type list above cannot answer (CR3483-001).
1556
+ *
1557
+ * `database = []` names no type, so the list is empty and a strip that decided
1558
+ * by its length left the key in the pulled file. That file then fails its own
1559
+ * next push: `normalizeTriggerDeclaration` refuses the key by PRESENCE, of any
1560
+ * shape, an empty array included — so the two halves disagreed about what the
1561
+ * block is, and the tree an author pulled was a tree they could not push.
1562
+ * Presence is the one rule both sides read now, spelled the way
1563
+ * `normalizeTriggerDeclaration` spells it — `!== undefined` — so a value one
1564
+ * of them would call a block and the other would not cannot exist.
1565
+ */
1566
+ export declare function hasRetiredDatabaseTriggerBlock(functionTable: unknown): boolean;
1567
+ /**
1568
+ * The same scan, rendered for one file — the shape `config push` and
1569
+ * `config diff` print and the admin route answers with.
1570
+ *
1571
+ * `label` is what the reader can act on: `functions/<key>.toml` from the CLI,
1572
+ * and the function's key from the API, which has no file to name.
1573
+ */
1574
+ export declare function ignoredFunctionKeyWarnings(label: string, functionTable: unknown): string[];
1575
+ /**
1576
+ * The trigger blocks a function declares, derived from its authored TOML
1577
+ * (#3181, project `server-functions`, criterion 4).
1578
+ *
1579
+ * ── The declaration is derived, never supplied ────────────────────────────
1580
+ *
1581
+ * A config-version push carries the authored `functions/<key>.toml` bytes
1582
+ * inside its envelope, and `envelopeHash` covers them. If the push ALSO
1583
+ * carried a parsed `triggers` payload, the two could disagree: a direct API
1584
+ * caller could ship a public webhook trigger the authored file does not
1585
+ * declare, and two pushes with identical envelopes but different trigger
1586
+ * payloads would collapse to one version. So the server parses the envelope's
1587
+ * own bytes here (D3181-005) and there is no payload field to disagree with —
1588
+ * trigger behavior is bound to the version's identity by construction.
1589
+ *
1590
+ * ── Shape only ────────────────────────────────────────────────────────────
1591
+ *
1592
+ * This module decides what the file SAYS: the accepted key set, the required
1593
+ * values, and the rules that need nothing but the document (scheme `none`,
1594
+ * a nameless or duplicated cron entry, an entry count past the per-function
1595
+ * cap, a webhook or database block on a task version). Everything that needs the
1596
+ * app's state — whether a referenced secret exists, whether the
1597
+ * scheme-specific config is valid, whether the app is at its webhook or cron
1598
+ * cap, whether a standalone webhook holds the key — belongs to the push
1599
+ * boundary, which runs the SAME validators the standalone create runs
1600
+ * (D3181-006).
1601
+ *
1602
+ * ── One implementation, two readers (#3320) ───────────────────────────────
1603
+ *
1604
+ * The CLI checks the same rules against the author's own file before a request
1605
+ * is made. It used to do that from a hand-written restatement
1606
+ * (`cli/src/lib/function-triggers.ts`), kept in step only by a paired-fixture
1607
+ * test — so a rule added here with no fixture drifted silently. The rules
1608
+ * therefore live in `src/config-surface/`, which `cli/scripts/
1609
+ * gen-config-surfaces.mjs` vendors verbatim into the committed artifact
1610
+ * `cli/src/lib/generated-config-surfaces.ts`. There is one implementation, and
1611
+ * a change here that is not regenerated fails `--check` (a build failure)
1612
+ * rather than a fixture list that happens not to cover it.
1613
+ *
1614
+ * Reading the authored BYTES is the one thing that stayed server-side:
1615
+ * `deriveTriggerDeclaration` in `src/server-functions/trigger-declaration.ts`
1616
+ * parses them and calls `normalizeTriggerDeclaration` here. This directory
1617
+ * imports nothing but itself (asserted by `config-surface-drift-guard.test.ts`),
1618
+ * and the CLI has already parsed its own file by the time it asks.
1619
+ */
1620
+ /**
1621
+ * Why a webhook trigger is the request runtime, and a cron fire a task run —
1622
+ * #3482, the intent's "Mode vocabulary?" decision of 2026-09-15.
1623
+ *
1624
+ * Neither is a rule about the FUNCTION any more, so neither is a refusal: a
1625
+ * function is a function, and the DOOR decides which runtime runs it. A
1626
+ * webhook delivery runs inside the receiver because the provider is holding
1627
+ * the connection open waiting for an answer; a cron fire starts a task run
1628
+ * because it is waiting for nothing. A function that must not run under one of
1629
+ * them tests for it in code with `assertRuntime`, which is the only lock left.
1630
+ *
1631
+ * What survives here is the SHAPE of a declaration — the keys, the names, the
1632
+ * cron expression, the caps. The retired `mode` keys are accepted and reported
1633
+ * as ignored by `ignoredFunctionKeys` in `function-retired-keys.ts`.
1634
+ */
1635
+ /** A function's single webhook trigger, normalized. */
1636
+ export interface WebhookTriggerDeclaration {
1637
+ verificationScheme: string;
1638
+ signingSecret?: string;
1639
+ toleranceSeconds?: number;
1640
+ deduplicationEnabled?: boolean;
1641
+ deduplicationWindowMs?: number;
1642
+ maxBodyBytes?: number;
1643
+ secretGracePeriodMs?: number;
1644
+ /** `[function.triggers.webhook.verification]` — the row's `config`. */
1645
+ verification?: Record<string, unknown>;
1646
+ }
1647
+ /** One `[[function.triggers.cron]]` entry, normalized. */
1648
+ export interface CronTriggerDeclaration {
1649
+ name: string;
1650
+ cron: string;
1651
+ timezone?: string;
1652
+ overlapPolicy?: string;
1653
+ rootInput?: unknown;
1654
+ }
1655
+ export interface TriggerDeclaration {
1656
+ webhook: WebhookTriggerDeclaration | null;
1657
+ cron: CronTriggerDeclaration[];
1658
+ }
1659
+ export declare const EMPTY_TRIGGER_DECLARATION: TriggerDeclaration;
1660
+ /**
1661
+ * The most cron entries one function may declare.
1662
+ *
1663
+ * The per-app cap (50) is a resource ceiling; this is a per-OBJECT one, so a
1664
+ * single function cannot take most of an app's budget by itself. Ten is the
1665
+ * same order as the schedules a real function needs and leaves the app's
1666
+ * remaining slots for the other 40+ objects the cap is sized for.
1667
+ */
1668
+ export declare const MAX_CRON_TRIGGERS_PER_FUNCTION = 10;
1669
+ /**
1670
+ * The rule ids this module owns — one per refusal, declared on the `function`
1671
+ * surface (#3374). The union below closes `refuseTrigger`'s id parameter, so a
1672
+ * twenty-seventh refusal cannot compile without a twenty-seventh id, and that
1673
+ * id fails `cli-unit-tests` until the surface declares it (#3373's anchor).
1674
+ */
1675
+ export declare const TRIGGER_RULE_IDS: readonly ["triggers-table", "trigger-kind", "database-trigger-removed", "webhook-trigger-single", "webhook-trigger-table", "webhook-trigger-keys", "webhook-trigger-scheme-required", "webhook-trigger-scheme-none", "webhook-trigger-number", "webhook-trigger-dedup-boolean", "webhook-trigger-verification-table", "cron-trigger-cap", "cron-trigger-entry", "cron-trigger-keys", "cron-trigger-name-required", "cron-trigger-name-charset", "cron-trigger-duplicate", "cron-trigger-expression-required", "cron-trigger-overlap-policy"];
1676
+ export type TriggerRuleId = (typeof TRIGGER_RULE_IDS)[number];
1677
+ /**
1678
+ * A broken trigger rule. `ruleId` names which one, for a reader that wants to
1679
+ * branch without matching prose; every existing site reads `message` only.
1680
+ * Optional so `new TriggerDeclarationError(message)` — the CLI's own parse
1681
+ * refusal in `function-sync.ts` — keeps constructing.
1682
+ */
1683
+ export declare class TriggerDeclarationError extends Error {
1684
+ readonly ruleId?: TriggerRuleId;
1685
+ constructor(message: string, ruleId?: TriggerRuleId);
1686
+ }
1687
+ /** Is anything at all declared? Used to skip work on the common case. */
1688
+ export declare function hasDeclaredTriggers(declaration: TriggerDeclaration): boolean;
1689
+ /**
1690
+ * Normalize the `triggers` table of an already-parsed `[function]` table.
1691
+ * Throws `TriggerDeclarationError` naming the rule that was broken.
1692
+ *
1693
+ * Split out from the parse (`deriveTriggerDeclaration`, which owns the bytes)
1694
+ * so the CLI's preflight can check the document it has already read, and so the
1695
+ * push boundary can normalize a declaration it read from a stored row without
1696
+ * re-parsing bytes.
1697
+ */
1698
+ export declare function normalizeTriggerDeclaration(functionTable: any): TriggerDeclaration;
1699
+ /** The stored JSON for `ServerFunctionConfig.triggers`, or null when empty. */
1700
+ export declare function serializeTriggerDeclaration(declaration: TriggerDeclaration): string | null;
1701
+ /** Read a stored `ServerFunctionConfig.triggers` value back. */
1702
+ export declare function parseStoredTriggerDeclaration(stored: unknown): TriggerDeclaration;
1703
+ /**
1704
+ * The database types a STORED declaration used to watch, for a reader that
1705
+ * wants to name them — #3483.
1706
+ *
1707
+ * Pure, and separate from the parse on purpose: the parse answers what the
1708
+ * version means NOW (nothing), and this answers what it said, which is only
1709
+ * ever used to write one log line. Nothing branches on it.
1710
+ */
1711
+ export declare function storedDatabaseTriggerTypes(stored: unknown): string[];
1712
+ /** The `CronTrigger.triggerKey` an entry owns. */
1713
+ export declare function cronTriggerKeyFor(functionKey: string, name: string): string;
1714
+ /** The entry name a `<functionKey>:<name>` trigger key carries. */
1715
+ export declare function cronTriggerNameFrom(functionKey: string, triggerKey: string): string;
1716
+ /**
1717
+ * The `{{secrets.KEY}}` reference SHAPE, decided from the value alone.
1718
+ *
1719
+ * Split out of `src/services/secret-templates.ts` by #3320 so the one rule that
1720
+ * says whether a stored value IS a whole secret reference has one
1721
+ * implementation on both sides of a `config push`. The CLI preflight refuses a
1722
+ * webhook trigger whose `signingSecret` is a literal before anything is applied,
1723
+ * and the server refuses the same value at the write boundary, because both run
1724
+ * this code — the CLI through the artifact `cli/scripts/gen-config-surfaces.mjs`
1725
+ * renders, the server by importing this module. A shape-only restatement in the
1726
+ * CLI would have been subtly different: a reference spoiled by an invisible
1727
+ * character (#2297) survives `String.trim()` and would have passed a preflight
1728
+ * the server then failed.
1729
+ *
1730
+ * Pure by construction, which is what lets it live here: no secret store is
1731
+ * consulted, because whether a value is a REFERENCE never depends on which keys
1732
+ * exist. Whether the referenced key exists is the server's question, and stays
1733
+ * in `secret-templates.ts` beside the rest of resolution.
1734
+ *
1735
+ * `secret-templates.ts` re-exports everything here, so every existing caller
1736
+ * keeps its import and the two can never be different functions.
1737
+ */
1738
+ export declare const SECRETS_TEMPLATE_RE: RegExp;
1739
+ /** True when the value carries at least one `{{secrets.KEY}}` reference. */
1740
+ export declare function isSecretTemplate(value: string | null | undefined): boolean;
1741
+ /**
1742
+ * The value with every well-formed `{{secrets.KEY}}` reference removed — the
1743
+ * text that was NOT part of a reference the grammar accepts.
1744
+ *
1745
+ * This is the string the leftover-syntax rule below has to judge, and it is
1746
+ * always derived from the ORIGINAL stored value, never from a substituted
1747
+ * result. Resolution is a single `String.replace` pass that never re-scans
1748
+ * replacement text (`resolveMultiNamespaceTemplate`), so a brace or a
1749
+ * `secrets.` token coming out of a SECRET'S VALUE is inert — it is credential
1750
+ * material the operator stored, not config text, and testing the substituted
1751
+ * output would reject it (a Stripe key suffix stored as `}v2{` in an otherwise
1752
+ * valid `sk_live_{{secrets.SUFFIX}}` value).
1753
+ */
1754
+ export declare function withoutSecretReferences(value: string): string;
1755
+ /**
1756
+ * True when the value holds a well-formed `{{secrets.KEY}}` reference and the
1757
+ * text beside it is not credential material — a reference SPOILED by an
1758
+ * invisible character, rather than a legacy literal that happens to contain one
1759
+ * (#2297, consolidating #2386).
1760
+ *
1761
+ * Such a value is a reference spoiled by an authoring mistake — pasted out of
1762
+ * an editor or a document that carried a zero-width character along with it —
1763
+ * and it must fail closed rather than resolve. Before this rule a value spelled
1764
+ * `<U+200B>{{secrets.KEY}}` was not a whole reference (neither `\s` nor
1765
+ * `String.trim()` matches U+200B), carried no leftover reference SYNTAX once
1766
+ * the template was removed, and so classified as a working legacy literal that
1767
+ * resolved to U+200B followed by the secret: an HMAC key silently one byte
1768
+ * wrong, and a read surface pointing the operator at the wrong remediation.
1769
+ *
1770
+ * The rule judges the REMAINDER — the value with its well-formed references
1771
+ * taken out — against an allowlist, which is what makes the class closed:
1772
+ *
1773
+ * - Remainder empty, or ordinary whitespace only: the value is the reference it
1774
+ * plainly is, padding and all, and keeps resolving (#2191).
1775
+ * - Remainder carries at least one credential character: a genuine mixed
1776
+ * literal-plus-reference value (`sk_live_{{secrets.SUFFIX}}`), which predates
1777
+ * reference-only and keeps resolving as shipped (#2332) — including when the
1778
+ * operator's own bytes contain an invisible character, because that is
1779
+ * credential material rather than a spoiled pointer.
1780
+ * - Anything else: text that is present but that we cannot recognize as
1781
+ * credential material. Fail closed.
1782
+ *
1783
+ * Failing closed rather than stripping the character is the deliberate choice
1784
+ * (sponsor decision on #2297): stripping hides the mistake, where a
1785
+ * `malformed-reference` names it at the moment the value is written.
1786
+ *
1787
+ * A value with NO well-formed reference is not this rule's business, and needs
1788
+ * no separate handling: a pure literal is credential material the platform has
1789
+ * no standing to judge (`whsec_<U+200B>raw`), and a MISTYPED reference —
1790
+ * including one spoiled inside the braces, `{{secrets.<U+200B>KEY}}` — leaves
1791
+ * its syntax in the remainder and is already caught by
1792
+ * `carriesMalformedReferenceSyntax` in `secret-templates.ts`.
1793
+ *
1794
+ * Scoped to the reference-only credential boundary, not to
1795
+ * `resolveSecretTemplate`: an integration proxy header is a template by design
1796
+ * (`Authorization: Bearer {{secrets.TOKEN}}`), so it keeps resolving exactly
1797
+ * what the operator wrote.
1798
+ */
1799
+ export declare function isSpoiledSecretReference(value: string | null | undefined): boolean;
1800
+ /**
1801
+ * Matches a value that is EXACTLY one `{{secrets.KEY}}` reference and nothing
1802
+ * else. Anchored, and deliberately not global — `SECRETS_TEMPLATE_RE` carries
1803
+ * `lastIndex` state between calls.
1804
+ */
1805
+ export declare const WHOLE_SECRET_REFERENCE_RE: RegExp;
1806
+ /**
1807
+ * True when the whole (trimmed) value is a single `{{secrets.KEY}}` reference.
1808
+ *
1809
+ * The stricter sibling of `isSecretTemplate`, for the callers that use "is a
1810
+ * reference" to mean "carries no secret material of its own". `isSecretTemplate`
1811
+ * is a *contains* test, so `"sk_live_abcd{{secrets.SUFFIX}}"` satisfies it —
1812
+ * which is fine where a value is a template to be resolved (an
1813
+ * `Authorization: Bearer {{secrets.TOKEN}}` header is exactly that), and wrong
1814
+ * where the value is a credential that must live entirely in the encrypted
1815
+ * secret store. Used by the webhook `config` credential rule and by the
1816
+ * redaction that backs it: a mixed value would otherwise pass the write rule
1817
+ * AND skip redaction, storing and echoing most of a working credential in
1818
+ * cleartext.
1819
+ *
1820
+ * Trimmed, so `" {{secrets.KEY}} "` is accepted as the reference it plainly is;
1821
+ * two references, or a reference with any literal text beside it, are not.
1822
+ *
1823
+ * Invisible text beside the reference disqualifies the value before the trim
1824
+ * (#2297): U+FEFF is stripped by `String.trim()` and matched by `\s`, so
1825
+ * without the check a byte-order mark beside the braces would be silently
1826
+ * accepted while its zero-width siblings were not. Rejecting here is what makes
1827
+ * the write gates built on this predicate (`validateWholeSecretReference`, the
1828
+ * webhook `config` credential rule) refuse such a value at configuration time
1829
+ * rather than storing a row that can only fail at use time.
1830
+ */
1831
+ export declare function isWholeSecretReference(value: string | null | undefined): boolean;
1832
+ /**
1833
+ * The `signingSecret` rule a webhook's verification scheme carries, decided
1834
+ * from the declaration alone (#3320).
1835
+ *
1836
+ * `signingSecret` is reference-only (#2254): a whole `{{secrets.KEY}}`
1837
+ * reference naming an app secret, and nothing else. Which schemes need one,
1838
+ * whether one was supplied, and whether the supplied value is a reference are
1839
+ * all answerable from the file — so they belong in the `config push` preflight,
1840
+ * which aborts before anything is applied, rather than in the apply loop where
1841
+ * a refusal lands after sibling entities are already written.
1842
+ *
1843
+ * That is the whole reason this module exists here rather than beside the rest
1844
+ * of the webhook write pipeline: `src/config-surface/` is vendored verbatim
1845
+ * into `cli/src/lib/generated-config-surfaces.ts`, so the CLI runs the server's
1846
+ * rule instead of a restatement of it, and a change that is not regenerated
1847
+ * fails `gen-config-surfaces.mjs --check`.
1848
+ *
1849
+ * ── What is deliberately NOT here ─────────────────────────────────────────
1850
+ *
1851
+ * Everything that needs the app's state: whether the referenced secret exists,
1852
+ * whether the scheme's `config` is valid under this environment's JWKS policy,
1853
+ * the per-app row cap, a key a standalone webhook already holds. Those stay in
1854
+ * `src/app-api/services/webhook-settings-validation.ts`, which has `Env`. A
1855
+ * local copy of them would be a preflight that gives a false all-clear — and
1856
+ * the residue is then app-state-dependent by construction rather than by
1857
+ * accident of where a rule happened to live.
1858
+ */
1859
+ /**
1860
+ * Schemes that don't carry an HMAC `signingSecret`. These either store no key
1861
+ * material at all (`none`) or store it under `AppWebhook.config` instead:
1862
+ * `discord` puts the application public key in `config.publicKey`, `jwt` puts
1863
+ * a JWKS in `config.jwt.jwks`, and `plaid` fetches keys from Plaid using the
1864
+ * API credentials referenced in `config.plaid`.
1865
+ */
1866
+ export declare const SCHEMES_WITHOUT_SIGNING_SECRET: readonly string[];
1867
+ export declare function requiresSigningSecret(scheme: unknown): boolean;
1868
+ /** The coded refusals, so a client can branch without matching prose. */
1869
+ export declare const SIGNING_SECRET_MUST_BE_SECRET_REF = "SIGNING_SECRET_MUST_BE_SECRET_REF";
1870
+ export declare const SIGNING_SECRET_NOT_SUPPORTED_FOR_SCHEME = "SIGNING_SECRET_NOT_SUPPORTED_FOR_SCHEME";
1871
+ /**
1872
+ * The rule ids this module owns, declared on the `function` surface as
1873
+ * `preflight` and on the `webhook` surface as `apply` (#3374) — one rule, two
1874
+ * surfaces, one handler. `whole-secret-reference` is generic on purpose:
1875
+ * `validateWholeSecretReference` is reused by the Google client secret and by
1876
+ * both webhook controllers under their own labels and codes.
1877
+ */
1878
+ export declare const SIGNING_SECRET_RULE_IDS: readonly ["signing-secret-required", "whole-secret-reference", "signing-secret-not-supported"];
1879
+ type SigningSecretRuleId = (typeof SIGNING_SECRET_RULE_IDS)[number];
1880
+ /**
1881
+ * A refusal from this rule. `plain` marks the ones the admin webhook create
1882
+ * answered as a bare text body rather than coded JSON — an observable
1883
+ * distinction, so it travels with the error rather than being flattened.
1884
+ * `ruleId` names the rule and never reaches the wire: every reader picks
1885
+ * `message`, `code` and `plain`.
1886
+ */
1887
+ export interface SigningSecretRuleError {
1888
+ ruleId: SigningSecretRuleId;
1889
+ message: string;
1890
+ code?: string;
1891
+ plain?: boolean;
1892
+ }
1893
+ /** The reference-only message, shared by every field that carries one. */
1894
+ export declare function wholeSecretReferenceMessage(label: string): string;
1895
+ /**
1896
+ * Is this value a whole `{{secrets.KEY}}` reference? Returns the refusal a
1897
+ * caller renders, or null.
1898
+ *
1899
+ * `isWholeSecretReference`, never `isSecretTemplate`: a *contains* test admits
1900
+ * `sk_live_abcd{{secrets.SUFFIX}}`, which stores most of a working credential
1901
+ * in cleartext.
1902
+ */
1903
+ export declare function validateWholeSecretReference(label: string, value: unknown, code: string): SigningSecretRuleError | null;
1904
+ /**
1905
+ * The whole file-decidable `signingSecret` rule, in the order the standalone
1906
+ * webhook create ran it: a required secret must be present, a present one must
1907
+ * be a whole reference, and a scheme that carries no secret must not be given
1908
+ * one.
1909
+ *
1910
+ * Returns null when the declaration is acceptable — which does NOT mean the
1911
+ * write will succeed: the referenced key still has to exist, and that is the
1912
+ * server's question.
1913
+ */
1914
+ export declare function validateSigningSecretDeclaration(input: {
1915
+ verificationScheme: string;
1916
+ signingSecret?: unknown;
1917
+ }): SigningSecretRuleError | null;
1918
+ /**
1919
+ * The workflow rules two runners share (#3374, project `cli-server-rule-parity`
1920
+ * phase 2; intent §Success criteria 3).
1921
+ *
1922
+ * ── One predicate, two messages ──────────────────────────────────────────
1923
+ *
1924
+ * `runAs = "system"` beside a non-empty `accessRule` is dead config: a system
1925
+ * run can only be started by the system and never evaluates its access rule
1926
+ * (#1258, broadening #1172). The server refused it at save time
1927
+ * (`validateWorkflowIdentityConfig`) and the CLI refused it in the push
1928
+ * preflight (`validateWorkflowIdentity`), and the two carried the conjunction
1929
+ * byte-for-byte as separate copies kept in step by a comment. This module is
1930
+ * the one copy: it decides, and returns a STRUCTURED violation — the rule id
1931
+ * and the server's sentence — that each site renders in its own words. The
1932
+ * server pushes the sentence into its `string[]`; the CLI keeps its own hint,
1933
+ * which names the preflight remedy. Neither message changed.
1934
+ *
1935
+ * ── Why a `*-rules.ts` module ────────────────────────────────────────────
1936
+ *
1937
+ * The registry's unclaimed-export check (`findUnclaimedRuleModuleExports`)
1938
+ * keys on this name under `src/config-surface/`: every exported function here
1939
+ * is a rule, so one no surface declares fails `cli-unit-tests`. Shared
1940
+ * predicates that are not rules live elsewhere (`webhook-signing-secret.ts`).
1941
+ * The module is vendored into the CLI artifact like the rest of the
1942
+ * directory, which is what lets `workflow`'s declaration call the rule
1943
+ * `preflight`.
1944
+ */
1945
+ /** The rule ids this module owns — the union type below anchors them (#3373). */
1946
+ export declare const WORKFLOW_RULE_IDS: readonly ["system-access-rule"];
1947
+ type WorkflowRuleId = (typeof WORKFLOW_RULE_IDS)[number];
1948
+ /** A violation of one of this module's rules, for a site to render. */
1949
+ export interface WorkflowRuleViolation extends RuleRefusal<WorkflowRuleId> {
1950
+ }
1951
+ /**
1952
+ * `runAs = "system"` with a non-empty string `accessRule`, or null.
1953
+ *
1954
+ * Exactly the conjunction both sites carried: a default, unset, empty or
1955
+ * whitespace-only rule is no rule, and a non-string one (`accessRule = false`)
1956
+ * is malformed input for another check to name, not dead config. The message
1957
+ * is the server's save-time sentence; the CLI renders its own hint from the
1958
+ * same answer.
1959
+ */
1960
+ export declare function checkWorkflowSystemAccessRule(input: {
1961
+ runAs?: unknown;
1962
+ accessRule?: unknown;
1963
+ }): WorkflowRuleViolation | null;
1964
+ export declare const WORKFLOW_SURFACE: ConfigObjectSurface;
1965
+ /**
1966
+ * Cron-expression and timezone VALIDITY — the half of `src/cron-parser.ts`
1967
+ * both runners need (#3376, project `cli-server-rule-parity` phase 4).
1968
+ *
1969
+ * ── Why this module exists ───────────────────────────────────────────────
1970
+ *
1971
+ * A malformed cron expression and an unknown timezone are both decidable from
1972
+ * the authored file, so the intent lands both rules `preflight` — which under
1973
+ * this project's vocabulary means the implementation lives here, under
1974
+ * `src/config-surface/`, and is vendored into the CLI artifact.
1975
+ *
1976
+ * It got here by a SPLIT, not a move. `src/cron-parser.ts` is 415 lines, and
1977
+ * roughly 290 of them are timezone-aware scheduling arithmetic — "when does
1978
+ * this expression next fire?" — that only the cron Durable Object runs.
1979
+ * Vendoring is wholesale: the generator concatenates this whole directory, so
1980
+ * moving the file would have shipped that scheduler into the published CLI
1981
+ * package. The validator moved; the scheduler stayed; `src/cron-parser.ts`
1982
+ * re-exports what moved, so no server import changed.
1983
+ *
1984
+ * The scheduler's two entry points are deliberately not NAMED here: a CLI
1985
+ * unit test asserts the artifact does not contain either identifier, which is
1986
+ * how "the artifact carries the validator only" is kept true mechanically
1987
+ * rather than by review.
1988
+ *
1989
+ * ── Not a rules module ───────────────────────────────────────────────────
1990
+ *
1991
+ * `parseCron` THROWS, eight different sentences, and `tests/unit/
1992
+ * cron-parser.test.ts` pins that it throws. A module exporting a `*_RULE_IDS`
1993
+ * list may not contain a `throw` outside its one refusal constructor
1994
+ * (`findUnanchoredRefusals`, #3373), so the rule that renders these answers as
1995
+ * refusals is a separate module, `cron-rules.ts`, and this one is a plain
1996
+ * shared-predicate module — the `webhook-signing-secret.ts` / `function-mode.ts`
1997
+ * precedent.
1998
+ *
1999
+ * Pure: no models, no tenant context, no `env` (see `types.ts` §Purity).
2000
+ * `Intl.DateTimeFormat` is the one platform call, and it is the timezone
2001
+ * question itself.
2002
+ *
2003
+ * Supported fields (standard POSIX order):
2004
+ * minute (0-59)
2005
+ * hour (0-23)
2006
+ * day-of-month (1-31)
2007
+ * month (1-12)
2008
+ * day-of-week (0-6, where 0 = Sunday; 7 also accepted as Sunday)
2009
+ *
2010
+ * Supported syntax per field:
2011
+ * - "*" any value
2012
+ * - "5" exact value
2013
+ * - "5-10" range (inclusive)
2014
+ * - "star/step" every N values within the full range (e.g. "* /5" => 0,5,10,...)
2015
+ * - "a-b/step" every N values within a range
2016
+ * - "1,2,3" comma-separated list of values or ranges
2017
+ *
2018
+ * Not supported: month/day names, "?", "L", "W", "#", last-day modifiers.
2019
+ */
2020
+ export interface ParsedCron {
2021
+ minutes: Set<number>;
2022
+ hours: Set<number>;
2023
+ daysOfMonth: Set<number>;
2024
+ months: Set<number>;
2025
+ daysOfWeek: Set<number>;
2026
+ dayOfMonthWild: boolean;
2027
+ dayOfWeekWild: boolean;
2028
+ }
2029
+ export declare function parseCron(expr: string): ParsedCron;
2030
+ /**
2031
+ * The message `parseCron` would throw for `expr`, or null when it parses.
2032
+ *
2033
+ * The same grammar, asked as a question instead of as an exception, because
2034
+ * both callers want the sentence rather than the control flow: the CLI's push
2035
+ * preflight collects one message per broken entry, and the standalone cron
2036
+ * routes render theirs into a 400 body. `expr` is typed `unknown` because it
2037
+ * arrives as an authored TOML value, where it can be anything at all.
2038
+ */
2039
+ export declare function cronExpressionError(expr: unknown): string | null;
2040
+ /**
2041
+ * Whether `Intl.DateTimeFormat` accepts `name` as a timezone.
2042
+ *
2043
+ * This is THE timezone check — before #3376 the identical probe was written
2044
+ * out three times (the function push boundary and the standalone create and
2045
+ * update). Each of those sites keeps its own sentence and its own defaulting;
2046
+ * what they now share is this answer. A non-string is false rather than a
2047
+ * throw, for the same reason as above.
2048
+ */
2049
+ export declare function isValidTimezone(name: unknown): boolean;
2050
+ /**
2051
+ * The cron schedule rules two runners share (#3376, project
2052
+ * `cli-server-rule-parity` phase 4; intent §Success criteria 6).
2053
+ *
2054
+ * ── One implementation, two runners ──────────────────────────────────────
2055
+ *
2056
+ * A cron expression the grammar refuses, and a timezone `Intl` does not know,
2057
+ * are both decidable from the authored file. Before this issue only the SERVER
2058
+ * decided them, inside the apply loop: a `functions/<key>.toml` carrying
2059
+ * either passed `config push`'s preflight, sibling entities were written, and
2060
+ * the function alone was refused — while the command promises that a refusal
2061
+ * means nothing was applied. Now `cli/src/lib/function-sync.ts` and
2062
+ * `src/services/function-trigger-validation.ts` both call the rule below, and
2063
+ * the sentence an author reads is the same on either side of the wire because
2064
+ * it is built in one place.
2065
+ *
2066
+ * ── Why this is a `*-rules.ts` module and the parser is not ──────────────
2067
+ *
2068
+ * The registry's unclaimed-export check (`findUnclaimedRuleModuleExports`)
2069
+ * keys on this name under `src/config-surface/`: every exported function here
2070
+ * is a rule, so one no surface declares fails `cli-unit-tests`. The anchor
2071
+ * also forbids a `throw` outside the one refusal constructor — and `parseCron`
2072
+ * throws eight different sentences, which `tests/unit/cron-parser.test.ts`
2073
+ * pins. So the grammar and the `Intl` probe live next door in
2074
+ * `cron-expression.ts`, which is a shared-predicate module rather than a rules
2075
+ * module, and this one only decides and renders.
2076
+ *
2077
+ * ── What is NOT shared ───────────────────────────────────────────────────
2078
+ *
2079
+ * The standalone cron routes ask the same two predicates and render their own
2080
+ * `Invalid cron expression: …` / `Invalid timezone: …`, with their own
2081
+ * defaulting (create reads an absent timezone as UTC, update does not). That
2082
+ * is intent assumption 2 in the form its own fallback describes, and the shape
2083
+ * `workflow-rules.ts` set in phase 2: one predicate, each site's message and
2084
+ * defaulting preserved. No refusal message changed anywhere.
2085
+ */
2086
+ /** The rule ids this module owns — the union type below anchors them (#3373). */
2087
+ export declare const CRON_TRIGGER_RULE_IDS: readonly ["cron-trigger-expression", "cron-trigger-timezone"];
2088
+ type CronTriggerRuleId = (typeof CRON_TRIGGER_RULE_IDS)[number];
2089
+ /** A refused cron entry: the rule and the sentence the site renders. */
2090
+ export type CronTriggerRuleRefusal = RuleRefusal<CronTriggerRuleId>;
2091
+ /**
2092
+ * One `[[function.triggers.cron]]` entry's schedule, or null.
2093
+ *
2094
+ * Expression first, then timezone, which is the order the push boundary ran
2095
+ * them in — so an entry broken both ways still answers with the expression's
2096
+ * refusal, exactly as before. An unset or empty `timezone` reads as UTC, again
2097
+ * exactly as before: the boundary's `entry.timezone || "UTC"`.
2098
+ */
2099
+ export declare function checkCronTriggerEntry(entry: {
2100
+ name: string;
2101
+ cron: string;
2102
+ timezone?: string;
2103
+ }): CronTriggerRuleRefusal | null;
2104
+ /**
2105
+ * The prompt config's reasoning controls, resolved onto each provider's own
2106
+ * spelling — issue #3358.
2107
+ *
2108
+ * A `[[configs]]` entry states EITHER `reasoningEffort` (a provider-neutral
2109
+ * level, `none` through `high`) or `reasoningBudget` (a token count), never
2110
+ * both. This module is the whole translation: every authored pair either maps
2111
+ * onto the provider's native key or is REFUSED with a message naming the
2112
+ * remedy. Nothing is dropped — that was the trap `providerConfig` already laid
2113
+ * in the tree (stored, serialized, round-tripped, and never read at execution),
2114
+ * and the issue's third success criterion is precisely that a config asking for
2115
+ * something a provider cannot express fails rather than silently doing nothing.
2116
+ *
2117
+ * Pure and dependency-free, like every module under `src/config-surface/`: the
2118
+ * server's create/update handlers, the executor, and the vendored CLI artifact
2119
+ * all read this one copy, so a refusal at push and a refusal at execution
2120
+ * cannot disagree.
2121
+ *
2122
+ * Provider facts this encodes:
2123
+ *
2124
+ * - OpenRouter takes a unified `reasoning` block: `{ effort }`,
2125
+ * `{ max_tokens }`, or `{ enabled: false }` to decline it. `max_tokens` is an
2126
+ * exact bound on budget-native models and is translated to the nearest
2127
+ * effort level on effort-only ones, so it is documented as a bound, not a
2128
+ * guarantee — `metrics.reasoningTokens` is the measure of what was spent.
2129
+ * Default routing lets an endpoint IGNORE a parameter it does not support,
2130
+ * so a request carrying `reasoning` also carries
2131
+ * `provider: { require_parameters: true }`: an endpoint that cannot honor it
2132
+ * is refused by OpenRouter and surfaces as a failed execution rather than a
2133
+ * silent drop.
2134
+ * - Gemini 3.x expresses thinking as a LEVEL
2135
+ * (`thinkingConfig.thinkingLevel`) and cannot turn it off; `thinkingBudget`
2136
+ * is accepted there only for backward compatibility and is translated to a
2137
+ * level rather than honored as a bound, so a numeric budget is refused with
2138
+ * a pointer at `reasoningEffort`.
2139
+ * - Gemini 2.5 expresses it as a numeric BUDGET
2140
+ * (`thinkingConfig.thinkingBudget`); `0` turns thinking off on Flash and
2141
+ * Flash-Lite, while Pro has a floor of 128 and answers 400 for less.
2142
+ * - Gemini 2.0 and earlier have no thinking control at all.
2143
+ */
2144
+ /** The provider-neutral effort levels a config may state. */
2145
+ export declare const REASONING_EFFORTS: readonly ["none", "minimal", "low", "medium", "high"];
2146
+ export type ReasoningEffort = (typeof REASONING_EFFORTS)[number];
2147
+ /** The smallest budget Gemini 2.5 Pro accepts; it cannot stop thinking. */
2148
+ export declare const GEMINI_PRO_MIN_THINKING_BUDGET = 128;
2149
+ export interface PromptReasoningInput {
2150
+ provider?: string | null;
2151
+ model?: string | null;
2152
+ reasoningEffort?: string | null;
2153
+ reasoningBudget?: number | string | null;
2154
+ }
2155
+ /** What the executor adds to the upstream request, or `null` for "unset". */
2156
+ export type PromptReasoningDirective = {
2157
+ provider: "openrouter";
2158
+ /** The OpenRouter `reasoning` block. */
2159
+ reasoning: Record<string, unknown>;
2160
+ /**
2161
+ * `provider: { require_parameters: true }` — routing restricted to
2162
+ * endpoints that support every parameter in the request.
2163
+ */
2164
+ requireParameters: true;
2165
+ } | {
2166
+ provider: "gemini";
2167
+ /** The `generationConfig.thinkingConfig` block. */
2168
+ thinkingConfig: Record<string, unknown>;
2169
+ };
2170
+ export type PromptReasoningResolution = {
2171
+ ok: true;
2172
+ directive: PromptReasoningDirective | null;
2173
+ } | {
2174
+ ok: false;
2175
+ error: string;
2176
+ };
2177
+ /**
2178
+ * How a Gemini model spells its thinking control.
2179
+ *
2180
+ * `level` — Gemini 3.x, `thinkingLevel`, cannot be turned off.
2181
+ * `budget` — Gemini 2.5, `thinkingBudget` in tokens.
2182
+ * `none` — Gemini 2.0 and earlier, no control at all.
2183
+ */
2184
+ export type GeminiReasoningFamily = "level" | "budget" | "none";
2185
+ export declare function geminiReasoningFamily(model: string): GeminiReasoningFamily;
2186
+ /** Gemini Pro: the tier that cannot stop thinking in either family. */
2187
+ export declare function isGeminiProModel(model: string): boolean;
2188
+ /** Is EITHER reasoning key stated on this config? */
2189
+ export declare function hasPromptReasoning(input: PromptReasoningInput): boolean;
2190
+ /**
2191
+ * Resolve an authored pair onto the provider's spelling.
2192
+ *
2193
+ * Returns `{ ok: true, directive: null }` when neither key is set — the case
2194
+ * that must leave the upstream payload byte-identical to what it was before
2195
+ * this issue — a directive when the pair maps, and `{ ok: false, error }` when
2196
+ * it does not. The error text is what `config push` reports as the file's
2197
+ * error and what the admin routes answer 400 with.
2198
+ */
2199
+ export declare function resolvePromptReasoning(input: PromptReasoningInput): PromptReasoningResolution;
2200
+ /**
2201
+ * What a prompt's KIND admits — issue #3626.
2202
+ *
2203
+ * A prompt declares `[prompt] kind = "chat" | "decisions" | "agent"`. The kind decides
2204
+ * the input envelope (`variables` rendered into templates for chat, a `state`
2205
+ * value for decisions), the provider endpoint the executor posts to, and which
2206
+ * `[configs.<kind>]` block a `[[configs]]` entry may carry. Adding a kind is a
2207
+ * group declaration plus its fields, not another round of implicit
2208
+ * discrimination: the earlier design inferred "this is a decisions config" from
2209
+ * the presence of `questions` on a table otherwise shaped for chat, and refused
2210
+ * the nine chat keys one by one.
2211
+ *
2212
+ * This module is the whole rule. `resolvePromptKind` is called by the CLI's
2213
+ * push preflight through the vendored artifact, by `createAppPrompt`,
2214
+ * `createPromptConfig` and `updatePromptConfig`, so a refusal at push and a
2215
+ * refusal at the admin route cannot disagree — the `resolvePromptReasoning`
2216
+ * posture of #3358, for the same reason.
2217
+ *
2218
+ * Pure and dependency-free, like every module under `src/config-surface/`.
2219
+ */
2220
+ /**
2221
+ * The kinds a prompt may declare. An omitted `kind` is `chat`.
2222
+ *
2223
+ * #3798 — `agent` is a prompt run turn by turn in a session: no template, no
2224
+ * output schema, never run single-shot. Its tools and events are declared in
2225
+ * `[prompt.agent]` (`agent-declaration.ts`); its configs carry
2226
+ * `[configs.agent]`.
2227
+ */
2228
+ export declare const PROMPT_KINDS: readonly ["chat", "decisions", "agent"];
2229
+ export type PromptKind = (typeof PROMPT_KINDS)[number];
2230
+ /**
2231
+ * The nine chat settings that existed before `[configs.chat]` did. Only these
2232
+ * keep the deprecated FLAT spelling (#3642): a key added to the block later was
2233
+ * never written flat by any file, so it has none (the `questions` posture,
2234
+ * SO3626-013).
2235
+ */
2236
+ export declare const LEGACY_FLAT_CHAT_KEYS: readonly ["systemPrompt", "userPromptTemplate", "temperature", "topP", "maxTokens", "outputFormat", "outputSchema", "reasoningEffort", "reasoningBudget"];
2237
+ /**
2238
+ * The settings that describe a CHAT COMPLETION and nothing else. They are
2239
+ * authored under `[configs.chat]`; the flat spelling of the nine legacy keys
2240
+ * is deprecated (#3642).
2241
+ *
2242
+ * #3801 — `strictOutput`, the opt-in that sends `[prompt].outputSchema` as a
2243
+ * strict `json_schema` on OpenRouter (`prompt-strict-output.ts`). Not an agent
2244
+ * key (§D1: an agent has no output schema), so the agent arm refuses it.
2245
+ */
2246
+ export declare const CHAT_CONFIG_KEYS: readonly ["systemPrompt", "userPromptTemplate", "temperature", "topP", "maxTokens", "outputFormat", "outputSchema", "reasoningEffort", "reasoningBudget", "strictOutput"];
2247
+ export type ChatConfigKey = (typeof CHAT_CONFIG_KEYS)[number];
2248
+ /** The settings that describe a DECISIONS request. */
2249
+ export declare const DECISIONS_CONFIG_KEYS: readonly ["questions"];
2250
+ /**
2251
+ * #3798 — the settings of an AGENT's model round: the chat block less
2252
+ * `userPromptTemplate` (the model sees each message as sent), `outputFormat`
2253
+ * and `outputSchema` (an agent's final answer is text; anything structured is
2254
+ * a tool call). The same wire keys as chat, authored under `[configs.agent]`.
2255
+ */
2256
+ export declare const AGENT_CONFIG_KEYS: readonly ["systemPrompt", "temperature", "topP", "maxTokens", "reasoningEffort", "reasoningBudget"];
2257
+ /**
2258
+ * The WIRE field names each kind's block holds. The config surface declares the
2259
+ * same grouping through `ConfigField.tomlGroup`, and the drift guard asserts
2260
+ * the two agree — so a chat key added to the surface without a home here (or
2261
+ * the reverse) fails `cli-unit-tests` rather than being accepted under a
2262
+ * decisions prompt.
2263
+ */
2264
+ export declare const PROMPT_KIND_BLOCKS: Readonly<Record<PromptKind, readonly string[]>>;
2265
+ /** The question types TypeSafe's System One models answer. */
2266
+ export declare const DECISIONS_QUESTION_TYPES: readonly ["choice", "score", "noul"];
2267
+ export type DecisionsQuestionType = (typeof DECISIONS_QUESTION_TYPES)[number];
2268
+ /**
2269
+ * #3813 — where a `choice` question's options come from. `"static"`: the
2270
+ * config's `criteria` table. `"dynamic"`: each run supplies the table as
2271
+ * `variables.criteria.<question>`. Required on every `choice` question, with
2272
+ * no default, and a platform key: it is removed before the provider request.
2273
+ */
2274
+ export declare const DECISIONS_CRITERIA_SOURCES: readonly ["static", "dynamic"];
2275
+ export type DecisionsCriteriaSource = (typeof DECISIONS_CRITERIA_SOURCES)[number];
2276
+ /**
2277
+ * #3813 — the code a decisions run carries when the options it was asked to
2278
+ * choose between are refused before the provider call: malformed per-run
2279
+ * criteria, criteria for a question that does not take them, or a stored
2280
+ * `choice` question that does not say where its options come from.
2281
+ */
2282
+ export declare const PROMPT_CRITERIA_INVALID = "PROMPT_CRITERIA_INVALID";
2283
+ /**
2284
+ * The prompt's kind, normalized.
2285
+ *
2286
+ * Every reader goes through this: rows created before #3626 carry no `kind`
2287
+ * attribute at all, and an absent one is `chat` everywhere — the detail route,
2288
+ * pull, diff, execution and codegen.
2289
+ */
2290
+ export declare function promptKindOf(prompt: unknown): PromptKind;
2291
+ /** The config values the rule reads — the wire spelling, not the TOML one. */
2292
+ export interface PromptKindConfigInput {
2293
+ systemPrompt?: unknown;
2294
+ userPromptTemplate?: unknown;
2295
+ temperature?: unknown;
2296
+ topP?: unknown;
2297
+ maxTokens?: unknown;
2298
+ outputFormat?: unknown;
2299
+ outputSchema?: unknown;
2300
+ reasoningEffort?: unknown;
2301
+ reasoningBudget?: unknown;
2302
+ /** #3801 — a chat key; the agent and decisions arms refuse it. */
2303
+ strictOutput?: unknown;
2304
+ questions?: unknown;
2305
+ }
2306
+ export interface PromptKindInput {
2307
+ /** `[prompt].kind`. `null`, `undefined` and `""` are unset, meaning `chat`. */
2308
+ kind?: unknown;
2309
+ provider?: unknown;
2310
+ model?: unknown;
2311
+ /**
2312
+ * The EFFECTIVE config: the payload value where the request carries one, the
2313
+ * stored value otherwise. `outputSchema` here is the CONFIG's own field —
2314
+ * never the prompt-level schema, which is legal on either kind (§3, SO3626-003).
2315
+ */
2316
+ config: PromptKindConfigInput;
2317
+ }
2318
+ export type PromptKindResolution = {
2319
+ ok: true;
2320
+ kind: "chat";
2321
+ } | {
2322
+ ok: true;
2323
+ kind: "decisions";
2324
+ questions: Record<string, unknown>;
2325
+ } | {
2326
+ ok: true;
2327
+ kind: "agent";
2328
+ } | {
2329
+ ok: false;
2330
+ error: string;
2331
+ code?: string;
2332
+ };
2333
+ /**
2334
+ * The one rule: does this (kind, provider, config) triple describe something
2335
+ * the platform can run?
2336
+ *
2337
+ * `{ ok: true, kind: "chat" }` is today's behavior byte for byte. The decisions
2338
+ * arm returns the NORMALIZED questions so the caller stores one spelling
2339
+ * whichever transport the author used.
2340
+ */
2341
+ export declare function resolvePromptKind(input: PromptKindInput): PromptKindResolution;
2342
+ export type DecisionsRunQuestionsResolution = {
2343
+ ok: true;
2344
+ questions: Record<string, unknown>;
2345
+ } | {
2346
+ ok: false;
2347
+ error: string;
2348
+ };
2349
+ /**
2350
+ * #3813 — the questions one run sends to the provider.
2351
+ *
2352
+ * `questions` is the RAN config's declaration, as stored; `runCriteria` is
2353
+ * the run's `variables.criteria` (`undefined` when the run sent none). A
2354
+ * `"dynamic"` question is given the run's table as its `criteria`; every
2355
+ * question loses `criteriaSource`, which is the platform's key and not the
2356
+ * endpoint's. The config still owns each question's name, type and
2357
+ * instructions: a run can supply options only for a question declared
2358
+ * `"dynamic"`, so nothing a run sends can change what is being asked.
2359
+ *
2360
+ * Refuses, before any provider call: a `variables.criteria` that is not an
2361
+ * object; criteria for a name the config does not declare, for a `"static"`
2362
+ * question, or for a `score` or `noul` one; a `"dynamic"` question with no
2363
+ * table or a table the criteria rule refuses; and a stored `choice` question
2364
+ * with no usable `criteriaSource` — a config written before the key existed,
2365
+ * which is refused rather than given a silent default.
2366
+ *
2367
+ * Pure: the stored questions object is never mutated.
2368
+ */
2369
+ export declare function resolveDecisionsRunQuestions(questions: Record<string, unknown>, runCriteria: unknown): DecisionsRunQuestionsResolution;
2370
+ /** What the hoist did to one `[[configs]]` entry. */
2371
+ export interface DeprecatedChatKeyHoist {
2372
+ /** A COPY of the entry with the flat chat keys moved under `chat`. */
2373
+ entry: Record<string, unknown>;
2374
+ /** The flat keys that were moved, sorted — what the warning names. */
2375
+ moved: string[];
2376
+ /** Keys set BOTH flat and under `[configs.chat]`; the caller refuses these. */
2377
+ conflicts: string[];
2378
+ }
2379
+ /**
2380
+ * Move the deprecated flat chat keys of one `[[configs]]` entry under `chat`
2381
+ * — #3626 §4, the blob-bucket `accessPolicy` precedent made reusable.
2382
+ *
2383
+ * Push keeps accepting the nine keys flat so no existing file breaks, and pull
2384
+ * rewrites them, so one pull-then-push migrates a file. A key present in BOTH
2385
+ * spellings is not merged: the grouped value is left standing and the key is
2386
+ * reported in `conflicts`, which the caller turns into a refusal naming the
2387
+ * entry. Nothing else in the entry is touched — `providerConfig` is
2388
+ * provider-keyed rather than chat-keyed (D3626-002) and `questions` has no flat
2389
+ * spelling at all (SO3626-013).
2390
+ */
2391
+ export declare function hoistDeprecatedChatKeys(entry: unknown): DeprecatedChatKeyHoist;
2392
+ /**
2393
+ * Strict output for a chat config — issue #3801 (project `agents`, §D6).
2394
+ *
2395
+ * A chat prompt's OpenRouter request asks for JSON mode (`outputFormat =
2396
+ * "json"`) and the answer is checked AFTERWARDS against `[prompt].outputSchema`
2397
+ * (`derivePromptRunEnvelope`). A config that sets `[configs.chat].strictOutput
2398
+ * = true` asks the provider to constrain the answer instead: the prompt-level
2399
+ * schema is sent as `response_format: { type: "json_schema", json_schema: {
2400
+ * name: "output", strict: true, schema } }`, with `provider: {
2401
+ * require_parameters: true }` so OpenRouter refuses an endpoint that would
2402
+ * ignore it rather than dropping it in silence (the #3358 posture).
2403
+ *
2404
+ * This module is the whole rule, and it is read in both places a config is
2405
+ * written: the admin routes, and (vendored) the CLI's push preflight, so a
2406
+ * refusal at push and at the route cannot disagree — `resolvePromptReasoning`
2407
+ * and `resolvePromptKind`'s posture.
2408
+ *
2409
+ * Which schema is sent is never ambiguous: always the PROMPT's (§D6), so a
2410
+ * config that also declares its own `outputSchema` is refused. Five refusals,
2411
+ * in this order, each with its own code:
2412
+ *
2413
+ * - `PROMPT_STRICT_OUTPUT_INVALID` — the value is not a boolean.
2414
+ * - `PROMPT_STRICT_OUTPUT_SCHEMA_CONFLICT` — the config declares its own
2415
+ * `outputSchema` too.
2416
+ * - `PROMPT_STRICT_OUTPUT_PROVIDER_UNSUPPORTED` — not OpenRouter. A Gemini
2417
+ * config already constrains its request through `responseSchema`.
2418
+ * - `PROMPT_STRICT_OUTPUT_FORMAT_CONFLICT` — `outputFormat = "text"`.
2419
+ * - `PROMPT_STRICT_OUTPUT_SCHEMA_MISSING` — the prompt declares no usable
2420
+ * `[prompt].outputSchema`.
2421
+ *
2422
+ * The first four are about the config itself and apply whatever its status.
2423
+ * The last depends on PROMPT-level state that can change under a config, so it
2424
+ * is skipped for an ARCHIVED config (DSO-3801-002): a retired strict config may
2425
+ * be pulled, pushed and renamed after its prompt dropped the schema, and the
2426
+ * requirement is enforced when a config is or becomes active — the #3799
2427
+ * posture, "an archive is never checked".
2428
+ *
2429
+ * Pure and dependency-free, like every module under `src/config-surface/`.
2430
+ */
2431
+ /** Every code the rule answers, in the order it checks. */
2432
+ export declare const PROMPT_STRICT_OUTPUT_CODES: readonly ["PROMPT_STRICT_OUTPUT_INVALID", "PROMPT_STRICT_OUTPUT_SCHEMA_CONFLICT", "PROMPT_STRICT_OUTPUT_PROVIDER_UNSUPPORTED", "PROMPT_STRICT_OUTPUT_FORMAT_CONFLICT", "PROMPT_STRICT_OUTPUT_SCHEMA_MISSING"];
2433
+ export type PromptStrictOutputErrorCode = (typeof PROMPT_STRICT_OUTPUT_CODES)[number];
2434
+ /**
2435
+ * The one code a RUN can also carry: the executor refuses a strict config whose
2436
+ * stored prompt schema is absent or unusable before any provider call, rather
2437
+ * than downgrading the request to JSON mode.
2438
+ */
2439
+ export declare const PROMPT_STRICT_OUTPUT_SCHEMA_MISSING = "PROMPT_STRICT_OUTPUT_SCHEMA_MISSING";
2440
+ /**
2441
+ * `json_schema.name`. The OpenAI-shaped API requires one and the executor has
2442
+ * no prompt key to hand, so it is fixed — the same request for the same schema.
2443
+ */
2444
+ export declare const STRICT_OUTPUT_SCHEMA_NAME = "output";
2445
+ export interface PromptStrictOutputInput {
2446
+ provider?: unknown;
2447
+ /** `[configs.chat].strictOutput` as authored or stored. */
2448
+ strictOutput?: unknown;
2449
+ outputFormat?: unknown;
2450
+ /** The CONFIG's own `outputSchema` — the one strict output never sends. */
2451
+ configOutputSchema?: unknown;
2452
+ /** `[prompt].outputSchema` — the one it does. */
2453
+ promptOutputSchema?: unknown;
2454
+ /** The config's effective status; absent is `active`. */
2455
+ status?: unknown;
2456
+ }
2457
+ export type PromptStrictOutputResolution = {
2458
+ ok: true;
2459
+ strict: boolean;
2460
+ } | {
2461
+ ok: false;
2462
+ code: PromptStrictOutputErrorCode;
2463
+ error: string;
2464
+ };
2465
+ /** Does this config opt in? Only a literal `true` does. */
2466
+ export declare function isStrictOutput(value: unknown): boolean;
2467
+ /**
2468
+ * The schema strict output sends, from a stored or authored
2469
+ * `[prompt].outputSchema`: a JSON object (or its text), else `null`.
2470
+ */
2471
+ export declare function strictOutputSchemaOf(value: unknown): Record<string, unknown> | null;
2472
+ /**
2473
+ * Is this (provider, strictOutput, outputFormat, schemas, status) a config the
2474
+ * platform can run as strict — or not strict at all?
2475
+ */
2476
+ export declare function resolvePromptStrictOutput(input: PromptStrictOutputInput): PromptStrictOutputResolution;
2477
+ /**
2478
+ * What an agent prompt may declare — issue #3798 (project `agents`, §D1).
2479
+ *
2480
+ * An agent is a prompt of `kind = "agent"`. Its configs carry `[configs.agent]`
2481
+ * (the rule for those is `resolvePromptKind`); its contract lives in ONE
2482
+ * prompt-level block, `[prompt.agent]`: the tools the model may call, the event
2483
+ * kinds members record, the turn context, how history is selected, who answers
2484
+ * a paused call, and the limits an agent may lower but never raise.
2485
+ *
2486
+ * This module is the whole rule for that block. `resolveAgentDeclaration` is
2487
+ * called by the CLI's push preflight through the vendored artifact and by the
2488
+ * admin prompt routes, so a refusal at push and a refusal at the route cannot
2489
+ * disagree — the `resolvePromptKind` posture of #3626.
2490
+ *
2491
+ * STORED AS WRITTEN (DSO-3798-001). The resolver returns the AUTHORED value —
2492
+ * a block written as one JSON string is parsed to the object it encodes, and
2493
+ * nothing is added. `config diff` compares a `json` field by value with no
2494
+ * defaults applied, so a stored declaration with defaults filled in would read
2495
+ * Modified after every push, and `config pull` would write keys the author
2496
+ * never did. The defaults live in one reader instead, `normalizeAgentDeclaration`,
2497
+ * which every consumer (the executor, codegen, the turn engine) calls.
2498
+ *
2499
+ * Every refusal carries a stable code (intent criterion 22) and a refusal lists
2500
+ * EVERY offending item, so an author fixes a declaration in one pass.
2501
+ *
2502
+ * Pure and dependency-free, like every module under `src/config-surface/`.
2503
+ */
2504
+ /** The stable codes every agent agentRefusal this project adds carries. */
2505
+ export declare const AGENT_ERROR_CODES: readonly ["AGENT_DECLARATION_INVALID", "AGENT_TOOL_FUNCTION_MISSING", "AGENT_TOOL_FUNCTION_SCHEMA_MISSING", "AGENT_OUTPUT_SCHEMA_NOT_ALLOWED", "AGENT_CONFIG_KEY_NOT_ALLOWED", "AGENT_NOT_RUNNABLE", "AGENT_TEST_CASE_NOT_SUPPORTED", "AGENT_SCHEMA_NOT_TRANSLATABLE", "AGENT_MODEL_UNKNOWN", "AGENT_MODEL_CAPABILITY_MISSING", "AGENT_MODEL_CAPABILITIES_UNAVAILABLE", "AGENT_ROUND_NOT_AGENT", "AGENT_ROUND_INPUT_INVALID", "AGENT_TOOL_UNKNOWN", "AGENT_TOOL_ARGUMENTS_INVALID", "AGENT_ROUND_TRUNCATED", "AGENT_ROUND_EMPTY"];
2506
+ export type AgentErrorCode = (typeof AGENT_ERROR_CODES)[number];
2507
+ /** One agentRefusal: the code a client branches on, and the sentence a person reads. */
2508
+ export interface AgentRefusal {
2509
+ code: AgentErrorCode;
2510
+ message: string;
2511
+ }
2512
+ /**
2513
+ * The platform maximums. An agent may lower `maxSteps` and `waitLimitSeconds`,
2514
+ * never raise them; the tool and event counts bound what one declaration can
2515
+ * make every turn carry (principle 2).
2516
+ */
2517
+ export declare const AGENT_LIMITS: {
2518
+ readonly maxSteps: 25;
2519
+ readonly waitLimitSeconds: 604800;
2520
+ readonly tools: 64;
2521
+ readonly events: 64;
2522
+ };
2523
+ /**
2524
+ * A tool or event name: the intersection of OpenRouter's and Gemini's
2525
+ * function-name rules, so one declaration maps onto either provider.
2526
+ */
2527
+ export declare const AGENT_NAME: RegExp;
2528
+ export declare const AGENT_ANSWERED_BY: readonly ["initiator", "participants"];
2529
+ export declare const AGENT_TOOL_INVOKE: readonly ["request", "task"];
2530
+ export declare const AGENT_TOOL_HISTORY_SCOPES: readonly ["session", "turn"];
2531
+ export type AgentAnsweredBy = (typeof AGENT_ANSWERED_BY)[number];
2532
+ export type AgentToolInvoke = (typeof AGENT_TOOL_INVOKE)[number];
2533
+ export type AgentToolHistoryScope = (typeof AGENT_TOOL_HISTORY_SCOPES)[number];
2534
+ /** A JSON Schema object, as the declaration holds one. */
2535
+ export type AgentSchema = Record<string, unknown>;
2536
+ /** One `[[prompt.agent.tools]]` entry, as authored. */
2537
+ export interface AgentToolDeclaration {
2538
+ name: string;
2539
+ description: string;
2540
+ /** A server tool: the function whose schemas are the tool's. */
2541
+ function?: string;
2542
+ invoke?: AgentToolInvoke;
2543
+ /** A client tool: answered by a member's client, schemas in the TOML. */
2544
+ runs?: "client";
2545
+ inputSchema?: AgentSchema;
2546
+ outputSchema?: AgentSchema;
2547
+ approval?: boolean;
2548
+ statusText?: string;
2549
+ historyScope?: AgentToolHistoryScope;
2550
+ }
2551
+ /** One `[[prompt.agent.events]]` entry. */
2552
+ export interface AgentEventDeclaration {
2553
+ name: string;
2554
+ schema: AgentSchema;
2555
+ }
2556
+ /** `[prompt.agent]` as authored: every key optional. */
2557
+ export interface AgentDeclaration {
2558
+ answeredBy?: AgentAnsweredBy;
2559
+ maxSteps?: number;
2560
+ waitLimitSeconds?: number;
2561
+ turnContext?: {
2562
+ schema: AgentSchema;
2563
+ function?: string;
2564
+ };
2565
+ history?: {
2566
+ function?: string;
2567
+ maxHistoryChars?: number;
2568
+ };
2569
+ tools?: AgentToolDeclaration[];
2570
+ events?: AgentEventDeclaration[];
2571
+ }
2572
+ /** A tool with its defaults applied. */
2573
+ export type NormalizedAgentTool = AgentToolDeclaration & {
2574
+ approval: boolean;
2575
+ historyScope: AgentToolHistoryScope;
2576
+ };
2577
+ /** The declaration with every default applied — what readers consume. */
2578
+ export interface NormalizedAgentDeclaration {
2579
+ answeredBy: AgentAnsweredBy;
2580
+ maxSteps: number;
2581
+ waitLimitSeconds: number;
2582
+ turnContext: {
2583
+ schema: AgentSchema;
2584
+ function?: string;
2585
+ } | null;
2586
+ history: {
2587
+ function?: string;
2588
+ maxHistoryChars?: number;
2589
+ } | null;
2590
+ tools: NormalizedAgentTool[];
2591
+ events: AgentEventDeclaration[];
2592
+ }
2593
+ /**
2594
+ * What the caller knows about each function a declaration may name: `null` (or
2595
+ * absence from the map) is a function this app does not have. The CLI resolves
2596
+ * it from the live listing overlaid by the function files this push selects;
2597
+ * the admin routes from an app-scoped lookup.
2598
+ */
2599
+ export type AgentFunctionFacts = Readonly<Record<string, AgentFunctionFact | null>>;
2600
+ /**
2601
+ * What one function declares. `hasInputSchema`/`hasOutputSchema` are #3798's
2602
+ * presence facts; `inputSchema`/`outputSchema` are #3799's — the stored value,
2603
+ * a JSON string or an object, which `agentSchemaTranslationRefusals` translates
2604
+ * for each of the agent's providers. Both schema fields are OPTIONAL, so a
2605
+ * caller that only needs the presence half is unchanged (principle 5).
2606
+ */
2607
+ export interface AgentFunctionFact {
2608
+ hasInputSchema: boolean;
2609
+ hasOutputSchema: boolean;
2610
+ inputSchema?: unknown;
2611
+ outputSchema?: unknown;
2612
+ }
2613
+ export interface AgentDeclarationInput {
2614
+ /** `[prompt].kind`; unset means `chat`. */
2615
+ kind?: unknown;
2616
+ /** `[prompt.agent]`: a table, a JSON string encoding one, or unset. */
2617
+ agent?: unknown;
2618
+ /** `[prompt].outputSchema` — refused on an agent. */
2619
+ outputSchema?: unknown;
2620
+ /**
2621
+ * The function facts. Omitted means "not known here": the file-decidable
2622
+ * half runs alone (the CLI's `config diff` collector has no app state).
2623
+ */
2624
+ functions?: AgentFunctionFacts;
2625
+ }
2626
+ export type AgentDeclarationResolution = {
2627
+ ok: true;
2628
+ declaration: AgentDeclaration | null;
2629
+ } | {
2630
+ ok: false;
2631
+ refusals: AgentRefusal[];
2632
+ };
2633
+ /**
2634
+ * The same label, for the sibling rules that refuse a declaration from their
2635
+ * own module (#3799's `provider-schema.ts`), so every agent refusal points at
2636
+ * the block the author wrote.
2637
+ */
2638
+ export declare const AGENT_BLOCK_LABEL = "[prompt.agent]";
2639
+ /**
2640
+ * The function keys a declaration references (tools, turn context, history),
2641
+ * each once, in declaration order. What a caller resolves into the
2642
+ * `functions` facts before calling the resolver. `[]` for a block that is
2643
+ * absent or does not parse — the resolver refuses the latter itself.
2644
+ */
2645
+ /**
2646
+ * `[prompt.agent]` as a value: a table as it is, one JSON string parsed,
2647
+ * `undefined` for absence or for anything that is not a JSON object (which
2648
+ * `resolveAgentDeclaration` refuses on its own).
2649
+ *
2650
+ * Exported for the sibling rules that read the same block — #3799's
2651
+ * `agentSchemaTranslationRefusals` — so a declaration written as one JSON
2652
+ * string is read identically by every rule that consumes it.
2653
+ */
2654
+ export declare function parseAgentDeclarationBlock(agent: unknown): Record<string, unknown> | undefined;
2655
+ export declare function agentDeclarationFunctionKeys(agent: unknown): string[];
2656
+ /**
2657
+ * The one rule: is this `[prompt.agent]` declaration (with the prompt's kind
2658
+ * and `outputSchema`) something the platform can run?
2659
+ *
2660
+ * `{ ok: true, declaration }` carries the AUTHORED value — parsed when the
2661
+ * block was one JSON string, otherwise unchanged — or `null` for an absent
2662
+ * block. Callers store exactly this.
2663
+ */
2664
+ export declare function resolveAgentDeclaration(input: AgentDeclarationInput): AgentDeclarationResolution;
2665
+ /**
2666
+ * The refusal of a single-shot run of an agent — `ctx.prompts.run`, the member
2667
+ * execute route, the admin execute and preview routes, the workflow
2668
+ * `prompt.execute` step and the executor itself (§D1: an agent runs turn by
2669
+ * turn in a session, never once).
2670
+ */
2671
+ export declare function agentNotRunnableRefusal(promptKey?: string): AgentRefusal;
2672
+ /**
2673
+ * The refusal of an agent round asked of a prompt that is not an agent —
2674
+ * #3800 (`PromptExecutionService.resolveAgentTurnConfig` and
2675
+ * `executeAgentRound`). The mirror of `agentNotRunnableRefusal`.
2676
+ */
2677
+ export declare function agentRoundNotAgentRefusal(promptKey: string): AgentRefusal;
2678
+ /**
2679
+ * The refusal of a prompt test case that involves an agent (§D1: prompt test
2680
+ * cases are refused for the kind in v1; multi-turn tests are deferred).
2681
+ * `subject` is a case written ON the agent, `evaluator` a case that names the
2682
+ * agent as its judge.
2683
+ */
2684
+ export declare function agentTestCaseRefusal(promptKey: string, role: "subject" | "evaluator"): AgentRefusal;
2685
+ /**
2686
+ * The declaration with every default applied: `answeredBy = "initiator"`, the
2687
+ * platform maximums for the limits, and per tool `invoke = "request"` (server
2688
+ * tools), `approval = false` and `historyScope = "session"`.
2689
+ *
2690
+ * The ONLY accessor for defaults — the stored value never carries them
2691
+ * (DSO-3798-001). Takes a value `resolveAgentDeclaration` accepted (or `null`)
2692
+ * and leaves it untouched.
2693
+ */
2694
+ export declare function normalizeAgentDeclaration(declaration: AgentDeclaration | null | undefined): NormalizedAgentDeclaration;
2695
+ /**
2696
+ * Meaning-preserving schema translation, per provider — issue #3799
2697
+ * (project `agents`, §D6, intent criterion 2).
2698
+ *
2699
+ * A tool or event schema reaches a provider only through a translation that
2700
+ * preserves its meaning; anything else is refused at push, naming the path, the
2701
+ * keyword and the provider. The lossy `sanitizeSchemaForGemini` clean-up
2702
+ * (`src/services/block-executor.ts`) is NOT reused here: it drops unions and
2703
+ * references and rewrites a free-form object as a string, all of which change
2704
+ * what the model may produce. It stays where it is, for chat output schemas
2705
+ * (the project's non-goal: chat is unchanged).
2706
+ *
2707
+ * ## What "lossless" means (spec §3)
2708
+ *
2709
+ * Every keyword is either
2710
+ * (a) passed to the provider unchanged with the same meaning,
2711
+ * (b) rewritten into a provider spelling that admits exactly the same set of
2712
+ * values, or
2713
+ * (c) dropped because dropping it changes neither what the model is told it
2714
+ * may produce nor what the platform enforces on what it produced.
2715
+ *
2716
+ * Anything else is refused. The only silent drops are the annotations with no
2717
+ * value meaning (`$schema`, `$id`, `$comment`) and `additionalProperties`
2718
+ * (DSO-3799-001): Gemini's function `Schema` has no spelling for a closed
2719
+ * object at all, the platform validates every tool argument against the
2720
+ * ORIGINAL, untranslated schema (#3800, criterion 3) so an extra key becomes
2721
+ * the structured error the model sees, and a model following `properties` is
2722
+ * never told it may add keys. Refusing it instead would put the platform's own
2723
+ * closed-object marker — `additionalProperties: false` is how
2724
+ * `src/workflows/schema-descriptor.ts` spells a closed object — outside
2725
+ * Gemini's reach.
2726
+ *
2727
+ * The TRANSLATED schema is what the provider is sent; the ORIGINAL is what the
2728
+ * platform keeps and validates against. Neither function here mutates its
2729
+ * input.
2730
+ *
2731
+ * ## The two providers
2732
+ *
2733
+ * - `openrouter` forwards `tools[].function.parameters` as JSON Schema to the
2734
+ * model's own upstream. The platform cannot know each upstream's dialect, so
2735
+ * the only honest translation is identity — nothing is refused.
2736
+ * - `gemini` takes the OpenAPI 3.0 `Schema` object that
2737
+ * `functionDeclarations[].parameters` accepts: one `type` from a closed list,
2738
+ * `nullable`, `format` from a documented list, `enum` of strings,
2739
+ * `properties`/`required`, `items`, the numeric and length bounds,
2740
+ * `propertyOrdering`, `example`, and `anyOf`. It has no `$ref`, `oneOf`,
2741
+ * `allOf`, `not`, `const`, `additionalProperties`, type arrays or
2742
+ * `type: "null"`; an object needs non-empty `properties` and an array needs
2743
+ * `items`. Lowercase type names are accepted (the existing `responseSchema`
2744
+ * path already sends them).
2745
+ *
2746
+ * Pure and dependency-free, like every module under `src/config-surface/`, and
2747
+ * vendored into the CLI artifact after `agent-declaration.ts` so the push
2748
+ * preflight and the admin routes refuse exactly the same schemas.
2749
+ */
2750
+ /** The providers a prompt config may name. */
2751
+ export type SchemaProvider = "openrouter" | "gemini";
2752
+ /** One untranslatable keyword: where it is, what it is, and why it cannot go. */
2753
+ export interface SchemaTranslationRefusal {
2754
+ /**
2755
+ * The dotted path from the schema root, with indexes — `properties.amount`,
2756
+ * `items.properties.kind`, `anyOf[1].properties.x`. `""` is the root itself.
2757
+ */
2758
+ path: string;
2759
+ /** The keyword that cannot be carried, as the author spelled it. */
2760
+ keyword: string;
2761
+ /** What the provider cannot express, and what to write instead. */
2762
+ reason: string;
2763
+ }
2764
+ export type SchemaTranslation = {
2765
+ ok: true;
2766
+ schema: Record<string, unknown>;
2767
+ } | {
2768
+ ok: false;
2769
+ refusals: SchemaTranslationRefusal[];
2770
+ };
2771
+ /** What a message calls the root. */
2772
+ export declare function schemaPathLabel(path: string): string;
2773
+ /**
2774
+ * Translate one schema for one provider, or refuse it naming every keyword it
2775
+ * cannot carry.
2776
+ *
2777
+ * OpenRouter is identity — a deep copy of the input, so a caller that edits the
2778
+ * result never reaches the stored original. Gemini follows the table in spec
2779
+ * §4. Every refusal of one schema is returned at once, so an author fixes it in
2780
+ * one pass (principle 6).
2781
+ */
2782
+ export declare function translateSchemaForProvider(schema: unknown, provider: SchemaProvider | string): SchemaTranslation;
2783
+ /** One non-archived config of the prompt: which provider, under which name. */
2784
+ export interface AgentSchemaConfigFact {
2785
+ configName: string;
2786
+ provider: string;
2787
+ /** The per-version status; `archived` is skipped (spec §3). */
2788
+ status?: string | null;
2789
+ }
2790
+ export interface AgentSchemaTranslationInput {
2791
+ /** `[prompt.agent]` as authored: a table, one JSON string encoding one, or unset. */
2792
+ declaration: unknown;
2793
+ /**
2794
+ * What this app holds for each function the declaration names, including the
2795
+ * schemas a server tool's two schemas come from. Omitted means "not known
2796
+ * here" — server tools are then not checked, and the caller that does know
2797
+ * checks them.
2798
+ */
2799
+ functions?: AgentFunctionFacts;
2800
+ /** Every config of the prompt. Archived ones are skipped. */
2801
+ configs: ReadonlyArray<AgentSchemaConfigFact>;
2802
+ }
2803
+ /**
2804
+ * Every `AGENT_SCHEMA_NOT_TRANSLATABLE` refusal an agent's declaration owes,
2805
+ * checked against the provider of every config that is not archived
2806
+ * (intent criterion 2).
2807
+ *
2808
+ * One refusal per (schema, path, keyword, provider): it names the tool or
2809
+ * event, which schema, the dotted path, the keyword, the provider, the config
2810
+ * names on that provider, and the remedy. Two configs on the same provider
2811
+ * produce ONE refusal naming both — the author's fix is the same either way.
2812
+ *
2813
+ * A declaration with no tools and no events reads no function schema at all.
2814
+ */
2815
+ export declare function agentSchemaTranslationRefusals(input: AgentSchemaTranslationInput): AgentRefusal[];
2816
+ export declare const PROMPT_SURFACE: ConfigObjectSurface;
2817
+ export declare const INTEGRATION_SURFACE: ConfigObjectSurface;
2818
+ export declare const WEBHOOK_SURFACE: ConfigObjectSurface;
2819
+ export declare const CRON_TRIGGER_SURFACE: ConfigObjectSurface;
2820
+ export declare const BLOB_BUCKET_SURFACE: ConfigObjectSurface;
2821
+ /**
2822
+ * The `email-template` configuration object's definition (issue #2644, phase 2).
2823
+ *
2824
+ * `email-templates/<emailType>.toml` carries a single `[template]` table. The
2825
+ * object is an OVERRIDE of a built-in template: the detail response is
2826
+ * `{ emailType, hasOverride, override: {...}, default: {...} }`, and only the
2827
+ * `override` half is a field surface — the `default` half is what the platform
2828
+ * ships. Both are declared as response-only keys so `config pull`'s
2829
+ * unrecognized-key warning reports genuinely unknown fields rather than the
2830
+ * envelope.
2831
+ *
2832
+ * There is one write endpoint (`PUT …/email-templates/{emailType}`, an upsert),
2833
+ * so every field is writable on both modes.
2834
+ */
2835
+ /**
2836
+ * Email types RETIRED by #2884, kept named rather than simply deleted.
2837
+ *
2838
+ * Email sign-in sends ONE email from the `email-sign-in` template, so
2839
+ * `magic-link` and `otp` are no longer rendered by any code path — which is
2840
+ * what makes deleting the link block from an `email-sign-in` override an
2841
+ * actual guarantee rather than a hope about which endpoint ran.
2842
+ *
2843
+ * A stored override for a retired type is NOT deleted: it stays listed and
2844
+ * readable (labelled retired, with the guidance below) so an app can find its
2845
+ * customization and migrate it, and deleting it still works. Everything that
2846
+ * would author one — the admin write/preview/test endpoints, `config create`,
2847
+ * a `config push --only` selector — refuses by name instead. Silent
2848
+ * non-rendering is the outcome all of that exists to avoid.
2849
+ *
2850
+ * It lives in the config surface, not beside the default templates, because
2851
+ * the CLI vendors this directory and needs the same sentence.
2852
+ */
2853
+ export declare const RETIRED_EMAIL_TYPES: readonly ["magic-link", "otp"];
2854
+ export type RetiredEmailType = (typeof RETIRED_EMAIL_TYPES)[number];
2855
+ /** True when `emailType` is one of the retired sign-in types. */
2856
+ export declare function isRetiredEmailType(emailType: string): emailType is RetiredEmailType;
2857
+ /** What every surface says about a retired type, in one sentence. */
2858
+ export declare function retiredEmailTypeGuidance(emailType: string): string;
2859
+ export declare const EMAIL_TEMPLATE_SURFACE: ConfigObjectSurface;
2860
+ export declare const DATABASE_TYPE_SURFACE: ConfigObjectSurface;
2861
+ export declare const RULE_SET_SURFACE: ConfigObjectSurface;
2862
+ export declare const GROUP_TYPE_CONFIG_SURFACE: ConfigObjectSurface;
2863
+ export declare const COLLECTION_TYPE_CONFIG_SURFACE: ConfigObjectSurface;
2864
+ export declare const METADATA_CATEGORY_CONFIG_SURFACE: ConfigObjectSurface;
2865
+ /**
2866
+ * The `transform` configuration object's definition (issue #2644, phase 3).
2867
+ *
2868
+ * Transforms are the one synced type with NO TOML field table: a transform is
2869
+ * `transforms/<name>.rhai`, a Rhai source file, and its whole authored surface
2870
+ * is the script body. `config pull` writes the active `ScriptConfig`'s body and
2871
+ * `config push` sends it back; there is no key/value table to define, and the
2872
+ * `Script` / `ScriptConfig` scalars around it (name, description, inputSchema,
2873
+ * limits, status) are not authorable through the sync slot today.
2874
+ *
2875
+ * The entry exists so that is a DECISION rather than an absence. Criterion 3's
2876
+ * registry guard reads `SYNC_RESOURCE_TYPES` and requires a surface per label;
2877
+ * without this module `transform` would have to sit in an exemption list, which
2878
+ * is precisely the "absent from a hand-written list" failure mode this epic
2879
+ * exists to end.
2880
+ */
2881
+ export declare const TRANSFORM_SURFACE: ConfigObjectSurface;
2882
+ export declare const SERVER_FUNCTION_SURFACE: ConfigObjectSurface;
2883
+ export declare const TEST_CASE_SURFACE: ConfigObjectSurface;
2884
+ export declare const APP_SETTINGS_SURFACE: ConfigObjectSurface;
2885
+ /**
2886
+ * The configuration-object registry (issue #2644).
2887
+ *
2888
+ * `CONFIG_SURFACES` holds one entry per synced configuration object type. The
2889
+ * registry — not a per-type test — is what makes coverage follow from existing:
2890
+ * `cli/tests/unit/config-surface-drift-guard.test.ts` reads the CLI's
2891
+ * `SYNC_RESOURCE_TYPES` labels and fails when a label has no surface here.
2892
+ *
2893
+ * `CONFIG_SURFACES` is the write authority. `SYNC_RESOURCE_TYPES` keeps its
2894
+ * documented role — directory/state/prune/diff layout metadata, explicitly "not
2895
+ * a write framework" — and gains no write-surface fields; the two are
2896
+ * cross-checked, not merged.
2897
+ */
2898
+ /**
2899
+ * Every configuration object whose field surface is defined here.
2900
+ *
2901
+ * One entry per `SYNC_RESOURCE_TYPES` label, plus the two surfaces that
2902
+ * round-trip without being a per-entity file: `app-settings` (`app.toml`) and
2903
+ * `test-case` (`<key>.tests/`). Nothing that syncs sits outside the registry —
2904
+ * `PENDING_MIGRATION`, the migration's temporary exemption list, is gone as of
2905
+ * phase 3, so a new synced type has nowhere to be parked and fails the registry
2906
+ * guard until it is defined (#2644 criterion 3).
2907
+ */
2908
+ export declare const CONFIG_SURFACES: readonly ConfigObjectSurface[];
2909
+ /**
2910
+ * The configuration surfaces that have not declared their CROSS-FIELD rules yet
2911
+ * (#3373, project `cli-server-rule-parity`).
2912
+ *
2913
+ * A surface declares either `crossFieldRules` or `noCrossFieldRules`; one that
2914
+ * declares neither is on this list, and the guard asserts the two sides agree in
2915
+ * both directions. Unlike #2644's `PENDING_MIGRATION` — deleted once the field
2916
+ * surfaces were all defined — this is not an exemption anyone may add to: it is
2917
+ * a settled inventory of work, and it only ever SHRINKS.
2918
+ *
2919
+ * The ratchet: `cli/tests/unit/config-surface-rules-guard-3373.test.ts` carries
2920
+ * its own literal copy of this list and asserts the two are equal. Every
2921
+ * migration removes its label from BOTH in the same change — that shrink is part
2922
+ * of the migrating issue's definition of done. Adding a label back here alone
2923
+ * fails the guard; adding it back to both is an edit to the guard itself, which
2924
+ * is as review-visible as weakening any other assertion.
2925
+ */
2926
+ export declare const CROSS_FIELD_RULES_UNMIGRATED: readonly string[];
2927
+ /** The surface for a `SyncResourceType.label`, or undefined when unmigrated. */
2928
+ export declare function getConfigSurface(label: string): ConfigObjectSurface | undefined;
2929
+ /** One table of one surface, addressed by its TOML path. */
2930
+ export declare function getConfigTable(label: string, tomlPath: readonly string[]): ConfigTable | undefined;
2931
+ /**
2932
+ * Every field of every `models.yaml` model a configuration-object definition
2933
+ * names, in declaration order — the coverage guard's anchor (#2644 criterion 2).
2934
+ */
2935
+ export declare const GENERATED_CONFIG_MODEL_FIELDS: Readonly<Record<string, readonly string[]>>;
2936
+ export {};