primitive-admin 1.0.61 → 1.0.63

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 (320) hide show
  1. package/README.md +125 -69
  2. package/assets/skill/skills/primitive-platform/SKILL.md +336 -37
  3. package/dist/bin/primitive.js +25 -14
  4. package/dist/bin/primitive.js.map +1 -1
  5. package/dist/src/commands/analytics.js +36 -16
  6. package/dist/src/commands/analytics.js.map +1 -1
  7. package/dist/src/commands/apps.js +52 -188
  8. package/dist/src/commands/apps.js.map +1 -1
  9. package/dist/src/commands/blob-buckets.js +13 -153
  10. package/dist/src/commands/blob-buckets.js.map +1 -1
  11. package/dist/src/commands/collection-type-configs.js +14 -100
  12. package/dist/src/commands/collection-type-configs.js.map +1 -1
  13. package/dist/src/commands/collections.js +47 -8
  14. package/dist/src/commands/collections.js.map +1 -1
  15. package/dist/src/commands/config.d.ts +46 -0
  16. package/dist/src/commands/config.js +479 -0
  17. package/dist/src/commands/config.js.map +1 -0
  18. package/dist/src/commands/connections.js +12 -7
  19. package/dist/src/commands/connections.js.map +1 -1
  20. package/dist/src/commands/cron-triggers.js +84 -176
  21. package/dist/src/commands/cron-triggers.js.map +1 -1
  22. package/dist/src/commands/database-type-configs.d.ts +2 -0
  23. package/dist/src/commands/database-type-configs.js +171 -0
  24. package/dist/src/commands/database-type-configs.js.map +1 -0
  25. package/dist/src/commands/database-types.js +4 -4
  26. package/dist/src/commands/database-types.js.map +1 -1
  27. package/dist/src/commands/databases.d.ts +63 -0
  28. package/dist/src/commands/databases.js +649 -87
  29. package/dist/src/commands/databases.js.map +1 -1
  30. package/dist/src/commands/documents.js +869 -12
  31. package/dist/src/commands/documents.js.map +1 -1
  32. package/dist/src/commands/email-templates.js +21 -128
  33. package/dist/src/commands/email-templates.js.map +1 -1
  34. package/dist/src/commands/env.d.ts +12 -1
  35. package/dist/src/commands/env.js +115 -26
  36. package/dist/src/commands/env.js.map +1 -1
  37. package/dist/src/commands/feature-flags.d.ts +14 -0
  38. package/dist/src/commands/feature-flags.js +116 -0
  39. package/dist/src/commands/feature-flags.js.map +1 -0
  40. package/dist/src/commands/group-type-configs.js +14 -109
  41. package/dist/src/commands/group-type-configs.js.map +1 -1
  42. package/dist/src/commands/init.d.ts +24 -1
  43. package/dist/src/commands/init.js +1194 -279
  44. package/dist/src/commands/init.js.map +1 -1
  45. package/dist/src/commands/integrations.js +166 -435
  46. package/dist/src/commands/integrations.js.map +1 -1
  47. package/dist/src/commands/metadata-category-configs.d.ts +12 -0
  48. package/dist/src/commands/metadata-category-configs.js +112 -0
  49. package/dist/src/commands/metadata-category-configs.js.map +1 -0
  50. package/dist/src/commands/metadata.js +33 -141
  51. package/dist/src/commands/metadata.js.map +1 -1
  52. package/dist/src/commands/prompts.js +206 -563
  53. package/dist/src/commands/prompts.js.map +1 -1
  54. package/dist/src/commands/rule-sets.d.ts +1 -1
  55. package/dist/src/commands/rule-sets.js +16 -132
  56. package/dist/src/commands/rule-sets.js.map +1 -1
  57. package/dist/src/commands/scripts.d.ts +10 -0
  58. package/dist/src/commands/scripts.js +203 -241
  59. package/dist/src/commands/scripts.js.map +1 -1
  60. package/dist/src/commands/sessions.js +17 -5
  61. package/dist/src/commands/sessions.js.map +1 -1
  62. package/dist/src/commands/sync-app-settings.d.ts +113 -70
  63. package/dist/src/commands/sync-app-settings.js +193 -242
  64. package/dist/src/commands/sync-app-settings.js.map +1 -1
  65. package/dist/src/commands/sync.d.ts +1904 -51
  66. package/dist/src/commands/sync.js +9468 -1790
  67. package/dist/src/commands/sync.js.map +1 -1
  68. package/dist/src/commands/tokens.js +8 -2
  69. package/dist/src/commands/tokens.js.map +1 -1
  70. package/dist/src/commands/users.js +92 -1
  71. package/dist/src/commands/users.js.map +1 -1
  72. package/dist/src/commands/vars.js +44 -58
  73. package/dist/src/commands/vars.js.map +1 -1
  74. package/dist/src/commands/webhooks.js +318 -156
  75. package/dist/src/commands/webhooks.js.map +1 -1
  76. package/dist/src/commands/workflows.d.ts +49 -12
  77. package/dist/src/commands/workflows.js +652 -1086
  78. package/dist/src/commands/workflows.js.map +1 -1
  79. package/dist/src/lib/access-rule-display.d.ts +21 -0
  80. package/dist/src/lib/access-rule-display.js +34 -0
  81. package/dist/src/lib/access-rule-display.js.map +1 -0
  82. package/dist/src/lib/api-client.d.ts +541 -61
  83. package/dist/src/lib/api-client.js +559 -102
  84. package/dist/src/lib/api-client.js.map +1 -1
  85. package/dist/src/lib/app-settings-descriptor.d.ts +180 -25
  86. package/dist/src/lib/app-settings-descriptor.js +403 -82
  87. package/dist/src/lib/app-settings-descriptor.js.map +1 -1
  88. package/dist/src/lib/canonical-json.d.ts +12 -0
  89. package/dist/src/lib/canonical-json.js +35 -0
  90. package/dist/src/lib/canonical-json.js.map +1 -0
  91. package/dist/src/lib/cli-manifest.d.ts +8 -0
  92. package/dist/src/lib/cli-manifest.js +1 -0
  93. package/dist/src/lib/cli-manifest.js.map +1 -1
  94. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +6 -2
  95. package/dist/src/lib/codegen-shared/generatedFiles.js +9 -2
  96. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
  97. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +6 -6
  98. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +8 -8
  99. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -1
  100. package/dist/src/lib/config-object-descriptor.d.ts +127 -0
  101. package/dist/src/lib/config-object-descriptor.js +658 -0
  102. package/dist/src/lib/config-object-descriptor.js.map +1 -0
  103. package/dist/src/lib/config-payload.d.ts +85 -0
  104. package/dist/src/lib/config-payload.js +116 -0
  105. package/dist/src/lib/config-payload.js.map +1 -0
  106. package/dist/src/lib/config-surface.d.ts +130 -0
  107. package/dist/src/lib/config-surface.js +300 -0
  108. package/dist/src/lib/config-surface.js.map +1 -0
  109. package/dist/src/lib/credentials-store.d.ts +10 -0
  110. package/dist/src/lib/credentials-store.js +23 -0
  111. package/dist/src/lib/credentials-store.js.map +1 -1
  112. package/dist/src/lib/data-input.d.ts +23 -0
  113. package/dist/src/lib/data-input.js +50 -0
  114. package/dist/src/lib/data-input.js.map +1 -0
  115. package/dist/src/lib/db-codegen/dbTemplates.js +1 -1
  116. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
  117. package/dist/src/lib/db-codegen/dbTypeIR.d.ts +1 -1
  118. package/dist/src/lib/env-resolver-core.d.ts +187 -0
  119. package/dist/src/lib/env-resolver-core.js +325 -0
  120. package/dist/src/lib/env-resolver-core.js.map +1 -0
  121. package/dist/src/lib/env-resolver.d.ts +28 -6
  122. package/dist/src/lib/env-resolver.js +44 -32
  123. package/dist/src/lib/env-resolver.js.map +1 -1
  124. package/dist/src/lib/generated-allowlist.js +12 -0
  125. package/dist/src/lib/generated-allowlist.js.map +1 -1
  126. package/dist/src/lib/generated-config-surfaces.d.ts +682 -0
  127. package/dist/src/lib/generated-config-surfaces.js +4058 -0
  128. package/dist/src/lib/generated-config-surfaces.js.map +1 -0
  129. package/dist/src/lib/generated-template-lint.d.ts +212 -0
  130. package/dist/src/lib/generated-template-lint.js +624 -0
  131. package/dist/src/lib/generated-template-lint.js.map +1 -0
  132. package/dist/src/lib/init-adopt.d.ts +16 -0
  133. package/dist/src/lib/init-adopt.js +34 -0
  134. package/dist/src/lib/init-adopt.js.map +1 -0
  135. package/dist/src/lib/init-assets.d.ts +39 -0
  136. package/dist/src/lib/init-assets.js +97 -0
  137. package/dist/src/lib/init-assets.js.map +1 -0
  138. package/dist/src/lib/init-client-platforms.d.ts +14 -0
  139. package/dist/src/lib/init-client-platforms.js +71 -0
  140. package/dist/src/lib/init-client-platforms.js.map +1 -0
  141. package/dist/src/lib/init-config.d.ts +44 -5
  142. package/dist/src/lib/init-config.js +80 -7
  143. package/dist/src/lib/init-config.js.map +1 -1
  144. package/dist/src/lib/init-email-redirect-uris.d.ts +37 -0
  145. package/dist/src/lib/init-email-redirect-uris.js +46 -0
  146. package/dist/src/lib/init-email-redirect-uris.js.map +1 -0
  147. package/dist/src/lib/init-ios-links.d.ts +90 -0
  148. package/dist/src/lib/init-ios-links.js +218 -0
  149. package/dist/src/lib/init-ios-links.js.map +1 -0
  150. package/dist/src/lib/init-plan.d.ts +80 -0
  151. package/dist/src/lib/init-plan.js +95 -0
  152. package/dist/src/lib/init-plan.js.map +1 -0
  153. package/dist/src/lib/init-production-env.d.ts +48 -0
  154. package/dist/src/lib/init-production-env.js +59 -0
  155. package/dist/src/lib/init-production-env.js.map +1 -0
  156. package/dist/src/lib/init-schema.d.ts +74 -0
  157. package/dist/src/lib/init-schema.js +358 -0
  158. package/dist/src/lib/init-schema.js.map +1 -0
  159. package/dist/src/lib/init-xcode.d.ts +33 -0
  160. package/dist/src/lib/init-xcode.js +114 -0
  161. package/dist/src/lib/init-xcode.js.map +1 -0
  162. package/dist/src/lib/integration-request-config.d.ts +30 -0
  163. package/dist/src/lib/integration-request-config.js +145 -0
  164. package/dist/src/lib/integration-request-config.js.map +1 -0
  165. package/dist/src/lib/integration-selector.d.ts +42 -0
  166. package/dist/src/lib/integration-selector.js +46 -0
  167. package/dist/src/lib/integration-selector.js.map +1 -0
  168. package/dist/src/lib/local-state.d.ts +55 -0
  169. package/dist/src/lib/local-state.js +167 -0
  170. package/dist/src/lib/local-state.js.map +1 -0
  171. package/dist/src/lib/local-test-cases.d.ts +63 -0
  172. package/dist/src/lib/local-test-cases.js +135 -0
  173. package/dist/src/lib/local-test-cases.js.map +1 -0
  174. package/dist/src/lib/log-inspection.d.ts +568 -0
  175. package/dist/src/lib/log-inspection.js +639 -0
  176. package/dist/src/lib/log-inspection.js.map +1 -0
  177. package/dist/src/lib/migration-nag.d.ts +2 -2
  178. package/dist/src/lib/migration-nag.js +3 -3
  179. package/dist/src/lib/object-status-filter.d.ts +22 -0
  180. package/dist/src/lib/object-status-filter.js +45 -0
  181. package/dist/src/lib/object-status-filter.js.map +1 -0
  182. package/dist/src/lib/output.d.ts +24 -1
  183. package/dist/src/lib/output.js +42 -1
  184. package/dist/src/lib/output.js.map +1 -1
  185. package/dist/src/lib/package-manager.d.ts +140 -0
  186. package/dist/src/lib/package-manager.js +305 -0
  187. package/dist/src/lib/package-manager.js.map +1 -0
  188. package/dist/src/lib/paginate.d.ts +50 -0
  189. package/dist/src/lib/paginate.js +53 -0
  190. package/dist/src/lib/paginate.js.map +1 -1
  191. package/dist/src/lib/platform-owned.d.ts +29 -3
  192. package/dist/src/lib/platform-owned.js +42 -3
  193. package/dist/src/lib/platform-owned.js.map +1 -1
  194. package/dist/src/lib/project-config.d.ts +8 -0
  195. package/dist/src/lib/project-config.js +30 -5
  196. package/dist/src/lib/project-config.js.map +1 -1
  197. package/dist/src/lib/query-operators.d.ts +1 -1
  198. package/dist/src/lib/query-operators.js +1 -1
  199. package/dist/src/lib/record-filter.d.ts +18 -0
  200. package/dist/src/lib/record-filter.js +55 -0
  201. package/dist/src/lib/record-filter.js.map +1 -0
  202. package/dist/src/lib/resolve-init-dev-port.d.ts +56 -0
  203. package/dist/src/lib/resolve-init-dev-port.js +55 -0
  204. package/dist/src/lib/resolve-init-dev-port.js.map +1 -0
  205. package/dist/src/lib/resolve-init-server.d.ts +64 -0
  206. package/dist/src/lib/resolve-init-server.js +77 -0
  207. package/dist/src/lib/resolve-init-server.js.map +1 -0
  208. package/dist/src/lib/resolve-platform.d.ts +43 -14
  209. package/dist/src/lib/resolve-platform.js +74 -12
  210. package/dist/src/lib/resolve-platform.js.map +1 -1
  211. package/dist/src/lib/run-status.d.ts +19 -0
  212. package/dist/src/lib/run-status.generated.d.ts +39 -0
  213. package/dist/src/lib/run-status.generated.js +66 -0
  214. package/dist/src/lib/run-status.generated.js.map +1 -0
  215. package/dist/src/lib/run-status.js +19 -0
  216. package/dist/src/lib/run-status.js.map +1 -0
  217. package/dist/src/lib/server-text-normalization.d.ts +51 -0
  218. package/dist/src/lib/server-text-normalization.js +90 -0
  219. package/dist/src/lib/server-text-normalization.js.map +1 -0
  220. package/dist/src/lib/server-url.d.ts +22 -0
  221. package/dist/src/lib/server-url.js +33 -0
  222. package/dist/src/lib/server-url.js.map +1 -0
  223. package/dist/src/lib/signing-secret-status.d.ts +81 -0
  224. package/dist/src/lib/signing-secret-status.js +116 -0
  225. package/dist/src/lib/signing-secret-status.js.map +1 -0
  226. package/dist/src/lib/skill-installer.js +6 -3
  227. package/dist/src/lib/skill-installer.js.map +1 -1
  228. package/dist/src/lib/snapshots.d.ts +2 -2
  229. package/dist/src/lib/snapshots.js +2 -2
  230. package/dist/src/lib/swift-codegen/dbGenerator.d.ts +15 -2
  231. package/dist/src/lib/swift-codegen/dbGenerator.js +250 -18
  232. package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -1
  233. package/dist/src/lib/swift-codegen/generator.d.ts +11 -2
  234. package/dist/src/lib/swift-codegen/generator.js +181 -7
  235. package/dist/src/lib/swift-codegen/generator.js.map +1 -1
  236. package/dist/src/lib/swift-codegen/siblingSymbols.d.ts +7 -3
  237. package/dist/src/lib/swift-codegen/siblingSymbols.js +4 -1
  238. package/dist/src/lib/swift-codegen/siblingSymbols.js.map +1 -1
  239. package/dist/src/lib/sync-dir-selector.d.ts +21 -0
  240. package/dist/src/lib/sync-dir-selector.js +30 -0
  241. package/dist/src/lib/sync-dir-selector.js.map +1 -0
  242. package/dist/src/lib/sync-paths.d.ts +39 -0
  243. package/dist/src/lib/sync-paths.js +70 -2
  244. package/dist/src/lib/sync-paths.js.map +1 -1
  245. package/dist/src/lib/sync-resource-types.d.ts +138 -31
  246. package/dist/src/lib/sync-resource-types.js +241 -47
  247. package/dist/src/lib/sync-resource-types.js.map +1 -1
  248. package/dist/src/lib/sync-selectors.d.ts +95 -0
  249. package/dist/src/lib/sync-selectors.js +228 -0
  250. package/dist/src/lib/sync-selectors.js.map +1 -0
  251. package/dist/src/lib/template.d.ts +62 -4
  252. package/dist/src/lib/template.js +147 -39
  253. package/dist/src/lib/template.js.map +1 -1
  254. package/dist/src/lib/test-case-file-names.d.ts +40 -0
  255. package/dist/src/lib/test-case-file-names.js +91 -0
  256. package/dist/src/lib/test-case-file-names.js.map +1 -0
  257. package/dist/src/lib/test-case-keys.d.ts +29 -0
  258. package/dist/src/lib/test-case-keys.js +55 -0
  259. package/dist/src/lib/test-case-keys.js.map +1 -0
  260. package/dist/src/lib/test-case-variables.d.ts +15 -0
  261. package/dist/src/lib/test-case-variables.js +29 -0
  262. package/dist/src/lib/test-case-variables.js.map +1 -0
  263. package/dist/src/lib/toml-database-config.d.ts +4 -4
  264. package/dist/src/lib/toml-database-config.js +27 -34
  265. package/dist/src/lib/toml-database-config.js.map +1 -1
  266. package/dist/src/lib/toml-metadata-config.d.ts +9 -5
  267. package/dist/src/lib/toml-metadata-config.js +40 -45
  268. package/dist/src/lib/toml-metadata-config.js.map +1 -1
  269. package/dist/src/lib/toml-native-form.d.ts +1 -1
  270. package/dist/src/lib/toml-native-form.js +1 -1
  271. package/dist/src/lib/toml-params-validator.d.ts +1 -1
  272. package/dist/src/lib/toml-params-validator.js +1 -1
  273. package/dist/src/lib/toml-scalar-edit.d.ts +43 -0
  274. package/dist/src/lib/toml-scalar-edit.js +283 -0
  275. package/dist/src/lib/toml-scalar-edit.js.map +1 -0
  276. package/dist/src/lib/user-selector.d.ts +24 -0
  277. package/dist/src/lib/user-selector.js +33 -0
  278. package/dist/src/lib/user-selector.js.map +1 -0
  279. package/dist/src/lib/version-check.d.ts +25 -0
  280. package/dist/src/lib/version-check.js +77 -8
  281. package/dist/src/lib/version-check.js.map +1 -1
  282. package/dist/src/lib/watch.d.ts +121 -0
  283. package/dist/src/lib/watch.js +169 -0
  284. package/dist/src/lib/watch.js.map +1 -0
  285. package/dist/src/lib/web-url.d.ts +40 -0
  286. package/dist/src/lib/web-url.js +76 -0
  287. package/dist/src/lib/web-url.js.map +1 -0
  288. package/dist/src/lib/workflow-apply.d.ts +69 -45
  289. package/dist/src/lib/workflow-apply.js +99 -72
  290. package/dist/src/lib/workflow-apply.js.map +1 -1
  291. package/dist/src/lib/workflow-codegen/generator.js +4 -4
  292. package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
  293. package/dist/src/lib/workflow-codegen/invokerIR.d.ts +11 -0
  294. package/dist/src/lib/workflow-codegen/invokerIR.js +5 -0
  295. package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -1
  296. package/dist/src/lib/workflow-config-apply.d.ts +70 -0
  297. package/dist/src/lib/workflow-config-apply.js +137 -0
  298. package/dist/src/lib/workflow-config-apply.js.map +1 -0
  299. package/dist/src/lib/workflow-config-sidecar.d.ts +63 -0
  300. package/dist/src/lib/workflow-config-sidecar.js +96 -0
  301. package/dist/src/lib/workflow-config-sidecar.js.map +1 -0
  302. package/dist/src/lib/workflow-defaults.d.ts +29 -0
  303. package/dist/src/lib/workflow-defaults.js +41 -0
  304. package/dist/src/lib/workflow-defaults.js.map +1 -0
  305. package/dist/src/lib/workflow-include-preserve.d.ts +76 -0
  306. package/dist/src/lib/workflow-include-preserve.js +286 -0
  307. package/dist/src/lib/workflow-include-preserve.js.map +1 -0
  308. package/dist/src/lib/workflow-payload.d.ts +31 -20
  309. package/dist/src/lib/workflow-payload.js +100 -110
  310. package/dist/src/lib/workflow-payload.js.map +1 -1
  311. package/dist/src/lib/workflow-toml-validator.d.ts +37 -16
  312. package/dist/src/lib/workflow-toml-validator.js +141 -16
  313. package/dist/src/lib/workflow-toml-validator.js.map +1 -1
  314. package/dist/src/types/index.d.ts +78 -22
  315. package/dist/src/validators.d.ts +7 -7
  316. package/dist/src/validators.js +6 -6
  317. package/package.json +11 -6
  318. package/dist/src/commands/settings.d.ts +0 -15
  319. package/dist/src/commands/settings.js +0 -102
  320. package/dist/src/commands/settings.js.map +0 -1
@@ -0,0 +1,658 @@
1
+ /**
2
+ * The configuration-object descriptor registry (issue #2645).
3
+ *
4
+ * Server-side configuration is authored in TOML and applied with `config push`.
5
+ * That makes the TOML field surface the thing an operator has to discover, so
6
+ * it needs a machine-readable definition — the job per-flag `--help` used to do.
7
+ * This registry is that definition, and it drives four commands:
8
+ *
9
+ * - `config fields <type>` lists a type's keys, types, required, default
10
+ * - `config create <type> <key>` scaffolds the type's file from `scaffold()`
11
+ * - `config set <type>/<key>` validates the dotted path being edited
12
+ * - `config push --only <sel>` resolves a selector to a type + key
13
+ *
14
+ * ── Deliberately a descriptor, never reflection ──────────────────────────
15
+ * The field list is declared here, not inferred from the pull serializers in
16
+ * `commands/sync.ts`. Reflection over emitted keys cannot report `required` or
17
+ * `default`, and an implicit field surface is exactly the drift #2644 exists to
18
+ * end. The workflow key set is CONSUMED from #2644's vendored definition
19
+ * (`config-surface.ts` / `generated-config-surfaces.ts`) and the app settings
20
+ * from `app-settings-descriptor.ts`, rather than restated, so there is still
21
+ * one definition per field.
22
+ *
23
+ * ── Drift guard ──────────────────────────────────────────────────────────
24
+ * `cli/tests/unit/config-object-descriptor.test.ts` cross-checks the registry
25
+ * against `SYNC_RESOURCE_TYPES` (every per-entity type has exactly one
26
+ * descriptor) and `PUSH_PRUNE_SPECS` (the declared identity path is a real
27
+ * field), and asserts each scaffold parses and carries every required field. A
28
+ * new sync resource type therefore fails a test rather than silently
29
+ * under-reporting from `config fields`.
30
+ *
31
+ * ── Relationship to #2644 ────────────────────────────────────────────────
32
+ * #2644 defines one shared field definition across the server, the TOML surface
33
+ * and CLI validation. These descriptors are sized to be ABSORBED by it: they
34
+ * carry only what the four commands above need, and no validation behavior.
35
+ */
36
+ import { APP_SETTINGS_DESCRIPTOR, } from "./app-settings-descriptor.js";
37
+ import { WORKFLOW_TABLE } from "./config-surface.js";
38
+ import { SYNC_RESOURCE_TYPES, } from "./sync-resource-types.js";
39
+ /** The identity path a descriptor declares, or `undefined` when keyed by filename. */
40
+ export function describedIdentityPath(descriptor) {
41
+ return descriptor.identity;
42
+ }
43
+ function resourceType(label) {
44
+ const found = SYNC_RESOURCE_TYPES.find((t) => t.label === label);
45
+ if (!found)
46
+ throw new Error(`no sync resource type '${label}'`);
47
+ return found;
48
+ }
49
+ /** Shorthand for a descriptor field. */
50
+ function f(path, type, description, options = {}) {
51
+ return {
52
+ path,
53
+ type,
54
+ description,
55
+ required: !!options.required,
56
+ ...(options.default === undefined ? {} : { default: options.default }),
57
+ };
58
+ }
59
+ /** TOML text for a table of `key = value` lines, with a leading header. */
60
+ function tomlSection(header, lines) {
61
+ return [`[${header}]`, ...lines].join("\n");
62
+ }
63
+ // ---------------------------------------------------------------------------
64
+ // Derived field lists — consumed from the existing descriptors, not restated.
65
+ // ---------------------------------------------------------------------------
66
+ /** Human-readable one-liners for the `[workflow]` keys. */
67
+ const WORKFLOW_FIELD_NOTES = {
68
+ name: "Display name",
69
+ description: "What the workflow does",
70
+ inputSchema: "JSON Schema for the workflow input",
71
+ outputSchema: "JSON Schema for the workflow output",
72
+ perUserMaxRunning: "Concurrent runs allowed per user",
73
+ perUserMaxQueued: "Queued runs allowed per user",
74
+ perAppMaxRunning: "Concurrent runs allowed across the app",
75
+ perAppMaxQueued: "Queued runs allowed across the app",
76
+ queueTtlSeconds: "How long a queued run stays eligible",
77
+ dequeueOrder: "fifo | lifo",
78
+ requiresClientApply: "Client must apply the result before the run completes",
79
+ syncCallable: "Callable synchronously by clients",
80
+ templateMissingMarker: "Emit a marker when a template variable is missing",
81
+ accessRule: "CEL expression deciding who may run the workflow",
82
+ runAs: "Identity the run executes as",
83
+ lock: "Run-scoped lock declaration",
84
+ capabilities: "Capabilities the workflow is granted",
85
+ };
86
+ const WORKFLOW_FIELD_TYPES = {
87
+ string: "string",
88
+ number: "number",
89
+ boolean: "boolean",
90
+ "string[]": "string[]",
91
+ json: "json",
92
+ };
93
+ /**
94
+ * What the server assumes when a `[workflow]` key is absent.
95
+ *
96
+ * The vendored `WORKFLOW_TABLE` (#2644) carries key set and value shape but
97
+ * not defaults, so the defaults are stated here, next to the other types'.
98
+ * They are not free text: the `models.yaml` `WorkflowDefinition` defaults are
99
+ * the source of truth, and
100
+ * `cli/tests/unit/config-object-descriptor.test.ts` parses that model and fails
101
+ * when a default here disagrees or a newly-defaulted field is missing. Without
102
+ * them `config fields workflow` reported `default null` for the queueing and
103
+ * dispatch knobs — the command that replaced per-flag `--help` under-reporting
104
+ * exactly what the removed flags used to document (issue #2645).
105
+ *
106
+ * Exported because `config diff`'s workflow comparator needs exactly this table
107
+ * to normalize omitted-vs-defaulted fields, and kept a hand-mirrored second
108
+ * copy of it until #2731. Two tables can disagree; a guarded one cannot go
109
+ * stale unnoticed.
110
+ */
111
+ export const WORKFLOW_FIELD_DEFAULTS = {
112
+ perUserMaxRunning: 4,
113
+ perUserMaxQueued: 100,
114
+ perAppMaxRunning: 25,
115
+ perAppMaxQueued: 10000,
116
+ queueTtlSeconds: 43200,
117
+ dequeueOrder: "fifo",
118
+ requiresClientApply: true,
119
+ syncCallable: false,
120
+ };
121
+ const WORKFLOW_FIELDS = [
122
+ f("workflow.key", "string", "Workflow key — defaults to the file name", {
123
+ required: true,
124
+ }),
125
+ ...WORKFLOW_TABLE.fields.map((d) => f(`workflow.${d.tomlKey}`, WORKFLOW_FIELD_TYPES[d.type] ?? "string", WORKFLOW_FIELD_NOTES[d.tomlKey] ?? d.tomlKey, {
126
+ required: d.tomlKey === "name",
127
+ default: WORKFLOW_FIELD_DEFAULTS[d.tomlKey],
128
+ })),
129
+ f("steps", "table[]", "The workflow's steps, in order", { required: true }),
130
+ // Under `[workflow]`, not at the root: that is where `serializeWorkflow`
131
+ // emits it and where the push leg reads it from. A root-level path here made
132
+ // `config set workflow/<key> activeConfigName=<name>` write a key push ignores,
133
+ // so the scriptable activation path silently did nothing (issue #2645).
134
+ f("workflow.activeConfigName", "string", "Which named config under workflows/<key>.configs/ is live"),
135
+ ];
136
+ /**
137
+ * The `[test]` surface of a test-case sidecar (#2769), declared ONCE and
138
+ * attached to each of the four blocks that carry tests.
139
+ *
140
+ * With `tests create|update|delete` gone, this is where the field list is
141
+ * discoverable. The spellings are the authored ones: the three references are
142
+ * NAMES (resolved to ids at push time, which is what makes a sidecar portable
143
+ * across apps), and the three JSON fields carry JSON text.
144
+ */
145
+ const TEST_CASE_COMPANION_FIELDS = [
146
+ f("test.name", "string", "Test case name; the file name is its slug", {
147
+ required: true,
148
+ }),
149
+ f("test.description", "string", "What the case checks"),
150
+ // #2968 — the one place a case author can ask what may go in here, so it
151
+ // names the integration request surface rather than splitting the shared list.
152
+ f("test.inputVariables", "string", "JSON text of the input variables; an integration case's variables ARE its " +
153
+ "request (method, path, headers, query, body — or form, or bodyMode with " +
154
+ "multipartFields); an absent method uses requestConfig.defaultMethod, an " +
155
+ "absent path is /, headers/query merge with the configured ones, an " +
156
+ "absent bodyMode uses requestConfig.bodyMode, multipartFields merge with " +
157
+ "requestConfig.multipartFieldMapping by field name, and an " +
158
+ "unauthored body is no body"),
159
+ f("test.configName", "string", "Name of the config this case is pinned to"),
160
+ f("test.evaluatorPromptKey", "string", "Key of the judge prompt, when scored by one"),
161
+ f("test.evaluatorConfigName", "string", "Name of the judge prompt's config"),
162
+ f("test.expectedOutputPattern", "string", "Regex the output must match"),
163
+ f("test.expectedOutputContains", "string", "JSON text: array of required phrases"),
164
+ f("test.expectedJsonSubset", "string", "JSON text: object deep-matched against the output"),
165
+ ];
166
+ /** One owner's `<key>.tests/` companion entry (#2769). */
167
+ function testCaseCompanion(fileHint, attachmentHint) {
168
+ return {
169
+ fileHint,
170
+ description: "One test case for this block; the directory beside the file " +
171
+ `(${attachmentHint}) holds its attachments. An empty spelling ("", "{}", ` +
172
+ '"[]") clears the field on push; removing the file and running ' +
173
+ "`config push --prune` deletes the case",
174
+ fields: TEST_CASE_COMPANION_FIELDS,
175
+ };
176
+ }
177
+ /**
178
+ * The named-config sidecar surface (issue #2645, spec §Contracts/Named configs).
179
+ *
180
+ * `workflows configs create/update/duplicate/archive/activate` are gone, so
181
+ * these keys are the whole of what used to be their flags. Listing them under
182
+ * the workflow rather than as their own `config fields` type keeps one type per
183
+ * pushable object — a sidecar is part of a workflow, not a thing you can push
184
+ * on its own — while still answering "what may this file contain?", which is
185
+ * the question criterion 7 exists for. The config's NAME is the file name and
186
+ * is deliberately absent from the list: it is not a key of the file.
187
+ */
188
+ const WORKFLOW_COMPANION_FILES = [
189
+ {
190
+ fileHint: "workflows/<key>.configs/<name>.toml",
191
+ description: "One of the workflow's named configs; <name> is its name, and workflow.activeConfigName says which is live",
192
+ fields: [
193
+ f("config.description", "string", "What this config is tuned for"),
194
+ f("config.status", "string", "draft | active | archived"),
195
+ f("steps", "table[]", "This config's steps, in order", {
196
+ required: true,
197
+ }),
198
+ f("expr.cel", "table", "Named CEL guards travelling with these steps"),
199
+ ],
200
+ },
201
+ testCaseCompanion("workflows/<key>.tests/<name>.toml", "workflows/<key>.tests/<name>/"),
202
+ ];
203
+ const APP_SETTING_TYPES = {
204
+ string: "string",
205
+ boolean: "boolean",
206
+ number: "number",
207
+ "string[]": "string[]",
208
+ object: "table",
209
+ };
210
+ const APP_FIELDS = APP_SETTINGS_DESCRIPTOR.map((d) => f(`${d.section}.${d.key}`, APP_SETTING_TYPES[d.type], `App setting ${d.field}`, { required: false }));
211
+ // ---------------------------------------------------------------------------
212
+ // The registry.
213
+ // ---------------------------------------------------------------------------
214
+ export const CONFIG_OBJECT_DESCRIPTORS = [
215
+ {
216
+ type: "integration",
217
+ resourceType: resourceType("integration"),
218
+ fileHint: "integrations/<key>.toml",
219
+ identity: "integration.key",
220
+ description: "An outbound HTTP integration a workflow step can call",
221
+ fields: [
222
+ f("integration.key", "string", "Integration key", { required: true }),
223
+ f("integration.displayName", "string", "Display name", { required: true }),
224
+ f("integration.description", "string", "What the integration calls"),
225
+ f("integration.timeoutMs", "number", "Request timeout in milliseconds"),
226
+ f("integration.accessRule", "string", 'CEL expression deciding who may call it; absent denies every non-admin caller (use "true" to allow any app member)'),
227
+ f("requestConfig", "table", "Method, URL, headers and body template", {
228
+ required: true,
229
+ }),
230
+ ],
231
+ companionFiles: [
232
+ testCaseCompanion("integrations/<key>.tests/<name>.toml", "integrations/<key>.tests/<name>/"),
233
+ ],
234
+ scaffold: (key) => [
235
+ tomlSection("integration", [
236
+ `key = "${key}"`,
237
+ `displayName = "${key}"`,
238
+ // #2803 — no `status` line: availability is server-owned, a pushed
239
+ // file carrying the key is rejected, and a new object is active.
240
+ `# CEL expression deciding who may call this integration.`,
241
+ `# With no rule, every caller who is not an app admin or owner is denied.`,
242
+ `accessRule = "true"`,
243
+ ]),
244
+ "",
245
+ tomlSection("requestConfig", [
246
+ `method = "GET"`,
247
+ `url = "https://example.com/"`,
248
+ ]),
249
+ "",
250
+ ].join("\n"),
251
+ },
252
+ {
253
+ type: "webhook",
254
+ resourceType: resourceType("webhook"),
255
+ fileHint: "webhooks/<key>.toml",
256
+ identity: "webhook.key",
257
+ description: "An inbound webhook endpoint that starts a workflow",
258
+ fields: [
259
+ f("webhook.key", "string", "Webhook key", { required: true }),
260
+ f("webhook.displayName", "string", "Display name", { required: true }),
261
+ f("webhook.description", "string", "What sends to this endpoint"),
262
+ f("webhook.workflowKey", "string", "Workflow the delivery starts", {
263
+ required: true,
264
+ }),
265
+ f("webhook.verificationScheme", "string", "How a delivery's signature is verified", { default: "none" }),
266
+ f("webhook.signingSecret", "string", 'A `{{secrets.KEY}}` reference — never the secret itself'),
267
+ f("webhook.toleranceSeconds", "number", "Signature timestamp tolerance"),
268
+ f("webhook.deduplicationEnabled", "boolean", "Drop repeated delivery ids"),
269
+ f("webhook.deduplicationWindowMs", "number", "Deduplication window"),
270
+ f("webhook.maxBodyBytes", "number", "Inbound body cap; unset keeps 5 MiB"),
271
+ f("webhook.secretGracePeriodMs", "number", "How long the previous signing secret stays valid after a rotate"),
272
+ f("allowedIps.cidrs", "string[]", "CIDR ranges allowed to deliver"),
273
+ f("inputMapping", "table", "Maps the delivery body onto the workflow input"),
274
+ f("metadata", "table", "Free-form metadata carried with each delivery"),
275
+ f("verification", "table", "Per-scheme verification settings, e.g. [verification.jwt]"),
276
+ ],
277
+ scaffold: (key) => [
278
+ tomlSection("webhook", [
279
+ `key = "${key}"`,
280
+ `displayName = "${key}"`,
281
+ // #2803 — no `status` line: availability is server-owned, a pushed
282
+ // file carrying the key is rejected, and a new webhook is active.
283
+ `# The workflow a delivery starts.`,
284
+ `workflowKey = ""`,
285
+ `verificationScheme = "none"`,
286
+ `# Signing secrets are references, never literals:`,
287
+ `# signingSecret = "{{secrets.MY_WEBHOOK_SECRET}}"`,
288
+ ]),
289
+ "",
290
+ ].join("\n"),
291
+ },
292
+ {
293
+ type: "cron-trigger",
294
+ resourceType: resourceType("cron-trigger"),
295
+ fileHint: "cron-triggers/<key>.toml",
296
+ identity: "cronTrigger.key",
297
+ description: "A schedule that starts a workflow",
298
+ fields: [
299
+ f("cronTrigger.key", "string", "Trigger key", { required: true }),
300
+ f("cronTrigger.displayName", "string", "Display name", { required: true }),
301
+ f("cronTrigger.description", "string", "What the schedule is for"),
302
+ f("cronTrigger.cron", "string", "Cron expression", { required: true }),
303
+ f("cronTrigger.timezone", "string", "IANA timezone", { default: "UTC" }),
304
+ f("cronTrigger.workflowKey", "string", "Workflow the tick starts", {
305
+ required: true,
306
+ }),
307
+ f("cronTrigger.overlapPolicy", "string", "skip | allow", {
308
+ default: "skip",
309
+ }),
310
+ // #2645 criterion 9 — `cronTrigger.state` used to live here. Pausing a
311
+ // trigger wrote `state`, and so did `config push`, which made two writers
312
+ // for one piece of state. Pause state moved to the `operationallyDisabled`
313
+ // runtime toggle (`cron-triggers pause|resume`), and `state` went back to
314
+ // being server-owned lifecycle, so there is no `state` key to author.
315
+ f("rootInput", "table", "Static input passed to every run"),
316
+ f("inputMapping", "table", "Maps the tick onto the workflow input"),
317
+ ],
318
+ scaffold: (key) => [
319
+ tomlSection("cronTrigger", [
320
+ `key = "${key}"`,
321
+ `displayName = "${key}"`,
322
+ `# Minute hour day month weekday`,
323
+ `cron = "0 * * * *"`,
324
+ `timezone = "UTC"`,
325
+ `workflowKey = ""`,
326
+ `overlapPolicy = "skip"`,
327
+ ]),
328
+ "",
329
+ ].join("\n"),
330
+ },
331
+ {
332
+ type: "blob-bucket",
333
+ resourceType: resourceType("blob-bucket"),
334
+ fileHint: "blob-buckets/<key>.toml",
335
+ identity: "bucket.key",
336
+ description: "A blob storage bucket and its access model",
337
+ fields: [
338
+ f("bucket.key", "string", "Bucket key", { required: true }),
339
+ f("bucket.name", "string", "Display name", { required: true }),
340
+ f("bucket.description", "string", "What the bucket holds"),
341
+ // Required, and immutable once the bucket exists: the create endpoint
342
+ // rejects a missing or unknown tier (`blob-buckets-controller.ts`,
343
+ // VALID_TTL_TIERS), and the tier is part of the R2 key prefix, so it can
344
+ // never be changed afterwards. Reporting it as optional — and scaffolding
345
+ // a file without it — left `config create blob-bucket <key>` producing a file
346
+ // whose first push 400s (issue #2645).
347
+ f("bucket.ttlTier", "string", "Retention tier: 1d | 3d | 14d | 28d | 180d | 365d | permanent; immutable once the bucket exists", { required: true }),
348
+ f("bucket.preset", "string", "Access preset: public | authenticated | admin-only | personal-uploads; mutually exclusive with accessPolicy and ruleSetId"),
349
+ f("bucket.accessPolicy", "string", "Inline access policy; mutually exclusive with preset"),
350
+ f("bucket.ruleSetId", "string", "Rule set governing access"),
351
+ ],
352
+ scaffold: (key) => [
353
+ tomlSection("bucket", [
354
+ `key = "${key}"`,
355
+ `name = "${key}"`,
356
+ `# Retention tier, fixed at creation: 1d, 3d, 14d, 28d, 180d, 365d or permanent.`,
357
+ `ttlTier = "permanent"`,
358
+ `# One of preset, accessPolicy or ruleSetId decides who may read and write.`,
359
+ `# Presets: public, authenticated, admin-only, personal-uploads.`,
360
+ `preset = "admin-only"`,
361
+ ]),
362
+ "",
363
+ ].join("\n"),
364
+ },
365
+ {
366
+ type: "prompt",
367
+ resourceType: resourceType("prompt"),
368
+ fileHint: "prompts/<key>.toml",
369
+ identity: "prompt.key",
370
+ description: "An LLM prompt and its named model configs",
371
+ fields: [
372
+ f("prompt.key", "string", "Prompt key", { required: true }),
373
+ f("prompt.displayName", "string", "Display name", { required: true }),
374
+ f("prompt.description", "string", "What the prompt is for"),
375
+ f("prompt.inputSchema", "json", "JSON Schema for the prompt input"),
376
+ f("prompt.outputSchema", "json", "JSON Schema for the prompt output"),
377
+ f("configs", "table[]", "Named model configs", { required: true }),
378
+ f("configs.name", "string", "Config name", { required: true }),
379
+ f("configs.active", "boolean", "Marks the live config", {
380
+ default: false,
381
+ }),
382
+ // `prompts configs update --status archived` was the only way to retire a
383
+ // config before this issue removed it, so the key that replaced it has to
384
+ // be listed — an unlisted field is a capability the removal took away as
385
+ // far as anyone reading `config fields` can tell (issue #2645, review
386
+ // follow-up). Absent means unchanged: the server defaults a new config to
387
+ // active and leaves an existing one as it is.
388
+ f("configs.status", "string", "draft | active | archived"),
389
+ f("configs.description", "string", "What this config is tuned for"),
390
+ f("configs.provider", "string", "Model provider", { required: true }),
391
+ f("configs.model", "string", "Model id", { required: true }),
392
+ f("configs.temperature", "number", "Sampling temperature"),
393
+ f("configs.maxTokens", "number", "Output token cap"),
394
+ f("configs.outputFormat", "string", "text | json"),
395
+ f("configs.systemPrompt", "string", "System prompt"),
396
+ f("configs.userPromptTemplate", "string", "User prompt template"),
397
+ ],
398
+ companionFiles: [
399
+ testCaseCompanion("prompts/<key>.tests/<name>.toml", "prompts/<key>.tests/<name>/"),
400
+ ],
401
+ scaffold: (key) => [
402
+ tomlSection("prompt", [
403
+ `key = "${key}"`,
404
+ `displayName = "${key}"`,
405
+ ]),
406
+ "",
407
+ "[[configs]]",
408
+ `name = "default"`,
409
+ `# Exactly one config carries active = true; it is the live one.`,
410
+ `active = true`,
411
+ `provider = "openrouter"`,
412
+ `model = "anthropic/claude-sonnet-4.5"`,
413
+ `systemPrompt = ""`,
414
+ `userPromptTemplate = ""`,
415
+ "",
416
+ ].join("\n"),
417
+ },
418
+ {
419
+ type: "workflow",
420
+ resourceType: resourceType("workflow"),
421
+ fileHint: "workflows/<key>.toml",
422
+ identity: "workflow.key",
423
+ description: "A workflow definition and its steps",
424
+ fields: WORKFLOW_FIELDS,
425
+ companionFiles: WORKFLOW_COMPANION_FILES,
426
+ scaffold: (key) => [
427
+ tomlSection("workflow", [
428
+ `key = "${key}"`,
429
+ `name = "${key}"`,
430
+ // #2803 — no `status` line: availability is server-owned, a pushed
431
+ // file carrying the key is rejected, and a new workflow is active.
432
+ `# CEL expression deciding who may run this workflow.`,
433
+ `accessRule = "true"`,
434
+ ]),
435
+ "",
436
+ "[[steps]]",
437
+ `id = "start"`,
438
+ `kind = "noop"`,
439
+ "",
440
+ ].join("\n"),
441
+ },
442
+ {
443
+ type: "transform",
444
+ resourceType: resourceType("transform"),
445
+ fileHint: "transforms/<name>.rhai",
446
+ description: "A Rhai transform script; the file name is the script name",
447
+ // A `.rhai` file is a script body, not a table of keys. `config fields
448
+ // transform` reports that rather than inventing TOML keys for it.
449
+ fields: [],
450
+ companionFiles: [
451
+ testCaseCompanion("transforms/<name>.tests/<case>.toml", "transforms/<name>.tests/<case>/"),
452
+ ],
453
+ scaffold: (key) => [
454
+ `// Transform: ${key}`,
455
+ `// The script's return value is the step's output.`,
456
+ `input`,
457
+ "",
458
+ ].join("\n"),
459
+ },
460
+ {
461
+ type: "database-type-config",
462
+ resourceType: resourceType("database-type-config"),
463
+ fileHint: "database-type-configs/<type>.toml",
464
+ identity: "type.databaseType",
465
+ description: "A database type: its schema, operations and access model",
466
+ fields: [
467
+ f("type.databaseType", "string", "Type name", { required: true }),
468
+ f("type.ruleSetName", "string", "Rule set governing record access"),
469
+ f("type.celContextAccess", "string", "CEL expression exposing context to rules; empty string clears it"),
470
+ f("type.defaultAccess", "string", "Access applied when no rule matches"),
471
+ f("type.autoPopulatedFields", "table", "Fields the server fills in"),
472
+ f("type.timestamps", "table", "Create/update timestamp field names"),
473
+ f("models", "table", "The `[models.*]` schema subtree"),
474
+ f("operations", "table[]", "Named query and mutation operations"),
475
+ f("subscriptions", "table[]", "Named subscriptions"),
476
+ f("triggers", "table", "Record lifecycle triggers"),
477
+ f("metadata", "table", "Declared-access manifest"),
478
+ ],
479
+ scaffold: (key) => [
480
+ tomlSection("type", [`databaseType = "${key}"`]),
481
+ "",
482
+ `[models.${key}]`,
483
+ `# Field definitions go here, e.g.`,
484
+ `# title = { type = "string", required = true }`,
485
+ "",
486
+ ].join("\n"),
487
+ },
488
+ {
489
+ type: "rule-set",
490
+ resourceType: resourceType("rule-set"),
491
+ fileHint: "rule-sets/<name>.toml",
492
+ description: "A named set of CEL access rules",
493
+ fields: [
494
+ f("ruleSet.name", "string", "Rule set name", { required: true }),
495
+ f("ruleSet.resourceType", "string", "What the rules govern", {
496
+ required: true,
497
+ }),
498
+ f("ruleSet.description", "string", "What the rule set is for"),
499
+ f("rules", "table", "category → operation → CEL expression"),
500
+ ],
501
+ scaffold: (key) => [
502
+ tomlSection("ruleSet", [
503
+ `name = "${key}"`,
504
+ `resourceType = "database"`,
505
+ ]),
506
+ "",
507
+ tomlSection("rules.record", [
508
+ `read = "true"`,
509
+ `write = "false"`,
510
+ ]),
511
+ "",
512
+ ].join("\n"),
513
+ },
514
+ {
515
+ type: "group-type-config",
516
+ resourceType: resourceType("group-type-config"),
517
+ fileHint: "group-type-configs/<type>.toml",
518
+ identity: "groupTypeConfig.groupType",
519
+ description: "Access configuration for one group type",
520
+ fields: [
521
+ f("groupTypeConfig.groupType", "string", "Group type name", {
522
+ required: true,
523
+ }),
524
+ f("groupTypeConfig.ruleSetName", "string", "Rule set governing the group"),
525
+ f("groupTypeConfig.autoAddCreator", "boolean", "Add the creator as a member", { default: true }),
526
+ f("metadata", "table", "Declared-access manifest"),
527
+ ],
528
+ scaffold: (key) => [
529
+ tomlSection("groupTypeConfig", [
530
+ `groupType = "${key}"`,
531
+ `ruleSetName = ""`,
532
+ `autoAddCreator = true`,
533
+ ]),
534
+ "",
535
+ ].join("\n"),
536
+ },
537
+ {
538
+ type: "collection-type-config",
539
+ resourceType: resourceType("collection-type-config"),
540
+ fileHint: "collection-type-configs/<type>.toml",
541
+ identity: "collectionTypeConfig.collectionType",
542
+ description: "Access configuration for one collection type",
543
+ fields: [
544
+ f("collectionTypeConfig.collectionType", "string", "Collection type name", {
545
+ required: true,
546
+ }),
547
+ f("collectionTypeConfig.ruleSetName", "string", "Rule set governing the collection"),
548
+ f("metadata", "table", "Declared-access manifest"),
549
+ ],
550
+ scaffold: (key) => [
551
+ tomlSection("collectionTypeConfig", [
552
+ `collectionType = "${key}"`,
553
+ `ruleSetName = ""`,
554
+ ]),
555
+ "",
556
+ ].join("\n"),
557
+ },
558
+ {
559
+ type: "metadata-category-config",
560
+ resourceType: resourceType("metadata-category-config"),
561
+ fileHint: "metadata-category-configs/<resourceType>.<category>.toml",
562
+ identity: "metadataCategoryConfig.category",
563
+ description: "Schema and access rules for one metadata category",
564
+ fields: [
565
+ f("metadataCategoryConfig.resourceType", "string", "Resource type the category attaches to", { required: true }),
566
+ f("metadataCategoryConfig.category", "string", "Category name", {
567
+ required: true,
568
+ }),
569
+ f("metadataCategoryConfig.description", "string", "What the category holds"),
570
+ f("metadataCategoryConfig.readRule", "string", "CEL expression for reads"),
571
+ f("metadataCategoryConfig.writeRule", "string", "CEL expression for writes"),
572
+ f("metadataCategoryConfig.schema", "table", "Field definitions"),
573
+ ],
574
+ // The file is named `<resourceType>.<category>.toml`, so `config create
575
+ // metadata-category-config document.review` splits the key on the first dot.
576
+ scaffold: (key) => {
577
+ const dot = key.indexOf(".");
578
+ const resource = dot > 0 ? key.slice(0, dot) : key;
579
+ const category = dot > 0 ? key.slice(dot + 1) : key;
580
+ return [
581
+ tomlSection("metadataCategoryConfig", [
582
+ `resourceType = "${resource}"`,
583
+ `category = "${category}"`,
584
+ `readRule = "true"`,
585
+ `writeRule = "false"`,
586
+ ]),
587
+ "",
588
+ tomlSection("metadataCategoryConfig.schema.fields", []),
589
+ "",
590
+ ].join("\n");
591
+ },
592
+ },
593
+ {
594
+ type: "email-template",
595
+ resourceType: resourceType("email-template"),
596
+ fileHint: "email-templates/<emailType>.toml",
597
+ identity: "template.emailType",
598
+ description: "An override for one transactional email",
599
+ fields: [
600
+ f("template.emailType", "string", "Which email this overrides", {
601
+ required: true,
602
+ }),
603
+ f("template.subject", "string", "Subject line", { required: true }),
604
+ f("template.htmlBody", "string", "HTML body"),
605
+ f("template.textBody", "string", "Plain-text body"),
606
+ ],
607
+ scaffold: (key) => [
608
+ tomlSection("template", [
609
+ `emailType = "${key}"`,
610
+ `subject = ""`,
611
+ `textBody = ""`,
612
+ ]),
613
+ "",
614
+ ].join("\n"),
615
+ },
616
+ // ---- root singletons ----------------------------------------------------
617
+ {
618
+ type: "app",
619
+ fileHint: "app.toml",
620
+ description: "App settings — the `app.toml` root singleton",
621
+ fields: APP_FIELDS,
622
+ scaffold: () => [
623
+ tomlSection("app", [`name = ""`, `mode = "standard"`]),
624
+ "",
625
+ tomlSection("auth", [
626
+ `passkeyEnabled = false`,
627
+ `emailSignInEnabled = true`,
628
+ ]),
629
+ "",
630
+ tomlSection("cors", [`mode = "universal"`]),
631
+ "",
632
+ tomlSection("invitations", [`enabled = false`, `limit = 0`]),
633
+ "",
634
+ ].join("\n"),
635
+ },
636
+ {
637
+ type: "var",
638
+ fileHint: "vars.toml",
639
+ description: "Non-secret config vars — the `vars.toml` root singleton",
640
+ // `vars.toml` is a FLAT root table (`API_BASE_URL = "https://…"`), so the
641
+ // keys are the app's own and there is no fixed field list to report.
642
+ freeFormRootKeys: true,
643
+ fields: [],
644
+ scaffold: () => [
645
+ "# Per-environment non-secret config vars.",
646
+ "# Bind as {{ vars.KEY }} in workflow/integration config and vars.* in CEL",
647
+ "# rules. Never put a credential here — use `primitive secrets` for that.",
648
+ "",
649
+ ].join("\n"),
650
+ },
651
+ ];
652
+ const BY_TYPE = new Map(CONFIG_OBJECT_DESCRIPTORS.map((d) => [d.type, d]));
653
+ /** Every selector type name, in registry order. */
654
+ export const CONFIG_OBJECT_TYPES = CONFIG_OBJECT_DESCRIPTORS.map((d) => d.type);
655
+ export function getConfigObjectDescriptor(type) {
656
+ return BY_TYPE.get(type);
657
+ }
658
+ //# sourceMappingURL=config-object-descriptor.js.map