primitive-admin 1.1.0-alpha.7 → 1.1.0-alpha.71

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 (438) hide show
  1. package/README.md +404 -80
  2. package/assets/skill/skills/primitive-platform/SKILL.md +808 -0
  3. package/dist/bin/primitive.d.ts +2 -0
  4. package/dist/bin/primitive.js +294 -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 +138 -19
  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 +544 -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 +51 -96
  14. package/dist/src/commands/apps.js.map +1 -1
  15. package/dist/src/commands/auth.d.ts +2 -0
  16. package/dist/src/commands/auth.js +177 -7
  17. package/dist/src/commands/auth.js.map +1 -1
  18. package/dist/src/commands/blob-buckets.d.ts +2 -0
  19. package/dist/src/commands/blob-buckets.js +330 -0
  20. package/dist/src/commands/blob-buckets.js.map +1 -0
  21. package/dist/src/commands/catalog.d.ts +2 -0
  22. package/dist/src/commands/catalog.js +37 -38
  23. package/dist/src/commands/catalog.js.map +1 -1
  24. package/dist/src/commands/collection-type-configs.d.ts +2 -0
  25. package/dist/src/commands/collection-type-configs.js +92 -0
  26. package/dist/src/commands/collection-type-configs.js.map +1 -0
  27. package/dist/src/commands/collections.d.ts +2 -0
  28. package/dist/src/commands/collections.js +565 -0
  29. package/dist/src/commands/collections.js.map +1 -0
  30. package/dist/src/commands/comparisons.d.ts +2 -0
  31. package/dist/src/commands/comparisons.js +6 -6
  32. package/dist/src/commands/comparisons.js.map +1 -1
  33. package/dist/src/commands/config.d.ts +46 -0
  34. package/dist/src/commands/config.js +479 -0
  35. package/dist/src/commands/config.js.map +1 -0
  36. package/dist/src/commands/connections.d.ts +2 -0
  37. package/dist/src/commands/connections.js +100 -0
  38. package/dist/src/commands/connections.js.map +1 -0
  39. package/dist/src/commands/cron-triggers.d.ts +2 -0
  40. package/dist/src/commands/cron-triggers.js +265 -0
  41. package/dist/src/commands/cron-triggers.js.map +1 -0
  42. package/dist/src/commands/database-type-configs.d.ts +2 -0
  43. package/dist/src/commands/database-type-configs.js +171 -0
  44. package/dist/src/commands/database-type-configs.js.map +1 -0
  45. package/dist/src/commands/database-types.d.ts +2 -0
  46. package/dist/src/commands/database-types.js +471 -0
  47. package/dist/src/commands/database-types.js.map +1 -0
  48. package/dist/src/commands/databases.d.ts +65 -0
  49. package/dist/src/commands/databases.js +2140 -112
  50. package/dist/src/commands/databases.js.map +1 -1
  51. package/dist/src/commands/documents.d.ts +2 -0
  52. package/dist/src/commands/documents.js +1357 -19
  53. package/dist/src/commands/documents.js.map +1 -1
  54. package/dist/src/commands/email-templates.d.ts +2 -0
  55. package/dist/src/commands/email-templates.js +174 -0
  56. package/dist/src/commands/email-templates.js.map +1 -0
  57. package/dist/src/commands/env.d.ts +23 -0
  58. package/dist/src/commands/env.js +333 -0
  59. package/dist/src/commands/env.js.map +1 -0
  60. package/dist/src/commands/feature-flags.d.ts +14 -0
  61. package/dist/src/commands/feature-flags.js +116 -0
  62. package/dist/src/commands/feature-flags.js.map +1 -0
  63. package/dist/src/commands/group-type-configs.d.ts +2 -0
  64. package/dist/src/commands/group-type-configs.js +86 -0
  65. package/dist/src/commands/group-type-configs.js.map +1 -0
  66. package/dist/src/commands/groups.d.ts +2 -0
  67. package/dist/src/commands/groups.js +38 -99
  68. package/dist/src/commands/groups.js.map +1 -1
  69. package/dist/src/commands/guides.d.ts +223 -0
  70. package/dist/src/commands/guides.js +617 -65
  71. package/dist/src/commands/guides.js.map +1 -1
  72. package/dist/src/commands/init.d.ts +25 -0
  73. package/dist/src/commands/init.js +1605 -208
  74. package/dist/src/commands/init.js.map +1 -1
  75. package/dist/src/commands/integrations.d.ts +2 -0
  76. package/dist/src/commands/integrations.js +380 -178
  77. package/dist/src/commands/integrations.js.map +1 -1
  78. package/dist/src/commands/llm.d.ts +2 -0
  79. package/dist/src/commands/llm.js +4 -2
  80. package/dist/src/commands/llm.js.map +1 -1
  81. package/dist/src/commands/locks.d.ts +8 -0
  82. package/dist/src/commands/locks.js +160 -0
  83. package/dist/src/commands/locks.js.map +1 -0
  84. package/dist/src/commands/metadata-category-configs.d.ts +12 -0
  85. package/dist/src/commands/metadata-category-configs.js +112 -0
  86. package/dist/src/commands/metadata-category-configs.js.map +1 -0
  87. package/dist/src/commands/metadata.d.ts +2 -0
  88. package/dist/src/commands/metadata.js +281 -0
  89. package/dist/src/commands/metadata.js.map +1 -0
  90. package/dist/src/commands/prompts.d.ts +2 -0
  91. package/dist/src/commands/prompts.js +225 -584
  92. package/dist/src/commands/prompts.js.map +1 -1
  93. package/dist/src/commands/rule-sets.d.ts +3 -0
  94. package/dist/src/commands/rule-sets.js +272 -0
  95. package/dist/src/commands/rule-sets.js.map +1 -0
  96. package/dist/src/commands/scripts.d.ts +20 -0
  97. package/dist/src/commands/scripts.js +554 -0
  98. package/dist/src/commands/scripts.js.map +1 -0
  99. package/dist/src/commands/secrets.d.ts +2 -0
  100. package/dist/src/commands/secrets.js +108 -0
  101. package/dist/src/commands/secrets.js.map +1 -0
  102. package/dist/src/commands/sessions.d.ts +2 -0
  103. package/dist/src/commands/sessions.js +75 -0
  104. package/dist/src/commands/sessions.js.map +1 -0
  105. package/dist/src/commands/skill.d.ts +2 -0
  106. package/dist/src/commands/skill.js +29 -0
  107. package/dist/src/commands/skill.js.map +1 -0
  108. package/dist/src/commands/sync-app-settings.d.ts +158 -0
  109. package/dist/src/commands/sync-app-settings.js +330 -0
  110. package/dist/src/commands/sync-app-settings.js.map +1 -0
  111. package/dist/src/commands/sync.d.ts +2323 -0
  112. package/dist/src/commands/sync.js +15065 -843
  113. package/dist/src/commands/sync.js.map +1 -1
  114. package/dist/src/commands/tokens.d.ts +2 -0
  115. package/dist/src/commands/tokens.js +130 -21
  116. package/dist/src/commands/tokens.js.map +1 -1
  117. package/dist/src/commands/users.d.ts +2 -0
  118. package/dist/src/commands/users.js +532 -23
  119. package/dist/src/commands/users.js.map +1 -1
  120. package/dist/src/commands/vars.d.ts +8 -0
  121. package/dist/src/commands/vars.js +96 -0
  122. package/dist/src/commands/vars.js.map +1 -0
  123. package/dist/src/commands/waitlist.d.ts +2 -0
  124. package/dist/src/commands/waitlist.js +10 -10
  125. package/dist/src/commands/waitlist.js.map +1 -1
  126. package/dist/src/commands/webhooks.d.ts +2 -0
  127. package/dist/src/commands/webhooks.js +562 -0
  128. package/dist/src/commands/webhooks.js.map +1 -0
  129. package/dist/src/commands/workflows.d.ts +116 -0
  130. package/dist/src/commands/workflows.js +1583 -681
  131. package/dist/src/commands/workflows.js.map +1 -1
  132. package/dist/src/lib/access-rule-display.d.ts +21 -0
  133. package/dist/src/lib/access-rule-display.js +34 -0
  134. package/dist/src/lib/access-rule-display.js.map +1 -0
  135. package/dist/src/lib/api-client.d.ts +1936 -0
  136. package/dist/src/lib/api-client.js +1826 -138
  137. package/dist/src/lib/api-client.js.map +1 -1
  138. package/dist/src/lib/app-settings-descriptor.d.ts +263 -0
  139. package/dist/src/lib/app-settings-descriptor.js +575 -0
  140. package/dist/src/lib/app-settings-descriptor.js.map +1 -0
  141. package/dist/src/lib/auth-flow.d.ts +8 -0
  142. package/dist/src/lib/batch.d.ts +26 -0
  143. package/dist/src/lib/batch.js +32 -0
  144. package/dist/src/lib/batch.js.map +1 -0
  145. package/dist/src/lib/block-layout.d.ts +160 -0
  146. package/dist/src/lib/block-layout.js +451 -0
  147. package/dist/src/lib/block-layout.js.map +1 -0
  148. package/dist/src/lib/canonical-json.d.ts +12 -0
  149. package/dist/src/lib/canonical-json.js +35 -0
  150. package/dist/src/lib/canonical-json.js.map +1 -0
  151. package/dist/src/lib/channel.d.ts +30 -0
  152. package/dist/src/lib/channel.js +68 -0
  153. package/dist/src/lib/channel.js.map +1 -0
  154. package/dist/src/lib/cli-manifest.d.ts +68 -0
  155. package/dist/src/lib/cli-manifest.js +71 -0
  156. package/dist/src/lib/cli-manifest.js.map +1 -0
  157. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +101 -0
  158. package/dist/src/lib/codegen-shared/generatedFiles.js +191 -0
  159. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -0
  160. package/dist/src/lib/codegen-shared/prettierStable.d.ts +262 -0
  161. package/dist/src/lib/codegen-shared/prettierStable.js +610 -0
  162. package/dist/src/lib/codegen-shared/prettierStable.js.map +1 -0
  163. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +68 -0
  164. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +168 -0
  165. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -0
  166. package/dist/src/lib/config-object-descriptor.d.ts +127 -0
  167. package/dist/src/lib/config-object-descriptor.js +658 -0
  168. package/dist/src/lib/config-object-descriptor.js.map +1 -0
  169. package/dist/src/lib/config-payload.d.ts +85 -0
  170. package/dist/src/lib/config-payload.js +116 -0
  171. package/dist/src/lib/config-payload.js.map +1 -0
  172. package/dist/src/lib/config-surface.d.ts +130 -0
  173. package/dist/src/lib/config-surface.js +300 -0
  174. package/dist/src/lib/config-surface.js.map +1 -0
  175. package/dist/src/lib/config-toml.d.ts +10 -0
  176. package/dist/src/lib/config-toml.js +42 -0
  177. package/dist/src/lib/config-toml.js.map +1 -0
  178. package/dist/src/lib/config.d.ts +53 -0
  179. package/dist/src/lib/config.js +92 -53
  180. package/dist/src/lib/config.js.map +1 -1
  181. package/dist/src/lib/confirm-prompt.d.ts +83 -0
  182. package/dist/src/lib/confirm-prompt.js +110 -0
  183. package/dist/src/lib/confirm-prompt.js.map +1 -0
  184. package/dist/src/lib/constants.d.ts +11 -0
  185. package/dist/src/lib/constants.js +12 -0
  186. package/dist/src/lib/constants.js.map +1 -0
  187. package/dist/src/lib/crash-handlers.d.ts +20 -0
  188. package/dist/src/lib/crash-handlers.js +49 -0
  189. package/dist/src/lib/crash-handlers.js.map +1 -0
  190. package/dist/src/lib/credentials-store.d.ts +89 -0
  191. package/dist/src/lib/credentials-store.js +330 -0
  192. package/dist/src/lib/credentials-store.js.map +1 -0
  193. package/dist/src/lib/csv.d.ts +47 -0
  194. package/dist/src/lib/csv.js +172 -0
  195. package/dist/src/lib/csv.js.map +1 -0
  196. package/dist/src/lib/data-input.d.ts +23 -0
  197. package/dist/src/lib/data-input.js +50 -0
  198. package/dist/src/lib/data-input.js.map +1 -0
  199. package/dist/src/lib/db-codegen/dbFingerprint.d.ts +10 -0
  200. package/dist/src/lib/db-codegen/dbFingerprint.js +17 -0
  201. package/dist/src/lib/db-codegen/dbFingerprint.js.map +1 -0
  202. package/dist/src/lib/db-codegen/dbGenerator.d.ts +67 -0
  203. package/dist/src/lib/db-codegen/dbGenerator.js +170 -0
  204. package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -0
  205. package/dist/src/lib/db-codegen/dbNaming.d.ts +87 -0
  206. package/dist/src/lib/db-codegen/dbNaming.js +180 -0
  207. package/dist/src/lib/db-codegen/dbNaming.js.map +1 -0
  208. package/dist/src/lib/db-codegen/dbTemplates.d.ts +272 -0
  209. package/dist/src/lib/db-codegen/dbTemplates.js +480 -0
  210. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -0
  211. package/dist/src/lib/db-codegen/dbTsTypes.d.ts +73 -0
  212. package/dist/src/lib/db-codegen/dbTsTypes.js +139 -0
  213. package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -0
  214. package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
  215. package/dist/src/lib/db-codegen/dbTypeIR.js +517 -0
  216. package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
  217. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +112 -0
  218. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +211 -0
  219. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
  220. package/dist/src/lib/env-resolver-core.d.ts +147 -0
  221. package/dist/src/lib/env-resolver-core.js +265 -0
  222. package/dist/src/lib/env-resolver-core.js.map +1 -0
  223. package/dist/src/lib/env-resolver.d.ts +84 -0
  224. package/dist/src/lib/env-resolver.js +133 -0
  225. package/dist/src/lib/env-resolver.js.map +1 -0
  226. package/dist/src/lib/fetch.d.ts +5 -0
  227. package/dist/src/lib/generated-allowlist.d.ts +28 -0
  228. package/dist/src/lib/generated-allowlist.js +277 -0
  229. package/dist/src/lib/generated-allowlist.js.map +1 -0
  230. package/dist/src/lib/generated-config-surfaces.d.ts +682 -0
  231. package/dist/src/lib/generated-config-surfaces.js +4058 -0
  232. package/dist/src/lib/generated-config-surfaces.js.map +1 -0
  233. package/dist/src/lib/generated-template-lint.d.ts +212 -0
  234. package/dist/src/lib/generated-template-lint.js +624 -0
  235. package/dist/src/lib/generated-template-lint.js.map +1 -0
  236. package/dist/src/lib/init-adopt.d.ts +16 -0
  237. package/dist/src/lib/init-adopt.js +34 -0
  238. package/dist/src/lib/init-adopt.js.map +1 -0
  239. package/dist/src/lib/init-assets.d.ts +39 -0
  240. package/dist/src/lib/init-assets.js +97 -0
  241. package/dist/src/lib/init-assets.js.map +1 -0
  242. package/dist/src/lib/init-config.d.ts +98 -0
  243. package/dist/src/lib/init-config.js +186 -0
  244. package/dist/src/lib/init-config.js.map +1 -0
  245. package/dist/src/lib/init-ios-links.d.ts +50 -0
  246. package/dist/src/lib/init-ios-links.js +153 -0
  247. package/dist/src/lib/init-ios-links.js.map +1 -0
  248. package/dist/src/lib/init-plan.d.ts +80 -0
  249. package/dist/src/lib/init-plan.js +95 -0
  250. package/dist/src/lib/init-plan.js.map +1 -0
  251. package/dist/src/lib/init-production-env.d.ts +48 -0
  252. package/dist/src/lib/init-production-env.js +59 -0
  253. package/dist/src/lib/init-production-env.js.map +1 -0
  254. package/dist/src/lib/init-schema.d.ts +74 -0
  255. package/dist/src/lib/init-schema.js +358 -0
  256. package/dist/src/lib/init-schema.js.map +1 -0
  257. package/dist/src/lib/init-xcode.d.ts +33 -0
  258. package/dist/src/lib/init-xcode.js +114 -0
  259. package/dist/src/lib/init-xcode.js.map +1 -0
  260. package/dist/src/lib/integration-request-config.d.ts +30 -0
  261. package/dist/src/lib/integration-request-config.js +145 -0
  262. package/dist/src/lib/integration-request-config.js.map +1 -0
  263. package/dist/src/lib/local-state.d.ts +55 -0
  264. package/dist/src/lib/local-state.js +167 -0
  265. package/dist/src/lib/local-state.js.map +1 -0
  266. package/dist/src/lib/log-inspection.d.ts +568 -0
  267. package/dist/src/lib/log-inspection.js +639 -0
  268. package/dist/src/lib/log-inspection.js.map +1 -0
  269. package/dist/src/lib/migration-nag.d.ts +49 -0
  270. package/dist/src/lib/migration-nag.js +163 -0
  271. package/dist/src/lib/migration-nag.js.map +1 -0
  272. package/dist/src/lib/object-status-filter.d.ts +22 -0
  273. package/dist/src/lib/object-status-filter.js +45 -0
  274. package/dist/src/lib/object-status-filter.js.map +1 -0
  275. package/dist/src/lib/output.d.ts +109 -0
  276. package/dist/src/lib/output.js +191 -8
  277. package/dist/src/lib/output.js.map +1 -1
  278. package/dist/src/lib/package-manager.d.ts +140 -0
  279. package/dist/src/lib/package-manager.js +305 -0
  280. package/dist/src/lib/package-manager.js.map +1 -0
  281. package/dist/src/lib/paginate.d.ts +83 -0
  282. package/dist/src/lib/paginate.js +95 -0
  283. package/dist/src/lib/paginate.js.map +1 -0
  284. package/dist/src/lib/platform-owned.d.ts +63 -0
  285. package/dist/src/lib/platform-owned.js +85 -0
  286. package/dist/src/lib/platform-owned.js.map +1 -0
  287. package/dist/src/lib/project-config.d.ts +97 -0
  288. package/dist/src/lib/project-config.js +217 -0
  289. package/dist/src/lib/project-config.js.map +1 -0
  290. package/dist/src/lib/query-operators.d.ts +43 -0
  291. package/dist/src/lib/query-operators.js +80 -0
  292. package/dist/src/lib/query-operators.js.map +1 -0
  293. package/dist/src/lib/record-filter.d.ts +18 -0
  294. package/dist/src/lib/record-filter.js +55 -0
  295. package/dist/src/lib/record-filter.js.map +1 -0
  296. package/dist/src/lib/refresh-admin-credentials.d.ts +65 -0
  297. package/dist/src/lib/refresh-admin-credentials.js +103 -0
  298. package/dist/src/lib/refresh-admin-credentials.js.map +1 -0
  299. package/dist/src/lib/resolve-init-dev-port.d.ts +56 -0
  300. package/dist/src/lib/resolve-init-dev-port.js +55 -0
  301. package/dist/src/lib/resolve-init-dev-port.js.map +1 -0
  302. package/dist/src/lib/resolve-init-server.d.ts +64 -0
  303. package/dist/src/lib/resolve-init-server.js +77 -0
  304. package/dist/src/lib/resolve-init-server.js.map +1 -0
  305. package/dist/src/lib/resolve-platform.d.ts +74 -0
  306. package/dist/src/lib/resolve-platform.js +105 -0
  307. package/dist/src/lib/resolve-platform.js.map +1 -0
  308. package/dist/src/lib/run-status.d.ts +19 -0
  309. package/dist/src/lib/run-status.generated.d.ts +39 -0
  310. package/dist/src/lib/run-status.generated.js +66 -0
  311. package/dist/src/lib/run-status.generated.js.map +1 -0
  312. package/dist/src/lib/run-status.js +19 -0
  313. package/dist/src/lib/run-status.js.map +1 -0
  314. package/dist/src/lib/server-text-normalization.d.ts +51 -0
  315. package/dist/src/lib/server-text-normalization.js +90 -0
  316. package/dist/src/lib/server-text-normalization.js.map +1 -0
  317. package/dist/src/lib/server-url.d.ts +22 -0
  318. package/dist/src/lib/server-url.js +33 -0
  319. package/dist/src/lib/server-url.js.map +1 -0
  320. package/dist/src/lib/signing-secret-status.d.ts +81 -0
  321. package/dist/src/lib/signing-secret-status.js +116 -0
  322. package/dist/src/lib/signing-secret-status.js.map +1 -0
  323. package/dist/src/lib/skill-installer.d.ts +25 -0
  324. package/dist/src/lib/skill-installer.js +266 -0
  325. package/dist/src/lib/skill-installer.js.map +1 -0
  326. package/dist/src/lib/snapshots.d.ts +99 -0
  327. package/dist/src/lib/snapshots.js +357 -0
  328. package/dist/src/lib/snapshots.js.map +1 -0
  329. package/dist/src/lib/swift-codegen/dbGenerator.d.ts +113 -0
  330. package/dist/src/lib/swift-codegen/dbGenerator.js +914 -0
  331. package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
  332. package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
  333. package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
  334. package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
  335. package/dist/src/lib/swift-codegen/generator.d.ts +94 -0
  336. package/dist/src/lib/swift-codegen/generator.js +440 -0
  337. package/dist/src/lib/swift-codegen/generator.js.map +1 -0
  338. package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +72 -0
  339. package/dist/src/lib/swift-codegen/schemaToSwift.js +644 -0
  340. package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
  341. package/dist/src/lib/swift-codegen/siblingSymbols.d.ts +94 -0
  342. package/dist/src/lib/swift-codegen/siblingSymbols.js +155 -0
  343. package/dist/src/lib/swift-codegen/siblingSymbols.js.map +1 -0
  344. package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
  345. package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
  346. package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
  347. package/dist/src/lib/sync-dir-selector.d.ts +21 -0
  348. package/dist/src/lib/sync-dir-selector.js +30 -0
  349. package/dist/src/lib/sync-dir-selector.js.map +1 -0
  350. package/dist/src/lib/sync-paths.d.ts +111 -0
  351. package/dist/src/lib/sync-paths.js +198 -0
  352. package/dist/src/lib/sync-paths.js.map +1 -0
  353. package/dist/src/lib/sync-resource-types.d.ts +544 -0
  354. package/dist/src/lib/sync-resource-types.js +975 -0
  355. package/dist/src/lib/sync-resource-types.js.map +1 -0
  356. package/dist/src/lib/sync-selectors.d.ts +95 -0
  357. package/dist/src/lib/sync-selectors.js +228 -0
  358. package/dist/src/lib/sync-selectors.js.map +1 -0
  359. package/dist/src/lib/template.d.ts +170 -0
  360. package/dist/src/lib/template.js +484 -68
  361. package/dist/src/lib/template.js.map +1 -1
  362. package/dist/src/lib/test-case-keys.d.ts +29 -0
  363. package/dist/src/lib/test-case-keys.js +55 -0
  364. package/dist/src/lib/test-case-keys.js.map +1 -0
  365. package/dist/src/lib/test-case-variables.d.ts +15 -0
  366. package/dist/src/lib/test-case-variables.js +29 -0
  367. package/dist/src/lib/test-case-variables.js.map +1 -0
  368. package/dist/src/lib/token-inject.d.ts +56 -0
  369. package/dist/src/lib/token-inject.js +204 -0
  370. package/dist/src/lib/token-inject.js.map +1 -0
  371. package/dist/src/lib/toml-database-config.d.ts +123 -0
  372. package/dist/src/lib/toml-database-config.js +527 -0
  373. package/dist/src/lib/toml-database-config.js.map +1 -0
  374. package/dist/src/lib/toml-metadata-config.d.ts +151 -0
  375. package/dist/src/lib/toml-metadata-config.js +476 -0
  376. package/dist/src/lib/toml-metadata-config.js.map +1 -0
  377. package/dist/src/lib/toml-native-form.d.ts +46 -0
  378. package/dist/src/lib/toml-native-form.js +78 -0
  379. package/dist/src/lib/toml-native-form.js.map +1 -0
  380. package/dist/src/lib/toml-params-validator.d.ts +129 -0
  381. package/dist/src/lib/toml-params-validator.js +298 -0
  382. package/dist/src/lib/toml-params-validator.js.map +1 -0
  383. package/dist/src/lib/toml-scalar-edit.d.ts +43 -0
  384. package/dist/src/lib/toml-scalar-edit.js +283 -0
  385. package/dist/src/lib/toml-scalar-edit.js.map +1 -0
  386. package/dist/src/lib/user-selector.d.ts +24 -0
  387. package/dist/src/lib/user-selector.js +33 -0
  388. package/dist/src/lib/user-selector.js.map +1 -0
  389. package/dist/src/lib/version-check.d.ts +35 -0
  390. package/dist/src/lib/version-check.js +241 -0
  391. package/dist/src/lib/version-check.js.map +1 -0
  392. package/dist/src/lib/watch.d.ts +121 -0
  393. package/dist/src/lib/watch.js +169 -0
  394. package/dist/src/lib/watch.js.map +1 -0
  395. package/dist/src/lib/workflow-apply.d.ts +110 -0
  396. package/dist/src/lib/workflow-apply.js +164 -0
  397. package/dist/src/lib/workflow-apply.js.map +1 -0
  398. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.d.ts +129 -0
  399. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js +269 -0
  400. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js.map +1 -0
  401. package/dist/src/lib/workflow-codegen/generator.d.ts +96 -0
  402. package/dist/src/lib/workflow-codegen/generator.js +361 -0
  403. package/dist/src/lib/workflow-codegen/generator.js.map +1 -0
  404. package/dist/src/lib/workflow-codegen/invokerIR.d.ts +94 -0
  405. package/dist/src/lib/workflow-codegen/invokerIR.js +76 -0
  406. package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
  407. package/dist/src/lib/workflow-codegen/naming.d.ts +33 -0
  408. package/dist/src/lib/workflow-codegen/naming.js +81 -0
  409. package/dist/src/lib/workflow-codegen/naming.js.map +1 -0
  410. package/dist/src/lib/workflow-codegen/schemaToTs.d.ts +80 -0
  411. package/dist/src/lib/workflow-codegen/schemaToTs.js +303 -0
  412. package/dist/src/lib/workflow-codegen/schemaToTs.js.map +1 -0
  413. package/dist/src/lib/workflow-config-apply.d.ts +70 -0
  414. package/dist/src/lib/workflow-config-apply.js +137 -0
  415. package/dist/src/lib/workflow-config-apply.js.map +1 -0
  416. package/dist/src/lib/workflow-config-sidecar.d.ts +63 -0
  417. package/dist/src/lib/workflow-config-sidecar.js +96 -0
  418. package/dist/src/lib/workflow-config-sidecar.js.map +1 -0
  419. package/dist/src/lib/workflow-defaults.d.ts +29 -0
  420. package/dist/src/lib/workflow-defaults.js +41 -0
  421. package/dist/src/lib/workflow-defaults.js.map +1 -0
  422. package/dist/src/lib/workflow-fragments.d.ts +64 -0
  423. package/dist/src/lib/workflow-fragments.js +342 -0
  424. package/dist/src/lib/workflow-fragments.js.map +1 -0
  425. package/dist/src/lib/workflow-include-preserve.d.ts +76 -0
  426. package/dist/src/lib/workflow-include-preserve.js +286 -0
  427. package/dist/src/lib/workflow-include-preserve.js.map +1 -0
  428. package/dist/src/lib/workflow-payload.d.ts +98 -0
  429. package/dist/src/lib/workflow-payload.js +178 -0
  430. package/dist/src/lib/workflow-payload.js.map +1 -0
  431. package/dist/src/lib/workflow-toml-validator.d.ts +202 -0
  432. package/dist/src/lib/workflow-toml-validator.js +757 -0
  433. package/dist/src/lib/workflow-toml-validator.js.map +1 -0
  434. package/dist/src/types/index.d.ts +581 -0
  435. package/dist/src/validators.d.ts +65 -0
  436. package/dist/src/validators.js +64 -0
  437. package/dist/src/validators.js.map +1 -0
  438. package/package.json +32 -8
@@ -0,0 +1,757 @@
1
+ /**
2
+ * Push-time validator for workflow TOML files (issue #685, #998).
3
+ *
4
+ * Detects the common footgun where a user writes `[steps.<id>.<field>]` under
5
+ * an open `[[steps]]` array. TOML parses that as a sub-table on the
6
+ * most-recent step keyed by the step's id (e.g. `steps[0]["refresh-each"]`),
7
+ * not as the intended `steps[0].request`. The result is a step with an
8
+ * unrecognized top-level field — the runtime silently ignores it, and the
9
+ * step then runs with an empty `request` block.
10
+ *
11
+ * The validator walks every step in `tomlData.steps[]`. For a step whose
12
+ * `kind` the CLI KNOWS about, it reports any top-level field not in the
13
+ * generated allowlist. For an UNKNOWN kind (an old CLI run against a newer
14
+ * server that registered a step kind the CLI doesn't have), it SKIPS the
15
+ * per-field allowlist check — but still runs the kind-agnostic
16
+ * misnested-header footgun detector. This is the #998 fix: the recurring
17
+ * "newer server kind → false-reject of valid fields" failure (#685/#802/#971
18
+ * were all false rejections) becomes "unvalidated, not rejected."
19
+ *
20
+ * ── Source of truth (#998) ───────────────────────────────────────────────
21
+ * The allowlist field union and the known-kind set are GENERATED from the
22
+ * server step runners (`src/workflows/steps/*.ts`) and the universal
23
+ * `BaseStepDefinition` shape into the committed
24
+ * `cli/src/lib/generated-allowlist.ts` artifact (the CLI does NOT import
25
+ * server `src/` at runtime — only the build-time generator does). The union is
26
+ * derived from what each runner READS, not what the `*StepDefinition` TYPE
27
+ * declares — types over-declare and would weaken the footgun detector. A CI
28
+ * freshness guard (`gen-allowlist.mjs --check`, also asserted by the #985
29
+ * drift-guard test) keeps the committed artifact in sync with the runners, so
30
+ * the hand-edit drift class (#685/#802/#971) cannot recur for the same-version
31
+ * case. Regenerate with `node cli/scripts/gen-allowlist.mjs`.
32
+ */
33
+ import { GENERATED_ALLOWLISTED_FIELDS, GENERATED_KNOWN_KINDS, } from "./generated-allowlist.js";
34
+ // #2689 — the static `{{ }}` template lint, generated verbatim from the server
35
+ // module `src/workflows/runner/template-static-lint.ts` (see
36
+ // `cli/scripts/gen-template-lint.mjs`) so push-time and save-time verdicts are
37
+ // produced by the same code rather than a hand mirror.
38
+ import { lintWorkflowStepTemplates } from "./generated-template-lint.js";
39
+ /**
40
+ * Universal-and-consumed allowlist of top-level fields permitted on a step
41
+ * (known kinds). Generated from the runners; see header.
42
+ */
43
+ const ALLOWLISTED_FIELDS = new Set(GENERATED_ALLOWLISTED_FIELDS);
44
+ /**
45
+ * The set of step kinds the CLI knows about (the server's registered kinds at
46
+ * generation time). A step whose `kind` is NOT in this set has its per-field
47
+ * allowlist check skipped — the kind-agnostic footgun detector still runs.
48
+ */
49
+ const KNOWN_KINDS = new Set(GENERATED_KNOWN_KINDS);
50
+ /**
51
+ * Read-only view of `ALLOWLISTED_FIELDS` for the drift-guard test (#985).
52
+ *
53
+ * Exported so `cli/tests/unit/workflow-toml-validator-drift-guard.test.ts` can
54
+ * assert this set stays a superset of every top-level field the step runners
55
+ * in `src/workflows/steps/*.ts` actually read — checking the *live* set the
56
+ * validator enforces rather than a copy that could itself drift. Not part of
57
+ * the public validator API; consumed only by the guard.
58
+ */
59
+ export const ALLOWLISTED_FIELDS_FOR_DRIFT_GUARD = ALLOWLISTED_FIELDS;
60
+ /**
61
+ * Read-only view of `KNOWN_KINDS` for the drift-guard test (#998). Lets the
62
+ * guard assert the generated known-kind set matches a fresh scan.
63
+ */
64
+ export const KNOWN_KINDS_FOR_DRIFT_GUARD = KNOWN_KINDS;
65
+ /**
66
+ * #1447 workflow-identity predicate, extracted (codex review, 2026-07-15) so
67
+ * command sites that apply command-line metadata overrides can re-run it
68
+ * against the merged/effective workflow rather than only the parsed file.
69
+ *
70
+ * `runAs = "system"` + a non-empty `accessRule` is dead config: a system run
71
+ * can only be started by the system and never evaluates its accessRule, so any
72
+ * non-empty rule is inert. The server rejects this at save time (#1258,
73
+ * `src/workflows/definition-store.ts:271-280`); catching it locally keeps
74
+ * `config push` all-or-nothing instead of failing mid-push and leaving partial
75
+ * server state (#1418 drift).
76
+ *
77
+ * Mirrors the server predicate byte-for-byte: returns the sentinel error only
78
+ * when `runAs === "system"` AND `typeof accessRule === "string"` AND
79
+ * `accessRule.trim() !== ""`. Default/unset/empty/whitespace-only runAs or
80
+ * accessRule (and a bare non-string boolean accessRule) return `null`.
81
+ *
82
+ * @param workflow The workflow-metadata object — the `[workflow]` table, or
83
+ * for commands that accept unwrapped root-level metadata, the root TOML
84
+ * object (`tomlData.workflow || tomlData`). Non-object inputs return `null`.
85
+ */
86
+ export function validateWorkflowIdentity(workflow) {
87
+ if (workflow === null ||
88
+ typeof workflow !== "object" ||
89
+ Array.isArray(workflow)) {
90
+ return null;
91
+ }
92
+ const runAs = workflow.runAs;
93
+ const accessRule = workflow.accessRule;
94
+ if (runAs === "system" &&
95
+ typeof accessRule === "string" &&
96
+ accessRule.trim() !== "") {
97
+ return {
98
+ stepIndex: -1,
99
+ stepId: null,
100
+ field: "__workflow_system_access_rule__",
101
+ hint: 'accessRule has no effect when runAs = "system" (system runs skip ' +
102
+ "accessRule; gate callers with syncCallable + caller-mode, or see #1433)",
103
+ };
104
+ }
105
+ return null;
106
+ }
107
+ /**
108
+ * #2643 — `templateMissingMarker` was removed from the platform. A workflow
109
+ * TOML that still sets it is rejected here, before the push, with the same
110
+ * sentence the server returns, rather than being silently dropped.
111
+ */
112
+ export const REMOVED_TEMPLATE_MISSING_MARKER_MESSAGE = "templateMissingMarker is no longer supported. An unresolved template " +
113
+ "reference now fails the step on every workflow; mark individual " +
114
+ "expressions optional with `{{ x | default: '' }}` instead.";
115
+ /**
116
+ * #2645 — named workflow configs moved to sidecar files
117
+ * (`workflows/<key>.configs/<name>.toml`), so an inline `[[configs]]` list is
118
+ * no longer read by anything.
119
+ *
120
+ * It fails the push rather than being ignored. A pull taken before this change
121
+ * wrote those blocks, and push now applies only the sidecars: tolerating the
122
+ * list would leave the file describing configurations the server does not have
123
+ * — silently, since the content hash deliberately excludes the legacy list, so
124
+ * the object would not even report as Modified. The whole point of authoring
125
+ * configuration in TOML is that the committed file describes the server.
126
+ */
127
+ const RETIRED_INLINE_CONFIGS_MESSAGE = "`[[configs]]` is no longer read from a workflow file (#2645). Named " +
128
+ "configurations are authored one per file at " +
129
+ "`workflows/<key>.configs/<name>.toml`, and `[workflow].activeConfigName` " +
130
+ "selects the live one. Move each entry's body to its own sidecar file and " +
131
+ "delete the `[[configs]]` blocks.";
132
+ function validateRetiredInlineConfigs(tomlData) {
133
+ const configs = tomlData?.configs;
134
+ if (!Array.isArray(configs) || configs.length === 0)
135
+ return null;
136
+ return {
137
+ stepIndex: -1,
138
+ stepId: null,
139
+ field: "__workflow_inline_configs__",
140
+ hint: RETIRED_INLINE_CONFIGS_MESSAGE,
141
+ };
142
+ }
143
+ function validateRemovedWorkflowFields(workflow) {
144
+ if (!workflow || typeof workflow !== "object")
145
+ return null;
146
+ if (!Object.prototype.hasOwnProperty.call(workflow, "templateMissingMarker")) {
147
+ return null;
148
+ }
149
+ return {
150
+ stepIndex: -1,
151
+ stepId: null,
152
+ field: "__workflow_removed_field__",
153
+ hint: REMOVED_TEMPLATE_MISSING_MARKER_MESSAGE,
154
+ };
155
+ }
156
+ /**
157
+ * Non-blocking notes for a workflow TOML — things worth saying on a push that
158
+ * are not errors.
159
+ *
160
+ * #2643: `strict` / `strictParams` are accepted and ignored, because the
161
+ * failure they used to opt into now applies to every workflow. A definition
162
+ * that sets them keeps working unchanged, so this is a note, not an error.
163
+ */
164
+ export function collectWorkflowTomlNotes(tomlData) {
165
+ const notes = [];
166
+ const steps = tomlData?.steps;
167
+ if (!Array.isArray(steps))
168
+ return notes;
169
+ const usesStrict = steps.some((step) => step &&
170
+ typeof step === "object" &&
171
+ (Object.prototype.hasOwnProperty.call(step, "strict") ||
172
+ Object.prototype.hasOwnProperty.call(step, "strictParams")));
173
+ if (usesStrict) {
174
+ notes.push("Note: `strict` / `strictParams` no longer do anything — an unresolved " +
175
+ "template reference fails the step on every workflow (#2643). The keys " +
176
+ "are still accepted, so you can remove them at your convenience.");
177
+ }
178
+ return notes;
179
+ }
180
+ /**
181
+ * #1447 (maintainer decision, 2026-07-21): compute the EFFECTIVE workflow
182
+ * identity that an `update --from-file` push will leave on the server — the
183
+ * merge of the persisted record with the incoming file/flags.
184
+ *
185
+ * The merge exists for a caller whose push OMITS one side of the
186
+ * runAs/accessRule pair and lets the server retain it. Linting the incoming
187
+ * payload alone misses the case where the OTHER side is already `system` / a
188
+ * stored rule: an existing `runAs="system"` workflow plus a file adding only an
189
+ * `accessRule`, or a file flipping a workflow with a stored rule to
190
+ * `runAs="system"`. Both pass a payload-only lint and are then rejected by the
191
+ * server's PATCH. Merging the two before `validateWorkflowIdentity` catches
192
+ * them locally at zero extra cost — the persisted record is already fetched at
193
+ * the call site.
194
+ *
195
+ * NOT `config push`, since #2743: its update is always-send, so the file alone IS
196
+ * the effective config (an omitted `accessRule` clears the stored rule rather
197
+ * than inheriting it) and its push-time lint of the file is exact. The merge
198
+ * semantics below are unchanged for any caller that does omit fields: a field
199
+ * PRESENT in `incoming` (including an empty-string clear) overrides the stored
200
+ * value; an ABSENT field (undefined) falls back to what the server keeps.
201
+ */
202
+ export function effectiveWorkflowIdentity(existing, incoming) {
203
+ const ex = existing ?? {};
204
+ const inc = incoming ?? {};
205
+ return {
206
+ runAs: inc.runAs !== undefined ? inc.runAs : ex.runAs,
207
+ accessRule: inc.accessRule !== undefined ? inc.accessRule : ex.accessRule,
208
+ };
209
+ }
210
+ /**
211
+ * Walk a parsed workflow TOML document and return all unknown-field errors.
212
+ *
213
+ * @param tomlData The output of `parseConfigToml()` for a workflow TOML file.
214
+ * @param opts.skipWorkflowIdentity When true, suppress the #1447 workflow
215
+ * identity check (`runAs="system"` + non-empty `accessRule`). Callers that
216
+ * merge command-line overrides after parsing re-run `validateWorkflowIdentity`
217
+ * against the effective metadata themselves.
218
+ * @returns An array of error objects, one per offending field. Empty if no
219
+ * errors were found.
220
+ */
221
+ export function validateWorkflowToml(tomlData, opts) {
222
+ const errors = [];
223
+ if (tomlData === null || tomlData === undefined) {
224
+ return errors;
225
+ }
226
+ // #1447 — workflow-level identity lint: `runAs = "system"` + a non-empty
227
+ // `accessRule` is dead config. See `validateWorkflowIdentity` for the
228
+ // predicate. This runs BEFORE the `steps` early-returns below so a file
229
+ // carrying the bad combo but with missing/malformed `[[steps]]` is still
230
+ // flagged.
231
+ //
232
+ // Metadata shape (codex review, 2026-07-15): read the workflow table with
233
+ // the same `tomlData.workflow || tomlData` fallback the consuming commands
234
+ // use (`workflows create/update --from-file`), so an UNWRAPPED root-level
235
+ // TOML carrying `runAs`/`accessRule` is checked too — not only the wrapped
236
+ // `[workflow]` form.
237
+ //
238
+ // `skipWorkflowIdentity` (codex review, 2026-07-15): callers that apply
239
+ // command-line metadata overrides AFTER parsing (e.g. `workflows update
240
+ // --from-file` with `--access-rule`) pass this to suppress the identity
241
+ // check on the raw file, then re-run `validateWorkflowIdentity` against the
242
+ // merged/effective metadata themselves. Otherwise `--access-rule ""` could
243
+ // not repair an offending file, and an override-introduced accessRule would
244
+ // escape the lint. Structural checks (#685 misnest, etc.) still run.
245
+ if (!opts?.skipWorkflowIdentity) {
246
+ const identityError = validateWorkflowIdentity(tomlData.workflow || tomlData);
247
+ if (identityError)
248
+ errors.push(identityError);
249
+ }
250
+ // #2643 — a `[workflow]` key the platform has removed. Checked with the same
251
+ // `tomlData.workflow || tomlData` fallback as the identity lint so the
252
+ // unwrapped root-level form is caught too, and BEFORE the `steps`
253
+ // early-returns so a metadata-only file is still flagged.
254
+ const removedFieldError = validateRemovedWorkflowFields(tomlData.workflow || tomlData);
255
+ if (removedFieldError)
256
+ errors.push(removedFieldError);
257
+ // #2645 — an inline `[[configs]]` list, which named configs left behind when
258
+ // they moved to sidecar files. Read from the document root (not the
259
+ // `[workflow]` table) and before the `steps` early-returns, so a
260
+ // configs-only file is flagged too.
261
+ const inlineConfigsError = validateRetiredInlineConfigs(tomlData);
262
+ if (inlineConfigsError)
263
+ errors.push(inlineConfigsError);
264
+ const steps = tomlData.steps;
265
+ // No steps section at all → nothing to validate. This is fine for
266
+ // partial TOML files (some commands accept a metadata-only file).
267
+ if (steps === undefined || steps === null) {
268
+ return errors;
269
+ }
270
+ // `steps` is a table instead of an array. This typically means the user
271
+ // wrote `[steps.foo]` with no preceding `[[steps]]` array marker, so
272
+ // TOML resolved `steps` to a table. The runtime expects an array — flag
273
+ // it with a clear shape diagnostic.
274
+ if (!Array.isArray(steps)) {
275
+ if (typeof steps === "object") {
276
+ errors.push({
277
+ stepIndex: -1,
278
+ stepId: null,
279
+ field: "__steps_shape__",
280
+ hint: 'The `steps` section is a table, not an array. Workflow TOML expects `[[steps]]` array markers — add `[[steps]]` before any `[steps.<field>]` blocks.',
281
+ });
282
+ }
283
+ else {
284
+ errors.push({
285
+ stepIndex: -1,
286
+ stepId: null,
287
+ field: "__steps_shape__",
288
+ hint: `The \`steps\` section must be an array of step tables (received: ${typeof steps}).`,
289
+ });
290
+ }
291
+ return errors;
292
+ }
293
+ for (let i = 0; i < steps.length; i++) {
294
+ const step = steps[i];
295
+ // Defensive: array entry isn't an object. Should be near-impossible with
296
+ // valid `[[steps]]` syntax, but possible if the user writes `steps =
297
+ // ["a", "b"]`. Surface it so the user gets a diagnostic instead of a
298
+ // silent skip.
299
+ if (step === null || typeof step !== "object" || Array.isArray(step)) {
300
+ errors.push({
301
+ stepIndex: i,
302
+ stepId: null,
303
+ field: "__step_shape__",
304
+ hint: `Each entry in \`steps[]\` must be a table. Got: ${step === null ? "null" : Array.isArray(step) ? "array" : typeof step}.`,
305
+ });
306
+ continue;
307
+ }
308
+ validateStepObject(step, i, /* parentStepId */ null, errors);
309
+ // Codex finding 2 (PR #762, 2026-05-15): a `collect` step's nested
310
+ // `step` field is itself a step definition that the collect runner
311
+ // executes. The outer-step allowlist accepts `step` as a top-level
312
+ // field, but that's a structural pass-through — we need to recurse
313
+ // into the inner step's keys to catch the same misnested-header
314
+ // footgun (e.g. `[steps.step.call.request]` parses as `step.step =
315
+ // { call: { request: {...} } }`, with `call` as an unknown inner
316
+ // field; without the recursion this slips through). We only recurse
317
+ // for `kind === "collect"` — other kinds with a `step`-named field
318
+ // (none today) would need their own audit.
319
+ if (step.kind === "collect" &&
320
+ step.step !== null &&
321
+ typeof step.step === "object" &&
322
+ !Array.isArray(step.step)) {
323
+ const outerStepId = typeof step.id === "string" ? step.id : null;
324
+ validateStepObject(step.step, i, outerStepId, errors);
325
+ }
326
+ }
327
+ // #2689 — statically-dead `{{ }}` expressions (unknown root, undeclared
328
+ // `steps.<id>` / `outputs.<name>`) are guaranteed run-time failures since
329
+ // #2643. Reject them here so `config push` reports them before anything is
330
+ // pushed, instead of after a deploy-and-run cycle.
331
+ //
332
+ // `knownKinds` carries the #998 skew posture into the lint: an old CLI must
333
+ // not judge a NEWER server's step kind, whose runner may bind template roots
334
+ // this copy of the lint has never heard of. The server-side check in
335
+ // `validateWorkflowSteps` scans every step and stays authoritative.
336
+ for (const finding of lintWorkflowStepTemplates(steps, {
337
+ knownKinds: KNOWN_KINDS,
338
+ })) {
339
+ errors.push({
340
+ stepIndex: finding.stepIndex,
341
+ stepId: finding.stepId,
342
+ field: "__template_expression__",
343
+ hint: `${finding.location}: ${finding.message}`,
344
+ });
345
+ }
346
+ return errors;
347
+ }
348
+ /**
349
+ * Validate a single step object's top-level keys against the allowlist and
350
+ * push any errors found onto `errors`. Used for both the top-level
351
+ * `steps[]` walk and the recursive `collect.step` walk.
352
+ *
353
+ * When `parentStepId` is set, the step being validated is the inner step
354
+ * of a `collect`. Errors carry the outer-step context so the rendered
355
+ * diagnostic can point operators at the right slot in the TOML.
356
+ */
357
+ function validateStepObject(step, stepIndex, parentStepId, errors) {
358
+ const stepId = typeof step.id === "string" ? step.id : null;
359
+ // #998: kind-membership branch. The CLI ships independently and may run
360
+ // against a NEWER server that registered a step kind the CLI's generated
361
+ // known-kind set doesn't have. For such an UNKNOWN kind we skip the
362
+ // per-field allowlist check (so a valid new-kind field is never falsely
363
+ // rejected — the recurring #685/#802/#971 failure) while STILL running the
364
+ // kind-agnostic misnested-header footgun detector below. For a KNOWN kind
365
+ // the full allowlist check applies as before. A missing/non-string `kind`
366
+ // is treated as known so the legacy strict check still catches obviously
367
+ // malformed steps (the runtime would reject a kindless step anyway).
368
+ const kind = typeof step.kind === "string" ? step.kind : null;
369
+ const isKnownKind = kind === null || KNOWN_KINDS.has(kind);
370
+ for (const key of Object.keys(step)) {
371
+ const value = step[key];
372
+ // Codex finding 1 (PR #762, 2026-05-15): self-id misnesting must be
373
+ // checked BEFORE the allowlist skip. When the step's `id` happens to
374
+ // match an allowlisted field name (e.g. `id = "query"`,
375
+ // `id = "request"`, `id = "input"`, `id = "output"`), TOML's
376
+ // `[steps.<id>.<sub-field>]` misnest produces a sub-table on the step
377
+ // keyed by the id — the same shape the validator was meant to catch.
378
+ // The allowlist would otherwise skip it as "expected per-kind field".
379
+ // Heuristic: when `step[step.id]` is a non-array table, this is
380
+ // (effectively always) the misnest pattern. Scalars are fine (the
381
+ // user really did mean to set the scalar field).
382
+ //
383
+ // Codex finding (PR #819, 2026-05-21): the heuristic over-fires for the
384
+ // `switch` step kind. A switch legitimately named `id = "default"` has a
385
+ // real `[steps.default]` fallback that parses as a non-array table at
386
+ // `step.default` — structurally identical to the misnest shape, but it's
387
+ // the field's *valid* form. (Likewise `id = "cases"`.) For these ids the
388
+ // footgun and the legitimate declaration are indistinguishable, so the
389
+ // heuristic must defer to the allowlist. Carve-out scope is narrow on
390
+ // purpose: only `kind === "switch"` with key `cases`/`default`. Every
391
+ // other (kind, id) collision — e.g. `id = "query"` on a database step —
392
+ // is still treated as the footgun, preserving finding 1's safety net.
393
+ const isSwitchFallbackField = step.kind === "switch" && (key === "cases" || key === "default");
394
+ const isSelfIdMisnest = stepId !== null &&
395
+ key === stepId &&
396
+ value !== null &&
397
+ typeof value === "object" &&
398
+ !Array.isArray(value) &&
399
+ !isSwitchFallbackField;
400
+ // Known kind → full allowlist check (an allowlisted field passes).
401
+ // Unknown kind → skip the per-field allowlist check entirely: only the
402
+ // structural footgun (self-id misnest) below can flag a field. The
403
+ // footgun check is kind-agnostic, so it fires on every step regardless.
404
+ if (!isSelfIdMisnest && (!isKnownKind || ALLOWLISTED_FIELDS.has(key)))
405
+ continue;
406
+ // Two failure modes are common enough to call out specifically in
407
+ // the hint:
408
+ //
409
+ // 1) `[steps.<id>.<field>]` under `[[steps]]` — TOML places the
410
+ // sub-table under `steps[N][<id>]`. We detect this when the
411
+ // unknown field name equals the step's own id (including the
412
+ // self-id-allowlist-collision case above). We use the first
413
+ // sub-key of the offending value (e.g. `request`) to build a
414
+ // concrete corrected-form example so the user sees exactly what
415
+ // to rewrite, not just an abstract `<field>`.
416
+ //
417
+ // 2) Any other unknown top-level field — covered by the generic hint.
418
+ let hint;
419
+ if (stepId !== null && key === stepId) {
420
+ const subKey = value && typeof value === "object" && !Array.isArray(value)
421
+ ? Object.keys(value)[0]
422
+ : null;
423
+ const exampleSub = subKey ?? "request";
424
+ hint =
425
+ `This is usually caused by writing [steps.${stepId}.${exampleSub}] instead of [steps.${exampleSub}]. ` +
426
+ `TOML can't address an array element by id — use [steps.${exampleSub}] (refers to the most recent step).`;
427
+ }
428
+ else {
429
+ hint =
430
+ `\`${key}\` is not a recognized step field. ` +
431
+ `If you meant to write a nested config block on this step, use [steps.${key}] (which refers to the most recent step) instead of [steps.<id>.${key}].`;
432
+ }
433
+ errors.push({
434
+ stepIndex,
435
+ stepId,
436
+ field: key,
437
+ hint,
438
+ parentStepId,
439
+ });
440
+ }
441
+ // #1252 — form-urlencoded body conflict. `[steps.request.form]` encodes an
442
+ // `application/x-www-form-urlencoded` body; it cannot coexist with a
443
+ // `request.body` or a raw/multipart `bodyMode`. The runtime rejects the same
444
+ // combination, but catching it at push time gives a clearer, earlier
445
+ // diagnostic. (`request.form` itself needs no allowlist entry — the validator
446
+ // only checks top-level step fields, and `request` is already allowlisted.)
447
+ if (step.kind === "integration.call" &&
448
+ step.request !== null &&
449
+ typeof step.request === "object" &&
450
+ !Array.isArray(step.request)) {
451
+ const req = step.request;
452
+ const hasForm = req.form !== undefined && req.form !== null;
453
+ if (hasForm) {
454
+ if (req.body !== undefined && req.body !== null) {
455
+ errors.push({
456
+ stepIndex,
457
+ stepId,
458
+ field: "request.form",
459
+ hint: "`request.form` (application/x-www-form-urlencoded) cannot be combined with `request.body`. " +
460
+ "Use one request body — either the JSON `body` or the `form` table.",
461
+ parentStepId,
462
+ });
463
+ }
464
+ const mode = step.bodyMode;
465
+ if (mode === "raw" || mode === "multipart") {
466
+ errors.push({
467
+ stepIndex,
468
+ stepId,
469
+ field: "request.form",
470
+ hint: `\`request.form\` (application/x-www-form-urlencoded) cannot be combined with bodyMode "${mode}". ` +
471
+ "Remove `form` or the `bodyMode`.",
472
+ parentStepId,
473
+ });
474
+ }
475
+ }
476
+ }
477
+ }
478
+ /**
479
+ * Render a multi-line diagnostic for a list of errors. Designed for the
480
+ * shape called out in the issue:
481
+ *
482
+ * Error in workflows/refresh.toml:
483
+ * steps[0] (id="refresh-each") has unknown field "refresh-each".
484
+ * This is usually caused by writing [steps.refresh-each.request] instead of [steps.request].
485
+ * TOML can't address an array element by id — use [steps.request] (refers to the most recent step).
486
+ *
487
+ * @param filePath The TOML file path (or display name) to include in the
488
+ * header.
489
+ * @param errors The error list from `validateWorkflowToml`.
490
+ * @returns A multi-line string ready to print to stderr.
491
+ */
492
+ export function formatWorkflowTomlErrors(filePath, errors) {
493
+ if (errors.length === 0)
494
+ return "";
495
+ const lines = [`Error in ${filePath}:`];
496
+ for (const err of errors) {
497
+ if (err.field === "__steps_shape__") {
498
+ lines.push(` ${err.hint}`);
499
+ continue;
500
+ }
501
+ if (err.field === "__step_shape__") {
502
+ lines.push(` steps[${err.stepIndex}] is malformed: ${err.hint}`);
503
+ continue;
504
+ }
505
+ // #2689 — a statically-dead `{{ }}` expression. The offending FIELD is
506
+ // fine; its contents are not, so the "unknown field" wording would be
507
+ // actively misleading. Render the step slot plus the lint's message, which
508
+ // already names the expression, the problem and the fix.
509
+ if (err.field === "__template_expression__") {
510
+ const idPart = err.stepId ? ` (id="${err.stepId}")` : "";
511
+ lines.push(` steps[${err.stepIndex}]${idPart}:`);
512
+ lines.push(` ${err.hint}`);
513
+ continue;
514
+ }
515
+ // #1447 — workflow-level error, not tied to a step. Render the bare hint
516
+ // (no `steps[N]` prefix) under the file header.
517
+ if (err.field === "__workflow_system_access_rule__" ||
518
+ err.field === "__workflow_removed_field__") {
519
+ lines.push(` ${err.hint}`);
520
+ continue;
521
+ }
522
+ // For errors inside a `collect` step's nested inner step (codex review,
523
+ // 2026-05-15), use a `steps[N].step` slot prefix so operators see that
524
+ // the offending field is on the inner step, not the outer collect.
525
+ // The outer step's id (if any) is also included in the prefix so the
526
+ // diagnostic can be cross-referenced against the parent's TOML header.
527
+ //
528
+ // #971: top-level errors carry `parentStepId: null` (set explicitly at the
529
+ // top-level `validateStepObject` call); only genuine collect-inner errors
530
+ // carry a real id (or `undefined` if a future caller omits it). Use a
531
+ // non-null check so BOTH `null` and `undefined` top-level errors render as
532
+ // a bare `steps[N]` without the `(inside collect step)` suffix. The prior
533
+ // `!== undefined` check treated `null` as inner (`null !== undefined` is
534
+ // `true`), mislabeling every top-level error as inside a collect step (a
535
+ // regression from PR #762).
536
+ const isInnerStep = err.parentStepId != null;
537
+ const slot = isInnerStep
538
+ ? `steps[${err.stepIndex}].step`
539
+ : `steps[${err.stepIndex}]`;
540
+ const idPart = err.stepId ? ` (id="${err.stepId}")` : "";
541
+ const parentPart = isInnerStep && err.parentStepId
542
+ ? ` (inside collect step id="${err.parentStepId}")`
543
+ : isInnerStep
544
+ ? ` (inside collect step)`
545
+ : "";
546
+ lines.push(` ${slot}${idPart}${parentPart} has unknown field "${err.field}".`);
547
+ lines.push(` ${err.hint}`);
548
+ }
549
+ return lines.join("\n");
550
+ }
551
+ /**
552
+ * #1614 — client-side mirror of the server's `validateWorkflowExpressions`
553
+ * (`src/workflows/definition-store.ts`) for named `expr.*` CEL guards. Returns
554
+ * structural errors so `config push` fails fast with the same class of diagnostic
555
+ * the server would 400 on:
556
+ * 1. every `expr.<name>` reference — in a definition body OR a step guard
557
+ * (`runIf` / `successWhen` / switch `when`) — names a DECLARED definition;
558
+ * 2. the definition reference graph is a DAG (no cycles);
559
+ * 3. each definition body is a non-empty string.
560
+ *
561
+ * The CLI has no CEL parser, so full CEL parse validation stays server-side
562
+ * (the authoritative check) — this mirror catches the common undeclared-name
563
+ * and cycle mistakes before a network round-trip, matching how the CLI does
564
+ * structural checks and the server does authoritative validation elsewhere.
565
+ */
566
+ /**
567
+ * #1614 — validate the RAW `[expr.cel]` table shape BEFORE
568
+ * `parseWorkflowExpressionsToml` filters it. That parser drops any entry whose
569
+ * body is not a string, so a mistyped `ready = true` would vanish and, with no
570
+ * references left to fail on, `config push` would succeed while omitting the whole
571
+ * expression table. Surface non-string / empty / wrong-typed bodies (and a
572
+ * non-table `cel`) as a hard CLI validation error instead. Mirrors the server's
573
+ * `validateRawExpressionsShape` (`src/workflows/definition-store.ts`).
574
+ *
575
+ * `tomlData.expr.cel` is the parsed `[expr.cel]` table.
576
+ */
577
+ export function validateWorkflowExpressionsRawToml(tomlData) {
578
+ const errors = [];
579
+ const cel = tomlData?.expr?.cel;
580
+ if (cel === undefined || cel === null)
581
+ return errors;
582
+ if (typeof cel !== "object" || Array.isArray(cel)) {
583
+ errors.push("[expr.cel] must be a table mapping each name to a CEL string");
584
+ return errors;
585
+ }
586
+ for (const [name, body] of Object.entries(cel)) {
587
+ if (typeof body !== "string" || !body.trim()) {
588
+ errors.push(`expr.cel.${name}: definition body must be a non-empty CEL string`);
589
+ }
590
+ }
591
+ return errors;
592
+ }
593
+ export function validateWorkflowExpressionsToml(steps, expressions) {
594
+ const errors = [];
595
+ const cel = expressions?.cel;
596
+ const declared = new Set(cel ? Object.keys(cel) : []);
597
+ const refsFromDef = new Map();
598
+ if (cel) {
599
+ for (const [name, body] of Object.entries(cel)) {
600
+ if (typeof body !== "string" || !body.trim()) {
601
+ errors.push(`expr.cel.${name}: definition body must be a non-empty CEL string`);
602
+ refsFromDef.set(name, new Set());
603
+ continue;
604
+ }
605
+ const refs = extractExprRefs(body);
606
+ refsFromDef.set(name, refs);
607
+ for (const ref of refs) {
608
+ if (!declared.has(ref)) {
609
+ errors.push(`expr.cel.${name} references undeclared expr.${ref}`);
610
+ }
611
+ }
612
+ }
613
+ }
614
+ if (Array.isArray(steps)) {
615
+ steps.forEach((step, index) => {
616
+ for (const guard of collectGuardExpressions(step)) {
617
+ for (const ref of extractExprRefs(guard.expr)) {
618
+ if (!declared.has(ref)) {
619
+ errors.push(`steps[${index}].${guard.field} references undeclared expr.${ref}`);
620
+ }
621
+ }
622
+ }
623
+ });
624
+ }
625
+ const cycle = findExprCycle(declared, refsFromDef);
626
+ if (cycle) {
627
+ errors.push(`expr.cel definitions form a cycle: ${cycle.join(" -> ")}`);
628
+ }
629
+ return errors;
630
+ }
631
+ function collectGuardExpressions(step) {
632
+ const out = [];
633
+ if (!step || typeof step !== "object")
634
+ return out;
635
+ if (typeof step.runIf === "string" && step.runIf.trim()) {
636
+ out.push({ field: "runIf", expr: step.runIf });
637
+ }
638
+ if (typeof step.successWhen === "string" && step.successWhen.trim()) {
639
+ out.push({ field: "successWhen", expr: step.successWhen });
640
+ }
641
+ if (Array.isArray(step.cases)) {
642
+ step.cases.forEach((c, ci) => {
643
+ if (c && typeof c.when === "string" && c.when.trim()) {
644
+ out.push({ field: `cases[${ci}].when`, expr: c.when });
645
+ }
646
+ });
647
+ }
648
+ return out;
649
+ }
650
+ /**
651
+ * Scan a CEL string for `expr.<name>` / `expr['name']` / `expr["name"]`
652
+ * references, skipping quoted string literals. Mirrors the server's
653
+ * `extractExprRefs`.
654
+ */
655
+ function extractExprRefs(expression) {
656
+ const refs = new Set();
657
+ if (!expression)
658
+ return refs;
659
+ const len = expression.length;
660
+ let i = 0;
661
+ // #1614 — match the server's `isIdentChar` exactly (includes `$`) so a
662
+ // `$`-containing expr name (`expr.a$b`) is not falsely flagged as an
663
+ // undeclared reference by the CLI mirror when the server would accept it.
664
+ const isIdent = (ch) => !!ch && /[A-Za-z0-9_$]/.test(ch);
665
+ const skipStr = (start) => {
666
+ const quote = expression[start];
667
+ let k = start + 1;
668
+ while (k < len) {
669
+ if (expression[k] === "\\") {
670
+ k += 2;
671
+ continue;
672
+ }
673
+ if (expression[k] === quote)
674
+ return k + 1;
675
+ k++;
676
+ }
677
+ return len;
678
+ };
679
+ while (i < len) {
680
+ const ch = expression[i];
681
+ if (ch === "'" || ch === '"') {
682
+ i = skipStr(i);
683
+ continue;
684
+ }
685
+ if (ch === "e" &&
686
+ expression.slice(i, i + 4) === "expr" &&
687
+ (i === 0 || !isIdent(expression[i - 1]))) {
688
+ let j = i + 4;
689
+ if (expression[j] === ".") {
690
+ j++;
691
+ const start = j;
692
+ while (j < len && isIdent(expression[j]))
693
+ j++;
694
+ if (j > start)
695
+ refs.add(expression.slice(start, j));
696
+ i = j;
697
+ continue;
698
+ }
699
+ if (expression[j] === "[") {
700
+ let k = j + 1;
701
+ while (k < len && expression[k] === " ")
702
+ k++;
703
+ const q = expression[k];
704
+ if (q === "'" || q === '"') {
705
+ const s = k + 1;
706
+ let e = s;
707
+ while (e < len && expression[e] !== q)
708
+ e++;
709
+ if (e < len) {
710
+ refs.add(expression.slice(s, e));
711
+ i = e + 1;
712
+ continue;
713
+ }
714
+ }
715
+ }
716
+ i = j;
717
+ continue;
718
+ }
719
+ i++;
720
+ }
721
+ return refs;
722
+ }
723
+ /** DFS cycle detection over the declared `expr.*` reference graph. */
724
+ function findExprCycle(declared, refs) {
725
+ const WHITE = 0;
726
+ const GRAY = 1;
727
+ const BLACK = 2;
728
+ const color = new Map();
729
+ for (const n of declared)
730
+ color.set(n, WHITE);
731
+ const stack = [];
732
+ let found = null;
733
+ const dfs = (n) => {
734
+ color.set(n, GRAY);
735
+ stack.push(n);
736
+ for (const m of refs.get(n) ?? []) {
737
+ if (!declared.has(m))
738
+ continue;
739
+ if (color.get(m) === GRAY) {
740
+ const idx = stack.indexOf(m);
741
+ found = stack.slice(idx).concat(m);
742
+ return true;
743
+ }
744
+ if (color.get(m) === WHITE && dfs(m))
745
+ return true;
746
+ }
747
+ stack.pop();
748
+ color.set(n, BLACK);
749
+ return false;
750
+ };
751
+ for (const n of declared) {
752
+ if (color.get(n) === WHITE && dfs(n))
753
+ break;
754
+ }
755
+ return found;
756
+ }
757
+ //# sourceMappingURL=workflow-toml-validator.js.map