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
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Background: the CLI built the create/update workflow payload in THREE
5
5
  * separate hand-enumerated literals — `workflows create --from-file`
6
- * (`cli/src/commands/workflows.ts`), the `sync push` create branch
7
- * (`cli/src/commands/sync.ts`), and the `sync push` update branch (the metadata
6
+ * (`cli/src/commands/workflows.ts`), the `config push` create branch
7
+ * (`cli/src/commands/sync.ts`), and the `config push` update branch (the metadata
8
8
  * PATCH in `cli/src/lib/workflow-apply.ts`). Because each site listed the
9
9
  * `[workflow]` fields by hand, they drifted apart: a field added to one path was
10
10
  * silently dropped by the others. `status` was the 4th field lost this way
@@ -27,19 +27,34 @@
27
27
  * Presence semantics, by mode:
28
28
  * - create: optional strings coalesce absent/empty → `undefined` (omit; the
29
29
  * server default applies). `capabilities` forwards the raw array (absent →
30
- * omit). Schemas omit when absent.
31
- * - update: optional strings distinguish explicit-clear from leave-unset via
32
- * `x !== undefined ? (x || null) : undefined`. `status` forwards the bare
33
- * value (matching the server's hasOwnProperty path). Schemas send `null`
34
- * when absent so a cleared schema round-trips.
35
- * - booleans (`requiresClientApply`, and `syncCallable` on create) are raw
36
- * pass-through so an explicit `false` is preserved and only a truly-absent
37
- * key drops.
38
- * - `syncCallable` is OMITTED in `mode: "update"`: the server re-validates
39
- * `syncCallable: true` against the CURRENTLY-active steps, so the update
40
- * path must send it as a deferred second PATCH after the new steps are live
41
- * (#807). `applyWorkflowBody` owns that second PATCH.
30
+ * omit). Schemas omit when absent. Booleans are raw pass-through so an
31
+ * explicit `false` is preserved and only a truly-absent key drops.
32
+ * - update: ALWAYS-SEND (#2743). The workflow TOML fully describes the
33
+ * workflow, so every update-mode field carries a definite value and
34
+ * `undefined` never appears: a defaulted scalar (`status`, the queue
35
+ * limits, `dequeueOrder`, `requiresClientApply`) sends its concrete model
36
+ * default when the file omits it, and a nullable field (`description`,
37
+ * `accessRule`, `runAs`, `capabilities`, the schemas, `lock`) sends `null`.
38
+ * Deleting a line from the file therefore CONVERGES the server rather than
39
+ * silently leaving the old value live (#1567's bug class). Optional strings
40
+ * keep their `"" null` coalescing, so an explicit clear and an omission
41
+ * land on the same wire value.
42
+ *
43
+ * Defaulted scalars deliberately travel as their default, not as `null`: a
44
+ * server predating #2743 coerces a queue-limit `null` to `0`, while an
45
+ * explicit default converges identically on both. The shared map lives in
46
+ * `workflow-defaults.ts` (the diff normalizer reads the same copy).
47
+ *
48
+ * Omit-preserve survives only as the SERVER's contract for other clients
49
+ * (web-admin): the PATCH still leaves an absent key alone.
50
+ * - `syncCallable` is OMITTED from the builder in `mode: "update"`: its
51
+ * ordering relative to the steps write is `applyWorkflowBody`'s to decide
52
+ * (#807 — enabling must validate against the NEW steps, so it is deferred
53
+ * to a second PATCH; disabling rides the first PATCH). See that module.
42
54
  */
55
+ import { writableFieldNames } from "./generated-config-surfaces.js";
56
+ import { WORKFLOW_TABLE } from "./config-surface.js";
57
+ import { WORKFLOW_MODEL_DEFAULTS } from "./workflow-defaults.js";
43
58
  /**
44
59
  * Parse a JSON schema field that TOML may present as a string OR (for an inline
45
60
  * table) as an already-parsed object. Kept here in `cli/src/lib` so the builder
@@ -75,31 +90,62 @@ export function parseWorkflowExpressionsToml(tomlData) {
75
90
  return Object.keys(out).length > 0 ? { cel: out } : undefined;
76
91
  }
77
92
  /**
78
- * The `[workflow]`-derived keys the builder emits, per mode. Exported so the
79
- * drift-guard unit test can assert the key set hasn't silently lost a field —
80
- * the recurring bug class this builder closes. `update` omits `syncCallable`
81
- * (deferred second PATCH, #807); everything else is shared.
93
+ * Fields the SERVER accepts on update but this BUILDER deliberately leaves to
94
+ * the caller. This is a sequencing invariant, not a statement about the server:
95
+ * `syncCallable: true` is re-validated against the CURRENTLY-active steps, so
96
+ * enabling it has to wait for a second PATCH once the new steps are live (#807
97
+ * — `applyWorkflowBody` owns the whole sequence, including the `false` case it
98
+ * puts in the FIRST PATCH). The definition correctly declares
99
+ * `writableOn: ["create", "update"]`; the exception lives here, where the
100
+ * ordering decision is.
82
101
  */
83
- export const WORKFLOW_PAYLOAD_FIELDS_CREATE = [
84
- "name",
85
- "description",
86
- "status",
87
- "accessRule",
88
- "runAs",
89
- "capabilities",
90
- "perUserMaxRunning",
91
- "perUserMaxQueued",
92
- "perAppMaxRunning",
93
- "perAppMaxQueued",
94
- "queueTtlSeconds",
95
- "dequeueOrder",
96
- "requiresClientApply",
97
- "inputSchema",
98
- "outputSchema",
99
- "lock",
100
- "syncCallable",
101
- ];
102
- export const WORKFLOW_PAYLOAD_FIELDS_UPDATE = WORKFLOW_PAYLOAD_FIELDS_CREATE.filter((f) => f !== "syncCallable");
102
+ const CREATE_ONLY_ON_THE_WIRE = new Set(["syncCallable"]);
103
+ /**
104
+ * The `[workflow]`-derived keys the builder emits, per mode — read from the
105
+ * vendored definition (#2644), not restated here. A field added to
106
+ * `src/config-surface/workflow.ts` is pushed with no edit to this file, which
107
+ * is what closes the recurring "CLI silently drops a new server field" bug.
108
+ */
109
+ export function workflowPayloadFields(mode) {
110
+ const fields = writableFieldNames(WORKFLOW_TABLE, mode);
111
+ return mode === "create"
112
+ ? fields
113
+ : fields.filter((f) => !CREATE_ONLY_ON_THE_WIRE.has(f));
114
+ }
115
+ /**
116
+ * Per-field value producers, keyed by the definition's field name. A field with
117
+ * no entry is a scalar passthrough: on create the TOML value is forwarded as-is
118
+ * (absent → `undefined`, which `JSON.stringify` drops so the server default
119
+ * applies); on update it converges (absent → the field's model default, or
120
+ * `null` when it has none). That is what makes a passthrough field authorable
121
+ * by editing the definition alone (#2644 criterion 1); the entries below are
122
+ * the fields whose value semantics are genuinely their own.
123
+ */
124
+ const PAYLOAD_VALUE = {
125
+ // accessRule / runAs / description — create coalesces absent/empty → omit;
126
+ // update coalesces both an explicit clear ("") and an omission to `null`,
127
+ // because the file is the whole truth (#2743). `value || null` also keeps a
128
+ // whitespace-only value out of the "set" state the server would trim to "".
129
+ accessRule: (value, create) => (create ? value || undefined : value || null),
130
+ runAs: (value, create) => (create ? value || undefined : value || null),
131
+ description: (value, create) => (create ? value : value || null),
132
+ // Schemas — parse a JSON string (or accept an inline table). Create omits
133
+ // when absent; update sends null so a cleared schema round-trips.
134
+ inputSchema: (value, create) => value ? safeJsonParse(value) : create ? undefined : null,
135
+ outputSchema: (value, create) => value ? safeJsonParse(value) : create ? undefined : null,
136
+ // #1972 — declarative run-scoped lock (`[workflow.lock]`, #1518 Phase 3).
137
+ // A TOML-owned nested-object field, mirroring the schemas above. Presence-
138
+ // keyed, not truthiness-keyed: forward the value whenever the KEY is present
139
+ // (`!== undefined`) — the server's create/PATCH accept an object OR a JSON
140
+ // string, so a present-but-malformed falsy value (`lock = false`/`0`) must
141
+ // be forwarded so the server surfaces its validation error, rather than
142
+ // being silently treated as absent (dropped on create, cleared on update).
143
+ // Absent on create → omit (server default: no lock); absent on update →
144
+ // null so removing `[workflow.lock]` clears the server-side lock
145
+ // (config-as-code). Before this the field was dropped from both sync paths,
146
+ // so a pull → push cycle silently lost the lock (#1972).
147
+ lock: (value, create) => value !== undefined ? value : create ? undefined : null,
148
+ };
103
149
  /**
104
150
  * Build the workflow payload's `[workflow]`-derived fields from a parsed TOML
105
151
  * `[workflow]` table. `workflow` is `tomlData.workflow` (already merged with any
@@ -109,79 +155,23 @@ export const WORKFLOW_PAYLOAD_FIELDS_UPDATE = WORKFLOW_PAYLOAD_FIELDS_CREATE.fil
109
155
  */
110
156
  export function buildWorkflowPayloadFromToml(workflow, { mode }) {
111
157
  const create = mode === "create";
112
- const payload = {
113
- name: workflow.name,
114
- description: workflow.description,
115
- // status create coalesces absent/empty → omit (server default `draft`
116
- // applies); update forwards the bare value so it round-trips and an
117
- // explicit "" surfaces the server's validation error rather than a silent
118
- // no-op (matches the pre-existing update path).
119
- status: create ? workflow.status || undefined : workflow.status,
120
- // accessRule / runAs — create coalesces absent/empty → omit; update
121
- // distinguishes explicit clear ("" → null) from leave-unset (absent →
122
- // undefined).
123
- accessRule: create
124
- ? workflow.accessRule || undefined
125
- : workflow.accessRule !== undefined
126
- ? workflow.accessRule || null
127
- : undefined,
128
- runAs: create
129
- ? workflow.runAs || undefined
130
- : workflow.runAs !== undefined
131
- ? workflow.runAs || null
132
- : undefined,
133
- // capabilities — create forwards the raw array (absent → omit); update
134
- // forwards presence-aware so an explicit array round-trips. (The server
135
- // update PATCH persist for capabilities is tracked separately in #1232; the
136
- // round-trip guard asserts capabilities on the create leg only.)
137
- capabilities: create
138
- ? workflow.capabilities
139
- : workflow.capabilities !== undefined
140
- ? workflow.capabilities
141
- : undefined,
142
- // Queue limits — raw numeric pass-through both modes (absent → omit).
143
- perUserMaxRunning: workflow.perUserMaxRunning,
144
- perUserMaxQueued: workflow.perUserMaxQueued,
145
- perAppMaxRunning: workflow.perAppMaxRunning,
146
- perAppMaxQueued: workflow.perAppMaxQueued,
147
- queueTtlSeconds: workflow.queueTtlSeconds,
148
- dequeueOrder: workflow.dequeueOrder,
149
- // requiresClientApply — raw boolean pass-through so an explicit `false` is
150
- // preserved and only a truly-absent key drops (server default applies).
151
- requiresClientApply: workflow.requiresClientApply,
152
- // Schemas — parse a JSON string (or accept an inline table). Create omits
153
- // when absent; update sends null so a cleared schema round-trips.
154
- inputSchema: workflow.inputSchema
155
- ? safeJsonParse(workflow.inputSchema)
156
- : create
157
- ? undefined
158
- : null,
159
- outputSchema: workflow.outputSchema
160
- ? safeJsonParse(workflow.outputSchema)
161
- : create
162
- ? undefined
163
- : null,
164
- // #1972 — declarative run-scoped lock (`[workflow.lock]`, #1518 Phase 3).
165
- // A TOML-owned nested-object field, mirroring the schemas above. Presence-
166
- // keyed, not truthiness-keyed: forward the value whenever the KEY is present
167
- // (`!== undefined`) — the server's create/PATCH accept an object OR a JSON
168
- // string, so a present-but-malformed falsy value (`lock = false`/`0`) must
169
- // be forwarded so the server surfaces its validation error, rather than
170
- // being silently treated as absent (dropped on create, cleared on update).
171
- // Absent on create → omit (server default: no lock); absent on update →
172
- // null so removing `[workflow.lock]` clears the server-side lock
173
- // (config-as-code). Before this the field was dropped from both sync paths,
174
- // so a pull → push cycle silently lost the lock (#1972).
175
- lock: workflow.lock !== undefined
176
- ? workflow.lock
158
+ const payload = {};
159
+ for (const field of workflowPayloadFields(mode)) {
160
+ const descriptor = WORKFLOW_TABLE.fields.find((f) => f.field === field);
161
+ const tomlKey = descriptor?.tomlKey ?? field;
162
+ const produce = PAYLOAD_VALUE[field];
163
+ const raw = workflow[tomlKey];
164
+ payload[field] = produce
165
+ ? produce(raw, create, workflow)
177
166
  : create
178
- ? undefined
179
- : null,
180
- };
181
- // syncCallable — create includes it (raw boolean pass-through); update omits
182
- // it (deferred second PATCH, #807 see module doc).
183
- if (create) {
184
- payload.syncCallable = workflow.syncCallable;
167
+ ? // Scalar passthrough on create: queue limits, dequeueOrder, name,
168
+ // capabilities, and the boolean flags — raw so an explicit `false`
169
+ // or `0` survives and only a truly-absent key drops.
170
+ raw
171
+ : // Update converges (#2743): a field the file omits sends its concrete
172
+ // model default, or `null` when it has none (`name`, `capabilities`).
173
+ // `??` (not `||`) so an explicit `false` / `0` still wins.
174
+ (raw ?? WORKFLOW_MODEL_DEFAULTS[field] ?? null);
185
175
  }
186
176
  return payload;
187
177
  }
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-payload.js","sourceRoot":"","sources":["../../../src/lib/workflow-payload.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow-payload.js","sourceRoot":"","sources":["../../../src/lib/workflow-payload.ts"],"names":[],"mappings":"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"}
@@ -57,6 +57,9 @@ export declare const KNOWN_KINDS_FOR_DRIFT_GUARD: ReadonlySet<string>;
57
57
  * - `__workflow_system_access_rule__`: `[workflow] runAs = "system"` with a
58
58
  * non-empty `accessRule` — dead config the server rejects (#1447/#1258).
59
59
  * A workflow-level error (not tied to a step): `stepIndex: -1, stepId: null`.
60
+ * - `__template_expression__`: a `{{ }}` expression that can never resolve
61
+ * (#2689). The field itself is valid — the `hint` carries the expression's
62
+ * location and the lint's message.
60
63
  * `hint` is a short, user-facing explanation (used by
61
64
  * `formatWorkflowTomlErrors` to render the multi-line diagnostic).
62
65
  * `parentStepId` is set when this error came from a `collect` step's
@@ -82,7 +85,7 @@ export type WorkflowTomlError = {
82
85
  * can only be started by the system and never evaluates its accessRule, so any
83
86
  * non-empty rule is inert. The server rejects this at save time (#1258,
84
87
  * `src/workflows/definition-store.ts:271-280`); catching it locally keeps
85
- * `sync push` all-or-nothing instead of failing mid-push and leaving partial
88
+ * `config push` all-or-nothing instead of failing mid-push and leaving partial
86
89
  * server state (#1418 drift).
87
90
  *
88
91
  * Mirrors the server predicate byte-for-byte: returns the sentinel error only
@@ -95,6 +98,21 @@ export type WorkflowTomlError = {
95
98
  * object (`tomlData.workflow || tomlData`). Non-object inputs return `null`.
96
99
  */
97
100
  export declare function validateWorkflowIdentity(workflow: any): WorkflowTomlError | null;
101
+ /**
102
+ * #2643 — `templateMissingMarker` was removed from the platform. A workflow
103
+ * TOML that still sets it is rejected here, before the push, with the same
104
+ * sentence the server returns, rather than being silently dropped.
105
+ */
106
+ export declare const REMOVED_TEMPLATE_MISSING_MARKER_MESSAGE: string;
107
+ /**
108
+ * Non-blocking notes for a workflow TOML — things worth saying on a push that
109
+ * are not errors.
110
+ *
111
+ * #2643: `strict` / `strictParams` are accepted and ignored, because the
112
+ * failure they used to opt into now applies to every workflow. A definition
113
+ * that sets them keeps working unchanged, so this is a note, not an error.
114
+ */
115
+ export declare function collectWorkflowTomlNotes(tomlData: any): string[];
98
116
  /** The runAs / accessRule pair the identity lint reads. */
99
117
  export interface WorkflowIdentityFields {
100
118
  runAs?: unknown;
@@ -105,19 +123,22 @@ export interface WorkflowIdentityFields {
105
123
  * identity that an `update --from-file` push will leave on the server — the
106
124
  * merge of the persisted record with the incoming file/flags.
107
125
  *
108
- * `applyWorkflowBody` omits undefined fields, so the server retains whichever
109
- * side of the runAs/accessRule pair the incoming payload doesn't set. Linting
110
- * the incoming payload alone therefore misses the case where the OTHER side is
111
- * already `system` / a stored rule: an existing `runAs="system"` workflow plus
112
- * a file adding only an `accessRule`, or a file flipping a workflow with a
113
- * stored rule to `runAs="system"`. Both pass a payload-only lint and are then
114
- * rejected by the server's PATCH. Merging the two before `validateWorkflowIdentity`
115
- * catches them locally at zero extra cost — the persisted record is already
116
- * fetched at the call site.
117
- *
118
- * Presence semantics mirror the update payload builder: a field PRESENT in
119
- * `incoming` (including an empty-string clear) overrides the stored value; an
120
- * ABSENT field (undefined) falls back to what the server keeps.
126
+ * The merge exists for a caller whose push OMITS one side of the
127
+ * runAs/accessRule pair and lets the server retain it. Linting the incoming
128
+ * payload alone misses the case where the OTHER side is already `system` / a
129
+ * stored rule: an existing `runAs="system"` workflow plus a file adding only an
130
+ * `accessRule`, or a file flipping a workflow with a stored rule to
131
+ * `runAs="system"`. Both pass a payload-only lint and are then rejected by the
132
+ * server's PATCH. Merging the two before `validateWorkflowIdentity` catches
133
+ * them locally at zero extra cost — the persisted record is already fetched at
134
+ * the call site.
135
+ *
136
+ * NOT `config push`, since #2743: its update is always-send, so the file alone IS
137
+ * the effective config (an omitted `accessRule` clears the stored rule rather
138
+ * than inheriting it) and its push-time lint of the file is exact. The merge
139
+ * semantics below are unchanged for any caller that does omit fields: a field
140
+ * PRESENT in `incoming` (including an empty-string clear) overrides the stored
141
+ * value; an ABSENT field (undefined) falls back to what the server keeps.
121
142
  */
122
143
  export declare function effectiveWorkflowIdentity(existing: WorkflowIdentityFields | null | undefined, incoming: WorkflowIdentityFields | null | undefined): WorkflowIdentityFields;
123
144
  /**
@@ -152,7 +173,7 @@ export declare function formatWorkflowTomlErrors(filePath: string, errors: Workf
152
173
  /**
153
174
  * #1614 — client-side mirror of the server's `validateWorkflowExpressions`
154
175
  * (`src/workflows/definition-store.ts`) for named `expr.*` CEL guards. Returns
155
- * structural errors so `sync push` fails fast with the same class of diagnostic
176
+ * structural errors so `config push` fails fast with the same class of diagnostic
156
177
  * the server would 400 on:
157
178
  * 1. every `expr.<name>` reference — in a definition body OR a step guard
158
179
  * (`runIf` / `successWhen` / switch `when`) — names a DECLARED definition;
@@ -168,7 +189,7 @@ export declare function formatWorkflowTomlErrors(filePath: string, errors: Workf
168
189
  * #1614 — validate the RAW `[expr.cel]` table shape BEFORE
169
190
  * `parseWorkflowExpressionsToml` filters it. That parser drops any entry whose
170
191
  * body is not a string, so a mistyped `ready = true` would vanish and, with no
171
- * references left to fail on, `sync push` would succeed while omitting the whole
192
+ * references left to fail on, `config push` would succeed while omitting the whole
172
193
  * expression table. Surface non-string / empty / wrong-typed bodies (and a
173
194
  * non-table `cel`) as a hard CLI validation error instead. Mirrors the server's
174
195
  * `validateRawExpressionsShape` (`src/workflows/definition-store.ts`).
@@ -31,6 +31,11 @@
31
31
  * case. Regenerate with `node cli/scripts/gen-allowlist.mjs`.
32
32
  */
33
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";
34
39
  /**
35
40
  * Universal-and-consumed allowlist of top-level fields permitted on a step
36
41
  * (known kinds). Generated from the runners; see header.
@@ -66,7 +71,7 @@ export const KNOWN_KINDS_FOR_DRIFT_GUARD = KNOWN_KINDS;
66
71
  * can only be started by the system and never evaluates its accessRule, so any
67
72
  * non-empty rule is inert. The server rejects this at save time (#1258,
68
73
  * `src/workflows/definition-store.ts:271-280`); catching it locally keeps
69
- * `sync push` all-or-nothing instead of failing mid-push and leaving partial
74
+ * `config push` all-or-nothing instead of failing mid-push and leaving partial
70
75
  * server state (#1418 drift).
71
76
  *
72
77
  * Mirrors the server predicate byte-for-byte: returns the sentinel error only
@@ -99,24 +104,100 @@ export function validateWorkflowIdentity(workflow) {
99
104
  }
100
105
  return null;
101
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
+ }
102
180
  /**
103
181
  * #1447 (maintainer decision, 2026-07-21): compute the EFFECTIVE workflow
104
182
  * identity that an `update --from-file` push will leave on the server — the
105
183
  * merge of the persisted record with the incoming file/flags.
106
184
  *
107
- * `applyWorkflowBody` omits undefined fields, so the server retains whichever
108
- * side of the runAs/accessRule pair the incoming payload doesn't set. Linting
109
- * the incoming payload alone therefore misses the case where the OTHER side is
110
- * already `system` / a stored rule: an existing `runAs="system"` workflow plus
111
- * a file adding only an `accessRule`, or a file flipping a workflow with a
112
- * stored rule to `runAs="system"`. Both pass a payload-only lint and are then
113
- * rejected by the server's PATCH. Merging the two before `validateWorkflowIdentity`
114
- * catches them locally at zero extra cost — the persisted record is already
115
- * fetched at the call site.
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.
116
194
  *
117
- * Presence semantics mirror the update payload builder: a field PRESENT in
118
- * `incoming` (including an empty-string clear) overrides the stored value; an
119
- * ABSENT field (undefined) falls back to what the server keeps.
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.
120
201
  */
121
202
  export function effectiveWorkflowIdentity(existing, incoming) {
122
203
  const ex = existing ?? {};
@@ -166,6 +247,20 @@ export function validateWorkflowToml(tomlData, opts) {
166
247
  if (identityError)
167
248
  errors.push(identityError);
168
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);
169
264
  const steps = tomlData.steps;
170
265
  // No steps section at all → nothing to validate. This is fine for
171
266
  // partial TOML files (some commands accept a metadata-only file).
@@ -229,6 +324,25 @@ export function validateWorkflowToml(tomlData, opts) {
229
324
  validateStepObject(step.step, i, outerStepId, errors);
230
325
  }
231
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
+ }
232
346
  return errors;
233
347
  }
234
348
  /**
@@ -388,9 +502,20 @@ export function formatWorkflowTomlErrors(filePath, errors) {
388
502
  lines.push(` steps[${err.stepIndex}] is malformed: ${err.hint}`);
389
503
  continue;
390
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
+ }
391
515
  // #1447 — workflow-level error, not tied to a step. Render the bare hint
392
516
  // (no `steps[N]` prefix) under the file header.
393
- if (err.field === "__workflow_system_access_rule__") {
517
+ if (err.field === "__workflow_system_access_rule__" ||
518
+ err.field === "__workflow_removed_field__") {
394
519
  lines.push(` ${err.hint}`);
395
520
  continue;
396
521
  }
@@ -426,7 +551,7 @@ export function formatWorkflowTomlErrors(filePath, errors) {
426
551
  /**
427
552
  * #1614 — client-side mirror of the server's `validateWorkflowExpressions`
428
553
  * (`src/workflows/definition-store.ts`) for named `expr.*` CEL guards. Returns
429
- * structural errors so `sync push` fails fast with the same class of diagnostic
554
+ * structural errors so `config push` fails fast with the same class of diagnostic
430
555
  * the server would 400 on:
431
556
  * 1. every `expr.<name>` reference — in a definition body OR a step guard
432
557
  * (`runIf` / `successWhen` / switch `when`) — names a DECLARED definition;
@@ -442,7 +567,7 @@ export function formatWorkflowTomlErrors(filePath, errors) {
442
567
  * #1614 — validate the RAW `[expr.cel]` table shape BEFORE
443
568
  * `parseWorkflowExpressionsToml` filters it. That parser drops any entry whose
444
569
  * body is not a string, so a mistyped `ready = true` would vanish and, with no
445
- * references left to fail on, `sync push` would succeed while omitting the whole
570
+ * references left to fail on, `config push` would succeed while omitting the whole
446
571
  * expression table. Surface non-string / empty / wrong-typed bodies (and a
447
572
  * non-table `cel`) as a hard CLI validation error instead. Mirrors the server's
448
573
  * `validateRawExpressionsShape` (`src/workflows/definition-store.ts`).