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.
- package/README.md +125 -69
- package/assets/skill/skills/primitive-platform/SKILL.md +336 -37
- package/dist/bin/primitive.js +25 -14
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/analytics.js +36 -16
- package/dist/src/commands/analytics.js.map +1 -1
- package/dist/src/commands/apps.js +52 -188
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/blob-buckets.js +13 -153
- package/dist/src/commands/blob-buckets.js.map +1 -1
- package/dist/src/commands/collection-type-configs.js +14 -100
- package/dist/src/commands/collection-type-configs.js.map +1 -1
- package/dist/src/commands/collections.js +47 -8
- package/dist/src/commands/collections.js.map +1 -1
- package/dist/src/commands/config.d.ts +46 -0
- package/dist/src/commands/config.js +479 -0
- package/dist/src/commands/config.js.map +1 -0
- package/dist/src/commands/connections.js +12 -7
- package/dist/src/commands/connections.js.map +1 -1
- package/dist/src/commands/cron-triggers.js +84 -176
- package/dist/src/commands/cron-triggers.js.map +1 -1
- package/dist/src/commands/database-type-configs.d.ts +2 -0
- package/dist/src/commands/database-type-configs.js +171 -0
- package/dist/src/commands/database-type-configs.js.map +1 -0
- package/dist/src/commands/database-types.js +4 -4
- package/dist/src/commands/database-types.js.map +1 -1
- package/dist/src/commands/databases.d.ts +63 -0
- package/dist/src/commands/databases.js +649 -87
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.js +869 -12
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/email-templates.js +21 -128
- package/dist/src/commands/email-templates.js.map +1 -1
- package/dist/src/commands/env.d.ts +12 -1
- package/dist/src/commands/env.js +115 -26
- package/dist/src/commands/env.js.map +1 -1
- package/dist/src/commands/feature-flags.d.ts +14 -0
- package/dist/src/commands/feature-flags.js +116 -0
- package/dist/src/commands/feature-flags.js.map +1 -0
- package/dist/src/commands/group-type-configs.js +14 -109
- package/dist/src/commands/group-type-configs.js.map +1 -1
- package/dist/src/commands/init.d.ts +24 -1
- package/dist/src/commands/init.js +1194 -279
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/integrations.js +166 -435
- package/dist/src/commands/integrations.js.map +1 -1
- package/dist/src/commands/metadata-category-configs.d.ts +12 -0
- package/dist/src/commands/metadata-category-configs.js +112 -0
- package/dist/src/commands/metadata-category-configs.js.map +1 -0
- package/dist/src/commands/metadata.js +33 -141
- package/dist/src/commands/metadata.js.map +1 -1
- package/dist/src/commands/prompts.js +206 -563
- package/dist/src/commands/prompts.js.map +1 -1
- package/dist/src/commands/rule-sets.d.ts +1 -1
- package/dist/src/commands/rule-sets.js +16 -132
- package/dist/src/commands/rule-sets.js.map +1 -1
- package/dist/src/commands/scripts.d.ts +10 -0
- package/dist/src/commands/scripts.js +203 -241
- package/dist/src/commands/scripts.js.map +1 -1
- package/dist/src/commands/sessions.js +17 -5
- package/dist/src/commands/sessions.js.map +1 -1
- package/dist/src/commands/sync-app-settings.d.ts +113 -70
- package/dist/src/commands/sync-app-settings.js +193 -242
- package/dist/src/commands/sync-app-settings.js.map +1 -1
- package/dist/src/commands/sync.d.ts +1904 -51
- package/dist/src/commands/sync.js +9468 -1790
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/tokens.js +8 -2
- package/dist/src/commands/tokens.js.map +1 -1
- package/dist/src/commands/users.js +92 -1
- package/dist/src/commands/users.js.map +1 -1
- package/dist/src/commands/vars.js +44 -58
- package/dist/src/commands/vars.js.map +1 -1
- package/dist/src/commands/webhooks.js +318 -156
- package/dist/src/commands/webhooks.js.map +1 -1
- package/dist/src/commands/workflows.d.ts +49 -12
- package/dist/src/commands/workflows.js +652 -1086
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/access-rule-display.d.ts +21 -0
- package/dist/src/lib/access-rule-display.js +34 -0
- package/dist/src/lib/access-rule-display.js.map +1 -0
- package/dist/src/lib/api-client.d.ts +541 -61
- package/dist/src/lib/api-client.js +559 -102
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/app-settings-descriptor.d.ts +180 -25
- package/dist/src/lib/app-settings-descriptor.js +403 -82
- package/dist/src/lib/app-settings-descriptor.js.map +1 -1
- package/dist/src/lib/canonical-json.d.ts +12 -0
- package/dist/src/lib/canonical-json.js +35 -0
- package/dist/src/lib/canonical-json.js.map +1 -0
- package/dist/src/lib/cli-manifest.d.ts +8 -0
- package/dist/src/lib/cli-manifest.js +1 -0
- package/dist/src/lib/cli-manifest.js.map +1 -1
- package/dist/src/lib/codegen-shared/generatedFiles.d.ts +6 -2
- package/dist/src/lib/codegen-shared/generatedFiles.js +9 -2
- package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +6 -6
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +8 -8
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -1
- package/dist/src/lib/config-object-descriptor.d.ts +127 -0
- package/dist/src/lib/config-object-descriptor.js +658 -0
- package/dist/src/lib/config-object-descriptor.js.map +1 -0
- package/dist/src/lib/config-payload.d.ts +85 -0
- package/dist/src/lib/config-payload.js +116 -0
- package/dist/src/lib/config-payload.js.map +1 -0
- package/dist/src/lib/config-surface.d.ts +130 -0
- package/dist/src/lib/config-surface.js +300 -0
- package/dist/src/lib/config-surface.js.map +1 -0
- package/dist/src/lib/credentials-store.d.ts +10 -0
- package/dist/src/lib/credentials-store.js +23 -0
- package/dist/src/lib/credentials-store.js.map +1 -1
- package/dist/src/lib/data-input.d.ts +23 -0
- package/dist/src/lib/data-input.js +50 -0
- package/dist/src/lib/data-input.js.map +1 -0
- package/dist/src/lib/db-codegen/dbTemplates.js +1 -1
- package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTypeIR.d.ts +1 -1
- package/dist/src/lib/env-resolver-core.d.ts +187 -0
- package/dist/src/lib/env-resolver-core.js +325 -0
- package/dist/src/lib/env-resolver-core.js.map +1 -0
- package/dist/src/lib/env-resolver.d.ts +28 -6
- package/dist/src/lib/env-resolver.js +44 -32
- package/dist/src/lib/env-resolver.js.map +1 -1
- package/dist/src/lib/generated-allowlist.js +12 -0
- package/dist/src/lib/generated-allowlist.js.map +1 -1
- package/dist/src/lib/generated-config-surfaces.d.ts +682 -0
- package/dist/src/lib/generated-config-surfaces.js +4058 -0
- package/dist/src/lib/generated-config-surfaces.js.map +1 -0
- package/dist/src/lib/generated-template-lint.d.ts +212 -0
- package/dist/src/lib/generated-template-lint.js +624 -0
- package/dist/src/lib/generated-template-lint.js.map +1 -0
- package/dist/src/lib/init-adopt.d.ts +16 -0
- package/dist/src/lib/init-adopt.js +34 -0
- package/dist/src/lib/init-adopt.js.map +1 -0
- package/dist/src/lib/init-assets.d.ts +39 -0
- package/dist/src/lib/init-assets.js +97 -0
- package/dist/src/lib/init-assets.js.map +1 -0
- package/dist/src/lib/init-client-platforms.d.ts +14 -0
- package/dist/src/lib/init-client-platforms.js +71 -0
- package/dist/src/lib/init-client-platforms.js.map +1 -0
- package/dist/src/lib/init-config.d.ts +44 -5
- package/dist/src/lib/init-config.js +80 -7
- package/dist/src/lib/init-config.js.map +1 -1
- package/dist/src/lib/init-email-redirect-uris.d.ts +37 -0
- package/dist/src/lib/init-email-redirect-uris.js +46 -0
- package/dist/src/lib/init-email-redirect-uris.js.map +1 -0
- package/dist/src/lib/init-ios-links.d.ts +90 -0
- package/dist/src/lib/init-ios-links.js +218 -0
- package/dist/src/lib/init-ios-links.js.map +1 -0
- package/dist/src/lib/init-plan.d.ts +80 -0
- package/dist/src/lib/init-plan.js +95 -0
- package/dist/src/lib/init-plan.js.map +1 -0
- package/dist/src/lib/init-production-env.d.ts +48 -0
- package/dist/src/lib/init-production-env.js +59 -0
- package/dist/src/lib/init-production-env.js.map +1 -0
- package/dist/src/lib/init-schema.d.ts +74 -0
- package/dist/src/lib/init-schema.js +358 -0
- package/dist/src/lib/init-schema.js.map +1 -0
- package/dist/src/lib/init-xcode.d.ts +33 -0
- package/dist/src/lib/init-xcode.js +114 -0
- package/dist/src/lib/init-xcode.js.map +1 -0
- package/dist/src/lib/integration-request-config.d.ts +30 -0
- package/dist/src/lib/integration-request-config.js +145 -0
- package/dist/src/lib/integration-request-config.js.map +1 -0
- package/dist/src/lib/integration-selector.d.ts +42 -0
- package/dist/src/lib/integration-selector.js +46 -0
- package/dist/src/lib/integration-selector.js.map +1 -0
- package/dist/src/lib/local-state.d.ts +55 -0
- package/dist/src/lib/local-state.js +167 -0
- package/dist/src/lib/local-state.js.map +1 -0
- package/dist/src/lib/local-test-cases.d.ts +63 -0
- package/dist/src/lib/local-test-cases.js +135 -0
- package/dist/src/lib/local-test-cases.js.map +1 -0
- package/dist/src/lib/log-inspection.d.ts +568 -0
- package/dist/src/lib/log-inspection.js +639 -0
- package/dist/src/lib/log-inspection.js.map +1 -0
- package/dist/src/lib/migration-nag.d.ts +2 -2
- package/dist/src/lib/migration-nag.js +3 -3
- package/dist/src/lib/object-status-filter.d.ts +22 -0
- package/dist/src/lib/object-status-filter.js +45 -0
- package/dist/src/lib/object-status-filter.js.map +1 -0
- package/dist/src/lib/output.d.ts +24 -1
- package/dist/src/lib/output.js +42 -1
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/package-manager.d.ts +140 -0
- package/dist/src/lib/package-manager.js +305 -0
- package/dist/src/lib/package-manager.js.map +1 -0
- package/dist/src/lib/paginate.d.ts +50 -0
- package/dist/src/lib/paginate.js +53 -0
- package/dist/src/lib/paginate.js.map +1 -1
- package/dist/src/lib/platform-owned.d.ts +29 -3
- package/dist/src/lib/platform-owned.js +42 -3
- package/dist/src/lib/platform-owned.js.map +1 -1
- package/dist/src/lib/project-config.d.ts +8 -0
- package/dist/src/lib/project-config.js +30 -5
- package/dist/src/lib/project-config.js.map +1 -1
- package/dist/src/lib/query-operators.d.ts +1 -1
- package/dist/src/lib/query-operators.js +1 -1
- package/dist/src/lib/record-filter.d.ts +18 -0
- package/dist/src/lib/record-filter.js +55 -0
- package/dist/src/lib/record-filter.js.map +1 -0
- package/dist/src/lib/resolve-init-dev-port.d.ts +56 -0
- package/dist/src/lib/resolve-init-dev-port.js +55 -0
- package/dist/src/lib/resolve-init-dev-port.js.map +1 -0
- package/dist/src/lib/resolve-init-server.d.ts +64 -0
- package/dist/src/lib/resolve-init-server.js +77 -0
- package/dist/src/lib/resolve-init-server.js.map +1 -0
- package/dist/src/lib/resolve-platform.d.ts +43 -14
- package/dist/src/lib/resolve-platform.js +74 -12
- package/dist/src/lib/resolve-platform.js.map +1 -1
- package/dist/src/lib/run-status.d.ts +19 -0
- package/dist/src/lib/run-status.generated.d.ts +39 -0
- package/dist/src/lib/run-status.generated.js +66 -0
- package/dist/src/lib/run-status.generated.js.map +1 -0
- package/dist/src/lib/run-status.js +19 -0
- package/dist/src/lib/run-status.js.map +1 -0
- package/dist/src/lib/server-text-normalization.d.ts +51 -0
- package/dist/src/lib/server-text-normalization.js +90 -0
- package/dist/src/lib/server-text-normalization.js.map +1 -0
- package/dist/src/lib/server-url.d.ts +22 -0
- package/dist/src/lib/server-url.js +33 -0
- package/dist/src/lib/server-url.js.map +1 -0
- package/dist/src/lib/signing-secret-status.d.ts +81 -0
- package/dist/src/lib/signing-secret-status.js +116 -0
- package/dist/src/lib/signing-secret-status.js.map +1 -0
- package/dist/src/lib/skill-installer.js +6 -3
- package/dist/src/lib/skill-installer.js.map +1 -1
- package/dist/src/lib/snapshots.d.ts +2 -2
- package/dist/src/lib/snapshots.js +2 -2
- package/dist/src/lib/swift-codegen/dbGenerator.d.ts +15 -2
- package/dist/src/lib/swift-codegen/dbGenerator.js +250 -18
- package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -1
- package/dist/src/lib/swift-codegen/generator.d.ts +11 -2
- package/dist/src/lib/swift-codegen/generator.js +181 -7
- package/dist/src/lib/swift-codegen/generator.js.map +1 -1
- package/dist/src/lib/swift-codegen/siblingSymbols.d.ts +7 -3
- package/dist/src/lib/swift-codegen/siblingSymbols.js +4 -1
- package/dist/src/lib/swift-codegen/siblingSymbols.js.map +1 -1
- package/dist/src/lib/sync-dir-selector.d.ts +21 -0
- package/dist/src/lib/sync-dir-selector.js +30 -0
- package/dist/src/lib/sync-dir-selector.js.map +1 -0
- package/dist/src/lib/sync-paths.d.ts +39 -0
- package/dist/src/lib/sync-paths.js +70 -2
- package/dist/src/lib/sync-paths.js.map +1 -1
- package/dist/src/lib/sync-resource-types.d.ts +138 -31
- package/dist/src/lib/sync-resource-types.js +241 -47
- package/dist/src/lib/sync-resource-types.js.map +1 -1
- package/dist/src/lib/sync-selectors.d.ts +95 -0
- package/dist/src/lib/sync-selectors.js +228 -0
- package/dist/src/lib/sync-selectors.js.map +1 -0
- package/dist/src/lib/template.d.ts +62 -4
- package/dist/src/lib/template.js +147 -39
- package/dist/src/lib/template.js.map +1 -1
- package/dist/src/lib/test-case-file-names.d.ts +40 -0
- package/dist/src/lib/test-case-file-names.js +91 -0
- package/dist/src/lib/test-case-file-names.js.map +1 -0
- package/dist/src/lib/test-case-keys.d.ts +29 -0
- package/dist/src/lib/test-case-keys.js +55 -0
- package/dist/src/lib/test-case-keys.js.map +1 -0
- package/dist/src/lib/test-case-variables.d.ts +15 -0
- package/dist/src/lib/test-case-variables.js +29 -0
- package/dist/src/lib/test-case-variables.js.map +1 -0
- package/dist/src/lib/toml-database-config.d.ts +4 -4
- package/dist/src/lib/toml-database-config.js +27 -34
- package/dist/src/lib/toml-database-config.js.map +1 -1
- package/dist/src/lib/toml-metadata-config.d.ts +9 -5
- package/dist/src/lib/toml-metadata-config.js +40 -45
- package/dist/src/lib/toml-metadata-config.js.map +1 -1
- package/dist/src/lib/toml-native-form.d.ts +1 -1
- package/dist/src/lib/toml-native-form.js +1 -1
- package/dist/src/lib/toml-params-validator.d.ts +1 -1
- package/dist/src/lib/toml-params-validator.js +1 -1
- package/dist/src/lib/toml-scalar-edit.d.ts +43 -0
- package/dist/src/lib/toml-scalar-edit.js +283 -0
- package/dist/src/lib/toml-scalar-edit.js.map +1 -0
- package/dist/src/lib/user-selector.d.ts +24 -0
- package/dist/src/lib/user-selector.js +33 -0
- package/dist/src/lib/user-selector.js.map +1 -0
- package/dist/src/lib/version-check.d.ts +25 -0
- package/dist/src/lib/version-check.js +77 -8
- package/dist/src/lib/version-check.js.map +1 -1
- package/dist/src/lib/watch.d.ts +121 -0
- package/dist/src/lib/watch.js +169 -0
- package/dist/src/lib/watch.js.map +1 -0
- package/dist/src/lib/web-url.d.ts +40 -0
- package/dist/src/lib/web-url.js +76 -0
- package/dist/src/lib/web-url.js.map +1 -0
- package/dist/src/lib/workflow-apply.d.ts +69 -45
- package/dist/src/lib/workflow-apply.js +99 -72
- package/dist/src/lib/workflow-apply.js.map +1 -1
- package/dist/src/lib/workflow-codegen/generator.js +4 -4
- package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
- package/dist/src/lib/workflow-codegen/invokerIR.d.ts +11 -0
- package/dist/src/lib/workflow-codegen/invokerIR.js +5 -0
- package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -1
- package/dist/src/lib/workflow-config-apply.d.ts +70 -0
- package/dist/src/lib/workflow-config-apply.js +137 -0
- package/dist/src/lib/workflow-config-apply.js.map +1 -0
- package/dist/src/lib/workflow-config-sidecar.d.ts +63 -0
- package/dist/src/lib/workflow-config-sidecar.js +96 -0
- package/dist/src/lib/workflow-config-sidecar.js.map +1 -0
- package/dist/src/lib/workflow-defaults.d.ts +29 -0
- package/dist/src/lib/workflow-defaults.js +41 -0
- package/dist/src/lib/workflow-defaults.js.map +1 -0
- package/dist/src/lib/workflow-include-preserve.d.ts +76 -0
- package/dist/src/lib/workflow-include-preserve.js +286 -0
- package/dist/src/lib/workflow-include-preserve.js.map +1 -0
- package/dist/src/lib/workflow-payload.d.ts +31 -20
- package/dist/src/lib/workflow-payload.js +100 -110
- package/dist/src/lib/workflow-payload.js.map +1 -1
- package/dist/src/lib/workflow-toml-validator.d.ts +37 -16
- package/dist/src/lib/workflow-toml-validator.js +141 -16
- package/dist/src/lib/workflow-toml-validator.js.map +1 -1
- package/dist/src/types/index.d.ts +78 -22
- package/dist/src/validators.d.ts +7 -7
- package/dist/src/validators.js +6 -6
- package/package.json +11 -6
- package/dist/src/commands/settings.d.ts +0 -15
- package/dist/src/commands/settings.js +0 -102
- 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 `
|
|
7
|
-
* (`cli/src/commands/sync.ts`), and the `
|
|
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
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
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
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
?
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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":"AAAA
|
|
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
|
-
* `
|
|
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
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
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 `
|
|
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, `
|
|
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
|
-
* `
|
|
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
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
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
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
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 `
|
|
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, `
|
|
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`).
|