akm-cli 0.9.16 → 0.9.17-alpha.10
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/CHANGELOG.md +2101 -0
- package/STABILITY.md +11 -10
- package/dist/akm +124 -193
- package/dist/akm-migrate +38 -19
- package/dist/assets/hints/cli-hints-full.md +6 -7
- package/dist/assets/improve-strategies/catchup.json +0 -3
- package/dist/assets/improve-strategies/consolidate.json +0 -1
- package/dist/assets/improve-strategies/default.json +1 -2
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -2
- package/dist/assets/improve-strategies/quick.json +1 -2
- package/dist/assets/improve-strategies/reflect-distill.json +1 -2
- package/dist/assets/improve-strategies/thorough.json +0 -3
- package/dist/assets/prompts/consolidate-pair.md +20 -0
- package/dist/assets/prompts/consolidate-system.md +4 -11
- package/dist/assets/prompts/retrieval-relevance-judge.md +6 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +20 -20
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -2
- package/dist/assets/templates/html/health.html +3 -5
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +6 -2
- package/dist/cli/unknown-flags.js +24 -1
- package/dist/cli.js +68 -10
- package/dist/commands/agent/agent-dispatch.js +1 -1
- package/dist/commands/command/command-execution.js +24 -62
- package/dist/commands/feedback-cli.js +0 -1
- package/dist/commands/health/accept-rate.js +6 -0
- package/dist/commands/health/archive-usage.js +92 -0
- package/dist/commands/health/checks.js +83 -74
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/data-dir-usage.js +25 -13
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +1 -42
- package/dist/commands/health/improve-metrics.js +136 -591
- package/dist/commands/health/md-report.js +1 -6
- package/dist/commands/health/plugin-staleness.js +53 -3
- package/dist/commands/health/renderers.js +12 -4
- package/dist/commands/health/report-view-model.js +14 -120
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -74
- package/dist/commands/health.js +145 -143
- package/dist/commands/improve/consolidate/chunking.js +26 -117
- package/dist/commands/improve/consolidate/continuity-check.js +137 -0
- package/dist/commands/improve/consolidate/pair-pass.js +791 -0
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +589 -1127
- package/dist/commands/improve/content-hash.js +16 -24
- package/dist/commands/improve/distill/content-repair.js +18 -100
- package/dist/commands/improve/distill-guards.js +20 -81
- package/dist/commands/improve/distill-promotion-policy.js +23 -243
- package/dist/commands/improve/distill.js +608 -1041
- package/dist/commands/improve/eligibility.js +126 -390
- package/dist/commands/improve/execution.js +8 -10
- package/dist/commands/improve/extract-prompt.js +1 -2
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +75 -169
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +52 -4
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +480 -1074
- package/dist/commands/improve/ledger.js +119 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +415 -1073
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +16 -118
- package/dist/commands/improve/memory/memory-improve.js +266 -14
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -15
- package/dist/commands/improve/preparation.js +779 -2319
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +642 -1353
- package/dist/commands/improve/retrieval-gate.js +127 -0
- package/dist/commands/improve/retrieval-scope.js +92 -0
- package/dist/commands/improve/salience.js +41 -240
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +322 -0
- package/dist/commands/lint/base-linter.js +37 -15
- package/dist/commands/proposal/drain.js +261 -578
- package/dist/commands/proposal/proposal-cli.js +19 -20
- package/dist/commands/proposal/proposal-types.js +31 -24
- package/dist/commands/proposal/proposal.js +38 -8
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +1097 -1394
- package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
- package/dist/commands/proposal/validators/proposal-validators.js +1 -1
- package/dist/commands/proposal/validators/proposals.js +22 -89
- package/dist/commands/read/curate.js +105 -462
- package/dist/commands/read/knowledge.js +3 -2
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +57 -108
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +4 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +127 -29
- package/dist/commands/sources/installed-stashes.js +197 -746
- package/dist/commands/sources/schema-repair.js +98 -129
- package/dist/commands/sources/source-add.js +62 -12
- package/dist/commands/sources/source-manage.js +9 -2
- package/dist/commands/sources/stash-cli.js +24 -4
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +12 -13
- package/dist/commands/tasks/tasks.js +350 -936
- package/dist/commands/tasks/validate.js +26 -24
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +2 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +42 -12
- package/dist/core/adapter/adapters/akm-task-adapter.js +29 -8
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/asset-placement.js +4 -13
- package/dist/core/asset/frontmatter.js +106 -1
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +285 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +9 -34
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +184 -111
- package/dist/core/config/engine-semantics.js +0 -2
- package/dist/core/config/legacy-source-shape-shim.js +38 -9
- package/dist/core/config/schema/embedding.js +20 -5
- package/dist/core/config/schema/engines.js +5 -0
- package/dist/core/config/schema/execution.js +1 -1
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/improve-processes.js +54 -125
- package/dist/core/config/schema/improve.js +4 -42
- package/dist/core/config/schema/index-config.js +9 -48
- package/dist/core/config/schema/scheduler.js +12 -12
- package/dist/core/config/schema/search.js +6 -22
- package/dist/core/env-secret-ref.js +0 -1
- package/dist/core/errors.js +8 -9
- package/dist/core/file-change.js +13 -5
- package/dist/core/file-lock.js +76 -173
- package/dist/core/improve-result.js +35 -7
- package/dist/core/improve-types.js +0 -1
- package/dist/core/logs-db.js +2 -2
- package/dist/core/loopback.js +7 -12
- package/dist/core/non-task-input.js +20 -0
- package/dist/core/parse.js +13 -16
- package/dist/core/paths.js +0 -24
- package/dist/core/redaction.js +109 -2
- package/dist/core/run-lock.js +2 -5
- package/dist/core/spawn-env.js +1 -1
- package/dist/core/state/migrations.js +123 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/time.js +0 -20
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +294 -1005
- package/dist/execution/input-contract.js +1 -1
- package/dist/execution/resolved-request.js +135 -689
- package/dist/execution/source.js +63 -257
- package/dist/execution/target-ref.js +1 -1
- package/dist/indexer/bundle-identity-guard.js +2 -2
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/ensure-index.js +77 -73
- package/dist/indexer/index-rebuild-lock.js +3 -11
- package/dist/indexer/index-writer-lock.js +8 -17
- package/dist/indexer/index-written-assets.js +141 -154
- package/dist/indexer/indexer.js +400 -1124
- package/dist/indexer/links/declared-links.js +90 -0
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +96 -90
- package/dist/indexer/passes/metadata.js +132 -219
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +2 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +190 -590
- package/dist/indexer/search/fts-query.js +30 -41
- package/dist/indexer/search/ranking.js +28 -154
- package/dist/indexer/search/search-attribution.js +12 -32
- package/dist/indexer/search/search-fields.js +11 -15
- package/dist/indexer/search/search-hit-enrichers.js +54 -85
- package/dist/indexer/search/search-source.js +1 -4
- package/dist/indexer/usage/usage-events.js +36 -7
- package/dist/indexer/walk/walker.js +3 -4
- package/dist/integrations/agent/engine-fallback.js +23 -40
- package/dist/integrations/agent/engine-resolution.js +93 -183
- package/dist/integrations/agent/execution.js +507 -0
- package/dist/integrations/agent/model-map.js +28 -156
- package/dist/integrations/agent/request-lowering.js +66 -141
- package/dist/integrations/agent/runner-dispatch.js +143 -321
- package/dist/integrations/agent/runner.js +54 -14
- package/dist/integrations/lockfile.js +53 -101
- package/dist/llm/client.js +18 -6
- package/dist/llm/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +11 -17
- package/dist/llm/feature-gate.js +0 -8
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/structured-call.js +5 -24
- package/dist/output/generic-render.js +23 -11
- package/dist/output/html-render.js +13 -10
- package/dist/output/render-registry.js +3 -32
- package/dist/output/shapes/helpers.js +25 -38
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/graph/graph-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +69 -31
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +48 -3
- package/dist/output/text/show-format.js +13 -17
- package/dist/output/text/workflow-format.js +0 -32
- package/dist/output/text.js +2 -0
- package/dist/registry/factory.js +4 -19
- package/dist/registry/network.js +66 -220
- package/dist/registry/providers/index.js +0 -2
- package/dist/registry/providers/skills-sh.js +3 -14
- package/dist/registry/providers/static-index.js +24 -26
- package/dist/registry/resolve.js +55 -131
- package/dist/scripts/akm-migrate-node.js +42948 -92369
- package/dist/scripts/akm-migrate.js +42935 -92354
- package/dist/setup/registry-stash-loader.js +4 -13
- package/dist/setup/semantic-assets.js +3 -44
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/connection.js +5 -6
- package/dist/setup/steps/platforms.js +2 -2
- package/dist/setup/steps/tasks.js +25 -15
- package/dist/sources/provider-factory.js +17 -18
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +7 -1
- package/dist/sources/providers/git-provider.js +0 -3
- package/dist/sources/providers/git-stash.js +83 -21
- package/dist/sources/providers/npm.js +2 -4
- package/dist/sources/providers/provider-utils.js +5 -10
- package/dist/sources/providers/website.js +0 -2
- package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
- package/dist/sources/website-url.js +2 -2
- package/dist/storage/database.js +9 -35
- package/dist/storage/repositories/improve-ledger-repository.js +209 -0
- package/dist/storage/repositories/index-connection.js +39 -72
- package/dist/storage/repositories/index-entries-repository.js +131 -129
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +101 -268
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-links-repository.js +143 -0
- package/dist/storage/repositories/index-llm-cache-repository.js +7 -9
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +257 -325
- package/dist/storage/repositories/index-utility-repository.js +8 -29
- package/dist/storage/repositories/index-vec-repository.js +133 -414
- package/dist/storage/repositories/outcome-repository.js +2 -1
- package/dist/storage/repositories/proposals-repository.js +104 -1
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- package/dist/storage/repositories/salience-repository.js +1 -19
- package/dist/storage/repositories/task-history-repository.js +26 -4
- package/dist/storage/repositories/workflow-runs-repository.js +53 -244
- package/dist/storage/sqlite-migrations.js +136 -0
- package/dist/storage/sqlite-pragmas.js +11 -9
- package/dist/storage/sqlite-transaction.js +170 -0
- package/dist/storage/state-db-integrity.js +130 -0
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +191 -302
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +141 -748
- package/dist/tasks/backends/schtasks.js +119 -623
- package/dist/tasks/prepare/prepare-support.js +5 -15
- package/dist/tasks/prepare/prepare.js +0 -2
- package/dist/tasks/resolve-akm-bin.js +20 -79
- package/dist/tasks/run/attempt-lifecycle.js +0 -1
- package/dist/tasks/run/load-task.js +1 -1
- package/dist/tasks/scheduler-binding.js +20 -238
- package/dist/tasks/scheduler-invocation.js +136 -244
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +368 -679
- package/dist/tasks/source/parse-task-source.js +55 -9
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +464 -88
- package/dist/workflows/authoring/authoring.js +3 -12
- package/dist/workflows/compile.js +211 -0
- package/dist/workflows/concurrency-policy.js +13 -74
- package/dist/workflows/exec/child-invocation.js +3 -17
- package/dist/workflows/exec/child-workflow.js +32 -141
- package/dist/workflows/exec/dispatch-redaction.js +13 -53
- package/dist/workflows/exec/environment.js +98 -0
- package/dist/workflows/exec/exec-unit.js +33 -140
- package/dist/workflows/exec/frozen-judge.js +7 -59
- package/dist/workflows/exec/native-executor.js +82 -341
- package/dist/workflows/exec/param-secrets.js +29 -47
- package/dist/workflows/exec/run-workflow.js +154 -387
- package/dist/workflows/exec/scheduler.js +9 -36
- package/dist/workflows/exec/step-work.js +127 -430
- package/dist/workflows/exec/unit-dispatch.js +11 -63
- package/dist/workflows/exec/unit-writer.js +8 -52
- package/dist/workflows/exec/worktree.js +39 -273
- package/dist/workflows/freeze/child-output-references.js +4 -15
- package/dist/workflows/freeze/environment.js +99 -92
- package/dist/workflows/freeze/freeze.js +172 -0
- package/dist/workflows/freeze/step-values.js +19 -21
- package/dist/workflows/freeze/targets/child-workflow.js +23 -92
- package/dist/workflows/freeze/targets/command.js +10 -33
- package/dist/workflows/freeze/targets/script.js +5 -12
- package/dist/workflows/freeze/targets/shell.js +3 -6
- package/dist/workflows/freeze/targets/task.js +25 -80
- package/dist/workflows/freeze/task-bindings.js +20 -67
- package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
- package/dist/workflows/ir/params.js +6 -51
- package/dist/workflows/ir/plan-hash.js +2 -34
- package/dist/workflows/parser.js +140 -43
- package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
- package/dist/workflows/renderer.js +36 -69
- package/dist/workflows/resource-limits.js +12 -120
- package/dist/workflows/runtime/agent-identity.js +8 -40
- package/dist/workflows/runtime/run-outputs.js +3 -6
- package/dist/workflows/runtime/run-plan.js +316 -0
- package/dist/workflows/runtime/runs.js +48 -200
- package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
- package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/integration/bundling-akm.md +49 -42
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.17.md +43 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +23 -7
- package/docs/reference/cli.md +232 -135
- package/docs/reference/configuration.md +71 -57
- package/docs/reference/data-and-telemetry.md +20 -21
- package/docs/reference/tasks.md +105 -39
- package/docs/reference/workflow-schema.md +14 -18
- package/docs/reference/workflows.md +6 -9
- package/package.json +1 -1
- package/schemas/akm-config.json +115 -738
- package/schemas/akm-workflow.json +1 -0
- package/dist/assets/improve-strategies/graph-refresh.json +0 -15
- package/dist/assets/prompts/contradiction-judge.md +0 -33
- package/dist/assets/prompts/graph-extract-system.md +0 -1
- package/dist/assets/prompts/graph-extract-user-prompt.md +0 -35
- package/dist/assets/prompts/metadata-enhance-system.md +0 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +0 -4
- package/dist/commands/health/advisories.js +0 -150
- package/dist/commands/health/metrics.js +0 -329
- package/dist/commands/health/surfaces.js +0 -102
- package/dist/commands/improve/anti-collapse.js +0 -83
- package/dist/commands/improve/collapse-detector.js +0 -432
- package/dist/commands/improve/consolidate/eligibility.js +0 -48
- package/dist/commands/improve/consolidate/merge.js +0 -149
- package/dist/commands/improve/distill/promote-memory.js +0 -291
- package/dist/commands/improve/distill/quality-gate.js +0 -337
- package/dist/commands/improve/eval-cases.js +0 -52
- package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
- package/dist/commands/improve/proposal-envelope.js +0 -31
- package/dist/commands/improve/run-context.js +0 -123
- package/dist/commands/improve/shared.js +0 -31
- package/dist/commands/improve/source-identity.js +0 -28
- package/dist/commands/improve/triage.js +0 -96
- package/dist/commands/proposal/drain-policies.js +0 -151
- package/dist/commands/sources/update-transaction.js +0 -220
- package/dist/core/action-contributors.js +0 -28
- package/dist/core/config/config-version-shim.js +0 -101
- package/dist/core/fs-txn.js +0 -405
- package/dist/core/lexical-score.js +0 -25
- package/dist/core/maintenance-barrier.js +0 -167
- package/dist/execution/executable-identity.js +0 -105
- package/dist/execution/guarded-source.js +0 -427
- package/dist/indexer/db/graph-db.js +0 -444
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/graph/graph-extraction.js +0 -1108
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- package/dist/indexer/search/ranking-types.js +0 -4
- package/dist/indexer/walk/project-context.js +0 -192
- package/dist/integrations/agent/execution-cascade.js +0 -566
- package/dist/integrations/agent/execution-definitions.js +0 -202
- package/dist/integrations/agent/execution-lowering.js +0 -841
- package/dist/integrations/agent/execution-preparation.js +0 -98
- package/dist/integrations/agent/inline-execution.js +0 -74
- package/dist/llm/graph-extract.js +0 -728
- package/dist/llm/metadata-enhance.js +0 -96
- package/dist/registry/create-provider-registry.js +0 -29
- package/dist/registry/pinned-request-helper.js +0 -247
- package/dist/registry/pinned-transport.js +0 -717
- package/dist/sources/providers/index.js +0 -14
- package/dist/storage/engines/sqlite-migrations.js +0 -271
- package/dist/storage/repositories/canaries-repository.js +0 -107
- package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
- package/dist/storage/repositories/registry-cache.js +0 -113
- package/dist/tasks/scheduler-sync-preview.js +0 -52
- package/dist/tasks/source/task-to-v3.js +0 -507
- package/dist/workflows/freeze/resolve-steps.js +0 -86
- package/dist/workflows/freeze/source-freeze.js +0 -64
- package/dist/workflows/ir/compile.js +0 -321
- package/dist/workflows/ir/environment-v4.js +0 -330
- package/dist/workflows/ir/freeze-v4.js +0 -153
- package/dist/workflows/ir/schema-v4.js +0 -745
- package/dist/workflows/ir/schema.js +0 -354
- package/dist/workflows/program/schema.js +0 -77
- package/dist/workflows/runtime/checkin.js +0 -57
- package/dist/workflows/runtime/plan-classifier.js +0 -196
- package/dist/workflows/runtime/unit-checkin.js +0 -45
- package/dist/workflows/runtime/unit-phases.js +0 -20
- package/dist/workflows/schema.js +0 -4
- package/dist/workflows/source-ir/compile.js +0 -200
- package/dist/workflows/source-ir/program.js +0 -50
- package/dist/workflows/source-ir/result.js +0 -26
- package/dist/workflows/source-ir/schema.js +0 -786
- package/dist/workflows/source-ir/triggers.js +0 -79
- package/dist/workflows/source-ir/uses.js +0 -40
- package/dist/workflows/validator.js +0 -60
|
@@ -2,23 +2,13 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* {@link
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `TaskInputBinding[]` by name against a DIFFERENT contract, trusting each
|
|
13
|
-
* entry's existing `kind` rather than re-deriving it from the value's shape
|
|
14
|
-
* (`freeze/targets/child-workflow.ts`'s only caller). Everything decidable
|
|
15
|
-
* at FREEZE time is decided here; a reference's *resolved* value is
|
|
16
|
-
* validated PRE-ATTEMPT instead (`exec/step-work.ts`). Pure function: no IO,
|
|
17
|
-
* no config reads.
|
|
18
|
-
*
|
|
19
|
-
* See docs/architecture/decisions/0008-task-binding-normalization.md for the
|
|
20
|
-
* full design history, including why re-binding cannot reuse the
|
|
21
|
-
* shape-driven normalizer (a code-review finding).
|
|
5
|
+
* Pure freeze-time binding of a composing step's inputs.
|
|
6
|
+
* {@link freezeTaskInputBindings} classifies an authored `with:` against a
|
|
7
|
+
* contract; {@link rebindTaskInputBindings} re-binds already-classified
|
|
8
|
+
* bindings by name against another contract (a task's effective inputs
|
|
9
|
+
* against a child workflow's `params:`) without re-deriving their kind. A
|
|
10
|
+
* reference's resolved value is validated before each attempt (`exec/step-work.ts`).
|
|
11
|
+
* See docs/architecture/decisions/0008-task-binding-normalization.md.
|
|
22
12
|
*/
|
|
23
13
|
import { isRecord } from "../../core/common.js";
|
|
24
14
|
import { UsageError } from "../../core/errors.js";
|
|
@@ -32,14 +22,9 @@ function unknownBindingNameError(stepId, targetRef, name, declaredNames) {
|
|
|
32
22
|
`Declared inputs: ${declaredNames.length > 0 ? declaredNames.join(", ") : "(none)"}.`);
|
|
33
23
|
}
|
|
34
24
|
/**
|
|
35
|
-
* Normalize
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* found — per authored entry first (B-11, B-15, B-16, B-17, B-18), then over
|
|
39
|
-
* the whole contract (B-12, B-13). The result is sorted by name; an entry
|
|
40
|
-
* exists only for a declared input with an effective value (authored
|
|
41
|
-
* literal, authored reference, or an applied default) — never for an
|
|
42
|
-
* unsupplied optional input with no default (B-20).
|
|
25
|
+
* Normalize an authored `with:` into the sorted `TaskInputBinding[]` a frozen
|
|
26
|
+
* target carries: one entry per declared input with an effective value
|
|
27
|
+
* (literal, reference, or default). Throws `INPUT_BINDING_INVALID` on the first violation.
|
|
43
28
|
*/
|
|
44
29
|
export function freezeTaskInputBindings(input) {
|
|
45
30
|
const { stepId, targetRef, contract, earlierStepIds, declaredParamNames } = input;
|
|
@@ -57,28 +42,11 @@ export function freezeTaskInputBindings(input) {
|
|
|
57
42
|
return finalizeBindings(stepId, targetRef, contract, byName);
|
|
58
43
|
}
|
|
59
44
|
/**
|
|
60
|
-
* Re-bind
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* its value's shape (a code-review finding — see
|
|
66
|
-
* docs/architecture/decisions/0008-task-binding-normalization.md for why a
|
|
67
|
-
* shape-shifting round-trip through {@link normalizeOneEntry} would
|
|
68
|
-
* silently misclassify a literal value shaped like a reference).
|
|
69
|
-
*
|
|
70
|
-
* Per-entry rules, otherwise identical to {@link freezeTaskInputBindings}:
|
|
71
|
-
* an entry naming a key the new `contract` does not declare is
|
|
72
|
-
* `INPUT_BINDING_INVALID` (same message shape); a `kind: "literal"` entry
|
|
73
|
-
* keeps its value verbatim and is validated against the NEW contract's
|
|
74
|
-
* declared schema for that name; a `kind: "reference"` entry keeps its
|
|
75
|
-
* `from` verbatim (the reference target — an earlier step or declared param
|
|
76
|
-
* of the composing workflow — does not change with which contract it is
|
|
77
|
-
* bound against) and its `schema` is re-derived from the NEW contract,
|
|
78
|
-
* matching {@link normalizeOneEntry}'s existing rule that a reference
|
|
79
|
-
* binding's schema always comes from the contract it is bound against; a
|
|
80
|
-
* contract key absent from `bindings` is defaulted or required exactly as
|
|
81
|
-
* {@link freezeTaskInputBindings} does.
|
|
45
|
+
* Re-bind already-normalized bindings by name against a different contract,
|
|
46
|
+
* keeping each entry's kind (a literal shaped like `{from}` stays a literal).
|
|
47
|
+
* A literal is validated against the new contract; a reference keeps its
|
|
48
|
+
* `from` and takes the new contract's schema; undeclared names are
|
|
49
|
+
* `INPUT_BINDING_INVALID`; missing keys are defaulted or required as usual.
|
|
82
50
|
*/
|
|
83
51
|
export function rebindTaskInputBindings(input) {
|
|
84
52
|
const { stepId, targetRef, contract } = input;
|
|
@@ -97,14 +65,7 @@ export function rebindTaskInputBindings(input) {
|
|
|
97
65
|
}
|
|
98
66
|
return finalizeBindings(stepId, targetRef, contract, byName);
|
|
99
67
|
}
|
|
100
|
-
/**
|
|
101
|
-
* The tail shared by {@link freezeTaskInputBindings} and
|
|
102
|
-
* {@link rebindTaskInputBindings} once `byName` holds one classified entry
|
|
103
|
-
* per AUTHORED/bound name: apply declared defaults for every remaining
|
|
104
|
-
* contract key (or throw for a required one with none), schema-validate
|
|
105
|
-
* every literal (authored, re-bound, or defaulted) against the contract, and
|
|
106
|
-
* return the result sorted by name.
|
|
107
|
-
*/
|
|
68
|
+
/** Shared tail: apply defaults (or require), schema-validate every literal, and sort by name. */
|
|
108
69
|
function finalizeBindings(stepId, targetRef, contract, byName) {
|
|
109
70
|
for (const [name, declaration] of Object.entries(contract)) {
|
|
110
71
|
if (byName.has(name))
|
|
@@ -118,11 +79,7 @@ function finalizeBindings(stepId, targetRef, contract, byName) {
|
|
|
118
79
|
`supply it with with.${name}.`);
|
|
119
80
|
}
|
|
120
81
|
}
|
|
121
|
-
//
|
|
122
|
-
// against its own declared schema — a contract NARROWED to just the
|
|
123
|
-
// literal-bound names, so a required input bound via REFERENCE (whose
|
|
124
|
-
// value is not known until pre-attempt, §3.6) is never wrongly flagged
|
|
125
|
-
// "missing" here.
|
|
82
|
+
// Validate literals only: a reference's value is not known until the attempt.
|
|
126
83
|
const literalContract = {};
|
|
127
84
|
const literalValues = {};
|
|
128
85
|
for (const binding of byName.values()) {
|
|
@@ -141,13 +98,9 @@ function finalizeBindings(stepId, targetRef, contract, byName) {
|
|
|
141
98
|
return Object.freeze(sorted);
|
|
142
99
|
}
|
|
143
100
|
/**
|
|
144
|
-
* Classify
|
|
145
|
-
*
|
|
146
|
-
* `
|
|
147
|
-
* whose OWN key set is exactly `["from"]` and whose `from` is a string
|
|
148
|
-
* `parseReference` accepts — the hard-fail band (B-15, B-16) means any OTHER
|
|
149
|
-
* shape carrying an own `from` key is `INPUT_BINDING_INVALID`, never
|
|
150
|
-
* reinterpreted as a literal.
|
|
101
|
+
* Classify one authored `with:` entry: exactly `{ from: <valid reference> }`
|
|
102
|
+
* is a reference; any other object with an own `from` key is
|
|
103
|
+
* `INPUT_BINDING_INVALID`, never a literal.
|
|
151
104
|
*/
|
|
152
105
|
function normalizeOneEntry(stepId, targetRef, name, value, schema, earlierStepIds, declaredParamNames) {
|
|
153
106
|
if (!isRecord(value) || !Object.hasOwn(value, "from")) {
|
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* The GitHub-shaped YAML workflow grammar: a strict `name`/`on`/`jobs`
|
|
6
|
+
* document with exactly one job, compiled straight to a {@link WorkflowPlan}.
|
|
7
|
+
* It is an AKM workflow format executed by AKM's own engine, not GitHub
|
|
8
|
+
* Actions: no expressions, no service events, `runs-on: [self-hosted]` only.
|
|
9
|
+
*/
|
|
4
10
|
import { isAlias, isMap, isScalar, isSeq, LineCounter, parseDocument } from "yaml";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
import { WORKFLOW_PLAN_VERSION, } from "./plan.js";
|
|
12
|
+
import { utf8Bytes, WORKFLOW_MAX_SOURCE_BYTES } from "./resource-limits.js";
|
|
13
|
+
import { canonicalizeWorkflowCron, canonicalizeWorkflowRun, canonicalizeWorkflowWorkingDirectory, classifyWorkflowStepUses, validateWorkflowBuiltinCommand, WorkflowSourceSemanticError, workflowShellCommand, } from "./source-semantics.js";
|
|
14
|
+
/** A located compile failure; `compile.ts` turns it into a `WorkflowSourceError`. */
|
|
15
|
+
export class WorkflowSourceFailure extends Error {
|
|
16
|
+
error;
|
|
17
|
+
constructor(code, message, source) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "WorkflowSourceFailure";
|
|
20
|
+
this.error = { code, message, path: source.path, line: source.start };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
10
23
|
const ROOT_KEYS = ["name", "on", "jobs"];
|
|
11
24
|
const TRIGGER_KEYS = ["schedule", "workflow_dispatch"];
|
|
12
25
|
const SCHEDULE_KEYS = ["cron"];
|
|
13
26
|
const JOB_KEYS = ["name", "needs", "runs-on", "steps"];
|
|
14
27
|
const STEP_KEYS = ["id", "name", "uses", "run", "with", "env", "shell", "working-directory"];
|
|
15
28
|
const UNSAFE_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
16
|
-
const HOST_SHELLS = new Set(
|
|
29
|
+
const HOST_SHELLS = new Set(["bash", "sh", "zsh", "pwsh", "powershell", "cmd"]);
|
|
17
30
|
const SOURCE_ID = /^[A-Za-z_][A-Za-z0-9_-]{0,127}$/;
|
|
18
31
|
const INPUT_KEY = /^[A-Za-z_][A-Za-z0-9_.-]{0,127}$/;
|
|
19
32
|
const ENV_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
@@ -80,16 +93,10 @@ export function parseGithubWorkflowSource(source, options) {
|
|
|
80
93
|
reader.rejectAliases(parsedRoot);
|
|
81
94
|
reader.checkTree(parsedRoot);
|
|
82
95
|
const root = reader.fields(parsedRoot, ROOT_KEYS, "workflow");
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
return {
|
|
87
|
-
sourceIrVersion: 1,
|
|
88
|
-
name,
|
|
89
|
-
triggers,
|
|
90
|
-
jobs,
|
|
91
|
-
source: documentSource,
|
|
92
|
-
};
|
|
96
|
+
reader.requiredString(root, "name", "workflow");
|
|
97
|
+
const schedules = parseTriggers(reader, reader.required(root, "on", "workflow"));
|
|
98
|
+
const steps = parseJob(reader, reader.required(root, "jobs", "workflow"), options);
|
|
99
|
+
return { irVersion: WORKFLOW_PLAN_VERSION, title: options.title, schedules, steps };
|
|
93
100
|
}
|
|
94
101
|
class StrictYamlReader {
|
|
95
102
|
filePath;
|
|
@@ -226,29 +233,6 @@ class StrictYamlReader {
|
|
|
226
233
|
}
|
|
227
234
|
this.fail("invalid-yaml-node", `${context} contains an unsupported YAML node.`, node);
|
|
228
235
|
}
|
|
229
|
-
lineAt(root, structuralPath) {
|
|
230
|
-
let current = root;
|
|
231
|
-
for (const [index, segment] of structuralPath.entries()) {
|
|
232
|
-
if (typeof segment === "string" && isMap(current)) {
|
|
233
|
-
const pair = current.items.find((candidate) => isScalar(candidate.key) && candidate.key.value === segment);
|
|
234
|
-
if (!pair)
|
|
235
|
-
return undefined;
|
|
236
|
-
if (pair.value === null) {
|
|
237
|
-
return index === structuralPath.length - 1 ? this.span(pair.key).start : undefined;
|
|
238
|
-
}
|
|
239
|
-
current = pair.value;
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
if (typeof segment === "number" && isSeq(current)) {
|
|
243
|
-
current = current.items[segment] ?? null;
|
|
244
|
-
if (current === null)
|
|
245
|
-
return undefined;
|
|
246
|
-
continue;
|
|
247
|
-
}
|
|
248
|
-
return undefined;
|
|
249
|
-
}
|
|
250
|
-
return this.span(current).start;
|
|
251
|
-
}
|
|
252
236
|
required(fields, key, context) {
|
|
253
237
|
const pair = fields.get(key);
|
|
254
238
|
if (!pair)
|
|
@@ -301,7 +285,7 @@ class StrictYamlReader {
|
|
|
301
285
|
throw new WorkflowSourceFailure(code, message, this.span(node));
|
|
302
286
|
}
|
|
303
287
|
}
|
|
304
|
-
function parseTriggers(reader,
|
|
288
|
+
function parseTriggers(reader, node) {
|
|
305
289
|
const fields = reader.arbitraryFields(node, "workflow.on");
|
|
306
290
|
for (const [key, pair] of fields) {
|
|
307
291
|
if (!TRIGGER_KEYS.includes(key)) {
|
|
@@ -310,7 +294,7 @@ function parseTriggers(reader, root, node, options) {
|
|
|
310
294
|
}
|
|
311
295
|
if (fields.size === 0)
|
|
312
296
|
reader.fail("trigger-required", "workflow.on must declare schedule or workflow_dispatch.", node);
|
|
313
|
-
const
|
|
297
|
+
const schedules = [];
|
|
314
298
|
const schedule = fields.get("schedule");
|
|
315
299
|
if (schedule) {
|
|
316
300
|
const records = reader.sequence(schedule.value, "workflow.on.schedule", 64);
|
|
@@ -318,7 +302,7 @@ function parseTriggers(reader, root, node, options) {
|
|
|
318
302
|
const scheduleFields = reader.fields(record, SCHEDULE_KEYS, `workflow.on.schedule[${ordinal}]`);
|
|
319
303
|
const cronNode = reader.required(scheduleFields, "cron", `workflow.on.schedule[${ordinal}]`);
|
|
320
304
|
const cron = validateCron(reader, reader.string(cronNode, `workflow.on.schedule[${ordinal}].cron`), cronNode);
|
|
321
|
-
|
|
305
|
+
schedules.push({ cron, ordinal, line: reader.span(cronNode).start });
|
|
322
306
|
}
|
|
323
307
|
}
|
|
324
308
|
const manual = fields.get("workflow_dispatch");
|
|
@@ -332,62 +316,8 @@ function parseTriggers(reader, root, node, options) {
|
|
|
332
316
|
reader.fail("workflow-dispatch-inputs-unsupported", "workflow_dispatch inputs are not supported for local execution.", manual.value.items[0]?.key);
|
|
333
317
|
}
|
|
334
318
|
}
|
|
335
|
-
triggers.push({ kind: "workflow_dispatch", source: reader.span(manual.key) });
|
|
336
|
-
}
|
|
337
|
-
if (options.classifyTriggers) {
|
|
338
|
-
verifyOwnerTriggerPlan(reader, root, node, triggers, options);
|
|
339
|
-
}
|
|
340
|
-
return triggers;
|
|
341
|
-
}
|
|
342
|
-
function verifyOwnerTriggerPlan(reader, root, onNode, triggers, options) {
|
|
343
|
-
const classifier = options.classifyTriggers;
|
|
344
|
-
if (!classifier)
|
|
345
|
-
return;
|
|
346
|
-
let lastLine = reader.span(onNode).start;
|
|
347
|
-
let plan;
|
|
348
|
-
try {
|
|
349
|
-
plan = classifier({ on: reader.plain(onNode, "workflow.on") }, {
|
|
350
|
-
filePath: options.path,
|
|
351
|
-
lineAt: (structuralPath) => {
|
|
352
|
-
const line = reader.lineAt(root, structuralPath);
|
|
353
|
-
if (line !== undefined)
|
|
354
|
-
lastLine = line;
|
|
355
|
-
return line;
|
|
356
|
-
},
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
catch (cause) {
|
|
360
|
-
const message = cause instanceof Error ? cause.message : String(cause);
|
|
361
|
-
throw new WorkflowSourceFailure("invalid-trigger", message, {
|
|
362
|
-
path: options.path,
|
|
363
|
-
start: lastLine,
|
|
364
|
-
end: lastLine,
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
const expectedSchedules = triggers.filter((trigger) => trigger.kind === "schedule");
|
|
368
|
-
const expectedManual = triggers.some((trigger) => trigger.kind === "workflow_dispatch");
|
|
369
|
-
const matches = plan !== null &&
|
|
370
|
-
typeof plan === "object" &&
|
|
371
|
-
plan.manual === expectedManual &&
|
|
372
|
-
Array.isArray(plan.schedules) &&
|
|
373
|
-
plan.schedules.length === expectedSchedules.length &&
|
|
374
|
-
plan.schedules.every((binding, index) => {
|
|
375
|
-
const expected = expectedSchedules[index];
|
|
376
|
-
let canonicalBindingCron;
|
|
377
|
-
try {
|
|
378
|
-
canonicalBindingCron = canonicalizeWorkflowCron(binding.cron);
|
|
379
|
-
}
|
|
380
|
-
catch {
|
|
381
|
-
return false;
|
|
382
|
-
}
|
|
383
|
-
return (expected !== undefined &&
|
|
384
|
-
canonicalBindingCron === expected.cron &&
|
|
385
|
-
binding.ordinal === expected.ordinal &&
|
|
386
|
-
binding.source === `on.schedule[${expected.ordinal}].cron`);
|
|
387
|
-
});
|
|
388
|
-
if (!matches) {
|
|
389
|
-
throw new WorkflowSourceFailure("trigger-classifier-drift", "The workflow trigger parser disagrees with the canonical workflow YAML trigger classifier.", reader.span(onNode));
|
|
390
319
|
}
|
|
320
|
+
return schedules;
|
|
391
321
|
}
|
|
392
322
|
function validateCron(reader, cron, node) {
|
|
393
323
|
try {
|
|
@@ -398,77 +328,45 @@ function validateCron(reader, cron, node) {
|
|
|
398
328
|
}
|
|
399
329
|
}
|
|
400
330
|
/**
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
* familiar GitHub-step-shaped `name:`/`on:`/`jobs:` document, but requires
|
|
404
|
-
* exactly one job (brief §10) — it is an AKM workflow format executed by
|
|
405
|
-
* AKM's native engine, not a GitHub Actions graph. Job ordering, dependency
|
|
406
|
-
* validation and the 256-job bound all existed only to support MULTIPLE
|
|
407
|
-
* jobs; they are gone with the machinery, not relocated.
|
|
331
|
+
* Exactly one job: AKM's YAML is an AKM workflow format executed by AKM's
|
|
332
|
+
* native engine, not a GitHub Actions job graph.
|
|
408
333
|
*/
|
|
409
|
-
function
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
if (!first)
|
|
415
|
-
first = entry;
|
|
416
|
-
else if (!second)
|
|
417
|
-
second = entry;
|
|
418
|
-
}
|
|
419
|
-
if (fields.size !== 1 || !first) {
|
|
420
|
-
reader.fail("multi-job-unsupported", `AKM workflow YAML requires exactly one job; this document declares ${fields.size}. AKM's YAML is an AKM workflow format executed by AKM's native engine, not GitHub Actions — split the jobs into separate workflows.`, second ? second[1].key : node);
|
|
334
|
+
function parseJob(reader, node, options) {
|
|
335
|
+
const jobs = reader.arbitraryFields(node, "workflow.jobs");
|
|
336
|
+
const [first, second] = [...jobs];
|
|
337
|
+
if (jobs.size !== 1 || !first) {
|
|
338
|
+
reader.fail("multi-job-unsupported", `AKM workflow YAML requires exactly one job; this document declares ${jobs.size}. AKM's YAML is an AKM workflow format executed by AKM's native engine, not GitHub Actions — split the jobs into separate workflows.`, second ? second[1].key : node);
|
|
421
339
|
}
|
|
422
340
|
const [id, pair] = first;
|
|
423
|
-
const
|
|
424
|
-
if (job.needs.length > 0) {
|
|
425
|
-
reader.fail("multi-job-unsupported", `Job ${job.id} declares needs, but an AKM workflow has exactly one job; remove needs.`, pair.key);
|
|
426
|
-
}
|
|
427
|
-
return [job];
|
|
428
|
-
}
|
|
429
|
-
function parseJob(reader, id, pair, options) {
|
|
430
|
-
const node = pair.value;
|
|
341
|
+
const jobNode = pair.value;
|
|
431
342
|
if (!SOURCE_ID.test(id))
|
|
432
|
-
reader.fail("invalid-job-id", `Invalid job id ${JSON.stringify(id)}.`,
|
|
433
|
-
const fields = reader.fields(
|
|
434
|
-
|
|
435
|
-
|
|
343
|
+
reader.fail("invalid-job-id", `Invalid job id ${JSON.stringify(id)}.`, jobNode);
|
|
344
|
+
const fields = reader.fields(jobNode, JOB_KEYS, `workflow.jobs.${id}`);
|
|
345
|
+
const runner = reader.required(fields, "runs-on", `workflow.jobs.${id}`);
|
|
346
|
+
if (!isSeq(runner) ||
|
|
347
|
+
runner.items.length !== 1 ||
|
|
348
|
+
!isScalar(runner.items[0]) ||
|
|
349
|
+
runner.items[0].value !== "self-hosted") {
|
|
350
|
+
reader.fail("unsupported-runner", `Job ${JSON.stringify(id)} must declare exactly runs-on: [self-hosted].`, runner);
|
|
351
|
+
}
|
|
352
|
+
const needs = fields.get("needs");
|
|
353
|
+
if (needs) {
|
|
354
|
+
const values = isSeq(needs.value)
|
|
355
|
+
? reader
|
|
356
|
+
.sequence(needs.value, `workflow.jobs.${id}.needs`, 256)
|
|
357
|
+
.map((item) => reader.string(item, `workflow.jobs.${id}.needs`))
|
|
358
|
+
: [reader.string(needs.value, `workflow.jobs.${id}.needs`)];
|
|
359
|
+
for (const need of values)
|
|
360
|
+
if (!SOURCE_ID.test(need))
|
|
361
|
+
reader.fail("invalid-job-id", `Invalid needs id ${need}.`, needs.value);
|
|
362
|
+
if (values.length > 0) {
|
|
363
|
+
reader.fail("multi-job-unsupported", `Job ${id} declares needs, but an AKM workflow has exactly one job; remove needs.`, pair.key);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
reader.optionalString(fields, "name", `workflow.jobs.${id}`);
|
|
436
367
|
const stepNodes = reader.sequence(reader.required(fields, "steps", `workflow.jobs.${id}`), `workflow.jobs.${id}.steps`, MAX_STEPS_PER_JOB);
|
|
437
368
|
const stepIds = new Set();
|
|
438
|
-
|
|
439
|
-
const name = reader.optionalString(fields, "name", `workflow.jobs.${id}`);
|
|
440
|
-
const keySource = reader.span(pair.key);
|
|
441
|
-
const valueSource = reader.span(node);
|
|
442
|
-
return {
|
|
443
|
-
id,
|
|
444
|
-
...(name ? { name } : {}),
|
|
445
|
-
needs,
|
|
446
|
-
steps,
|
|
447
|
-
extensions: { "github.com/actions-workflow": { runsOn: ["self-hosted"] } },
|
|
448
|
-
source: { path: keySource.path, start: keySource.start, end: valueSource.end },
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
function validateRunner(reader, node, jobId) {
|
|
452
|
-
if (!isSeq(node) || node.items.length !== 1 || !isScalar(node.items[0]) || node.items[0].value !== "self-hosted") {
|
|
453
|
-
reader.fail("unsupported-runner", `Job ${JSON.stringify(jobId)} must declare exactly runs-on: [self-hosted].`, node);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
function parseNeeds(reader, pair, jobId) {
|
|
457
|
-
if (!pair)
|
|
458
|
-
return [];
|
|
459
|
-
const values = isSeq(pair.value)
|
|
460
|
-
? reader
|
|
461
|
-
.sequence(pair.value, `workflow.jobs.${jobId}.needs`, 256)
|
|
462
|
-
.map((item) => reader.string(item, `workflow.jobs.${jobId}.needs`))
|
|
463
|
-
: [reader.string(pair.value, `workflow.jobs.${jobId}.needs`)];
|
|
464
|
-
for (const need of values)
|
|
465
|
-
if (!SOURCE_ID.test(need))
|
|
466
|
-
reader.fail("invalid-job-id", `Invalid needs id ${need}.`, pair.value);
|
|
467
|
-
// Duplicate-entry checking (code duplicate-job-dependency) deleted with the
|
|
468
|
-
// rest of the multi-job dependency machinery (P4 §3.3): ANY non-empty
|
|
469
|
-
// needs — duplicated or not — is multi-job-unsupported at the caller
|
|
470
|
-
// (parseJobs), since a single-job workflow has nothing to depend on.
|
|
471
|
-
return values.sort();
|
|
369
|
+
return stepNodes.map((step, index) => parseStep(reader, step, id, index, stepIds, options));
|
|
472
370
|
}
|
|
473
371
|
function parseStep(reader, node, jobId, index, stepIds, options) {
|
|
474
372
|
const context = `workflow.jobs.${jobId}.steps[${index}]`;
|
|
@@ -484,33 +382,35 @@ function parseStep(reader, node, jobId, index, stepIds, options) {
|
|
|
484
382
|
if ((usesPair === undefined) === (runPair === undefined)) {
|
|
485
383
|
reader.fail("step-target-xor", `${context} must declare exactly one of uses or run.`, node);
|
|
486
384
|
}
|
|
487
|
-
|
|
488
|
-
if (usesPair)
|
|
489
|
-
return parseUsesStep(reader, usesPair, fields, options, { id, ...common, source: reader.span(node) });
|
|
490
|
-
if (!runPair)
|
|
491
|
-
reader.fail("step-target-xor", `${context} must declare exactly one of uses or run.`, node);
|
|
492
|
-
return parseRunStep(reader, runPair, fields, options, { id, ...common, source: reader.span(node) });
|
|
493
|
-
}
|
|
494
|
-
function parseStepCommon(reader, fields, context) {
|
|
495
|
-
const name = reader.optionalString(fields, "name", context);
|
|
385
|
+
reader.optionalString(fields, "name", context);
|
|
496
386
|
const env = parseScalarMap(reader, fields.get("env"), `${context}.env`, ENV_KEY, false);
|
|
497
|
-
|
|
387
|
+
const target = usesPair
|
|
388
|
+
? parseUsesStep(reader, usesPair, fields)
|
|
389
|
+
: parseRunStep(reader, runPair, fields, options);
|
|
390
|
+
const spec = { ...target, ...(env ? { env } : {}), source: reader.span(node) };
|
|
391
|
+
return {
|
|
392
|
+
stepId: id,
|
|
393
|
+
title: id,
|
|
394
|
+
sequenceIndex: index,
|
|
395
|
+
spec,
|
|
396
|
+
gate: { kind: "gate", id: `${id}.gate`, stepId: id, criteria: [], maxLoops: 1, frozenJudge: null },
|
|
397
|
+
};
|
|
498
398
|
}
|
|
499
|
-
function parseUsesStep(reader, usesPair, fields
|
|
399
|
+
function parseUsesStep(reader, usesPair, fields) {
|
|
500
400
|
if (fields.has("shell") || fields.has("working-directory")) {
|
|
501
401
|
reader.fail("uses-field-conflict", "shell and working-directory are legal only with run.", usesPair.value);
|
|
502
402
|
}
|
|
503
403
|
const uses = reader.string(usesPair.value, "step.uses");
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
//
|
|
512
|
-
//
|
|
513
|
-
// keeps the
|
|
404
|
+
let target;
|
|
405
|
+
try {
|
|
406
|
+
target = classifyWorkflowStepUses(uses);
|
|
407
|
+
}
|
|
408
|
+
catch (cause) {
|
|
409
|
+
semanticReaderFail(reader, cause, usesPair.value);
|
|
410
|
+
}
|
|
411
|
+
// A tasks/<ref> or workflows/<ref> step's with: may bind any JSON value the
|
|
412
|
+
// composed target's declared input/param needs (an object/array literal, or
|
|
413
|
+
// a {from: "..."} reference); every other target keeps the scalar grammar.
|
|
514
414
|
const withValues = target.kind === "task" || target.kind === "workflow"
|
|
515
415
|
? parsePlainMap(reader, fields.get("with"), "step.with", INPUT_KEY)
|
|
516
416
|
: parseScalarMap(reader, fields.get("with"), "step.with", INPUT_KEY, true);
|
|
@@ -518,20 +418,11 @@ function parseUsesStep(reader, usesPair, fields, options, common) {
|
|
|
518
418
|
? validateBuiltinCommand(reader, withValues, fields.get("with")?.value ?? usesPair.value)
|
|
519
419
|
: undefined;
|
|
520
420
|
return {
|
|
521
|
-
...common,
|
|
522
421
|
uses,
|
|
523
422
|
...(commandMode ? { commandMode } : {}),
|
|
524
423
|
...(withValues ? { with: withValues } : {}),
|
|
525
424
|
};
|
|
526
425
|
}
|
|
527
|
-
function classifyUses(reader, uses, node, classifier) {
|
|
528
|
-
try {
|
|
529
|
-
return classifyWorkflowStepUses(uses, classifier);
|
|
530
|
-
}
|
|
531
|
-
catch (cause) {
|
|
532
|
-
semanticReaderFail(reader, cause, node);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
426
|
function validateBuiltinCommand(reader, values, node) {
|
|
536
427
|
try {
|
|
537
428
|
const action = validateWorkflowBuiltinCommand(values);
|
|
@@ -543,7 +434,8 @@ function validateBuiltinCommand(reader, values, node) {
|
|
|
543
434
|
semanticReaderFail(reader, cause, node);
|
|
544
435
|
}
|
|
545
436
|
}
|
|
546
|
-
|
|
437
|
+
/** A `run:` step lowers to its shell's argv now; `instructions` keeps the authored command for display. */
|
|
438
|
+
function parseRunStep(reader, runPair, fields, options) {
|
|
547
439
|
if (fields.has("with"))
|
|
548
440
|
reader.fail("run-field-conflict", "with is legal only with uses.", fields.get("with")?.value);
|
|
549
441
|
let run;
|
|
@@ -568,10 +460,8 @@ function parseRunStep(reader, runPair, fields, options, common) {
|
|
|
568
460
|
}
|
|
569
461
|
}
|
|
570
462
|
return {
|
|
571
|
-
...
|
|
572
|
-
run
|
|
573
|
-
...(shell ? { shell: shell } : {}),
|
|
574
|
-
...(workingDirectory ? { workingDirectory } : {}),
|
|
463
|
+
exec: { command: workflowShellCommand(shell ?? "sh", run), ...(workingDirectory ? { cwd: workingDirectory } : {}) },
|
|
464
|
+
instructions: `Run ${run}.`,
|
|
575
465
|
};
|
|
576
466
|
}
|
|
577
467
|
function parseScalarMap(reader, pair, context, keyPattern, allowNull) {
|
|
@@ -586,15 +476,7 @@ function parseScalarMap(reader, pair, context, keyPattern, allowNull) {
|
|
|
586
476
|
}
|
|
587
477
|
return out;
|
|
588
478
|
}
|
|
589
|
-
/**
|
|
590
|
-
* Like {@link parseScalarMap} but accepts an arbitrary JSON value per key —
|
|
591
|
-
* a task-composition with: binding may be the declared input's own shape (an
|
|
592
|
-
* object/array literal, or a `{from: "..."}` reference), not just a scalar
|
|
593
|
-
* (A-N3). Depth/node bounds are already enforced document-wide by
|
|
594
|
-
* `checkTree`/`rejectAliases` before any field-level parsing runs, so this
|
|
595
|
-
* adds no new bound. `decodeWorkflowSourceIrV1` (schema.ts) decides what a
|
|
596
|
-
* declared input actually accepts.
|
|
597
|
-
*/
|
|
479
|
+
/** Like {@link parseScalarMap} but any JSON value per key (bounded document-wide by `checkTree`). */
|
|
598
480
|
function parsePlainMap(reader, pair, context, keyPattern) {
|
|
599
481
|
if (!pair)
|
|
600
482
|
return undefined;
|
|
@@ -2,33 +2,13 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
* Run-parameter validation against the frozen plan's param schemas
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* flowing into a unit prompt. The schemas are frozen into the plan, so
|
|
9
|
-
* validation is a pure function of the frozen plan and supplied params.
|
|
10
|
-
*
|
|
11
|
-
* P2a (docs/plans/specs/p2a-task-source-v4.md §4.3, D3): this module is now a
|
|
12
|
-
* THIN CONSUMER of the shared input contract, `src/execution/input-contract.ts`
|
|
13
|
-
* (§4, D3, D3-N1/D3-N2/D3-N3). Every export below keeps its existing name,
|
|
14
|
-
* signature, message, code, and hint byte-identically —
|
|
15
|
-
* `tests/workflows/workflow-param-flags.test.ts` and
|
|
16
|
-
* `tests/integration/workflows/params-validation.test.ts` pin that with zero
|
|
17
|
-
* diff. `contractFromPlan` adapts a `WorkflowParameterPlan` into an
|
|
18
|
-
* `InputContract` (every declared param, `required: false` — workflow params
|
|
19
|
-
* declare nothing required). `WORKFLOW_PARAMETER_DIAGNOSTICS` reproduces
|
|
20
|
-
* today's five workflow-parameter messages/codes for the shared
|
|
21
|
-
* `materializeInputFlags` (D3-N3); its `contractViolation` formatter
|
|
22
|
-
* re-roots each `"$"`-prefixed error from the shared module's internal check
|
|
23
|
-
* to `"params."`, matching what `validateWorkflowParams` (called directly,
|
|
24
|
-
* already `"params."`-rooted) has always produced. No coercion or validation
|
|
25
|
-
* logic lives in this file — it lives once, in the shared module.
|
|
26
|
-
*
|
|
27
|
-
* Pure module: no IO, no engine imports.
|
|
5
|
+
* Run-parameter validation against the frozen plan's param schemas, a thin
|
|
6
|
+
* consumer of the shared input contract (`src/execution/input-contract.ts`):
|
|
7
|
+
* every declared param is optional, and the messages are the workflow ones.
|
|
28
8
|
*/
|
|
29
9
|
import { UsageError } from "../../core/errors.js";
|
|
30
10
|
import { materializeInputFlags, validateInputs, } from "../../execution/input-contract.js";
|
|
31
|
-
/** Every declared workflow param as an `InputDeclaration`, `required: false` — workflow params declare nothing required
|
|
11
|
+
/** Every declared workflow param as an `InputDeclaration`, `required: false` — workflow params declare nothing required. */
|
|
32
12
|
function contractFromPlan(plan) {
|
|
33
13
|
const names = plan.params ?? Object.keys(plan.paramSchemas ?? {});
|
|
34
14
|
const contract = {};
|
|
@@ -37,16 +17,7 @@ function contractFromPlan(plan) {
|
|
|
37
17
|
}
|
|
38
18
|
return contract;
|
|
39
19
|
}
|
|
40
|
-
/**
|
|
41
|
-
* `contractFromPlan`, exported under its P3a-facing name (spec
|
|
42
|
-
* docs/plans/specs/p3a-plan-v5-child-freeze.md A-N8): a child workflow has no
|
|
43
|
-
* `inputs:` contract of its own (that is task source v4's vocabulary) — it
|
|
44
|
-
* declares `params:`, and this is the SAME adapter this file already uses
|
|
45
|
-
* for run-parameter validation, reused so `freezeTaskInputBindings`
|
|
46
|
-
* (`src/workflows/freeze/task-bindings.ts`, generic over `InputContract`) has
|
|
47
|
-
* exactly one normalizer for every binding surface. Additive; no behavior
|
|
48
|
-
* change to this file's own exports.
|
|
49
|
-
*/
|
|
20
|
+
/** A child workflow's `params:` as an input contract, so one normalizer binds every composition surface. */
|
|
50
21
|
export { contractFromPlan as workflowParamContract };
|
|
51
22
|
function invalidParameter(name, message) {
|
|
52
23
|
return new UsageError(`Workflow parameter "--${name}" ${message}.`, "INVALID_FLAG_VALUE");
|
|
@@ -81,25 +52,9 @@ export function materializeWorkflowParameterFlags(plan, flags) {
|
|
|
81
52
|
*/
|
|
82
53
|
export function validateWorkflowParams(plan, params) {
|
|
83
54
|
// A plan with no schemas must not start emitting `properties: {}` noise —
|
|
84
|
-
// preserved as an explicit early return
|
|
55
|
+
// preserved as an explicit early return, even
|
|
85
56
|
// though an empty contract would validate to `[]` regardless.
|
|
86
57
|
if (!plan.paramSchemas || Object.keys(plan.paramSchemas).length === 0)
|
|
87
58
|
return [];
|
|
88
59
|
return validateInputs(contractFromPlan(plan), params, { pathRoot: "params" });
|
|
89
60
|
}
|
|
90
|
-
/**
|
|
91
|
-
* Run-integrity assert (reviewer #12): the journaled `params_json`
|
|
92
|
-
* row must STILL satisfy the frozen param schemas. `startWorkflowRun` already
|
|
93
|
-
* validated the params it stored, so a violation here means the row was edited
|
|
94
|
-
* after the run started — loud corruption, exactly like the frozen-plan hash
|
|
95
|
-
* mismatch and the tampered-params replay-divergence path. Refuse to describe
|
|
96
|
-
* or drive the run rather than resolve prompts from schema-violating params.
|
|
97
|
-
*/
|
|
98
|
-
export function assertRunParamsSatisfyPlan(runId, plan, params) {
|
|
99
|
-
const errors = validateWorkflowParams(plan, params);
|
|
100
|
-
if (errors.length === 0)
|
|
101
|
-
return;
|
|
102
|
-
throw new UsageError(`Workflow run ${runId} failed the frozen param-schema integrity check: the journaled params row no longer ` +
|
|
103
|
-
`satisfies the workflow's declared parameter schemas (edited after the run started). Refusing to execute it. ` +
|
|
104
|
-
`Start a new run.\n${errors.map((e) => ` - ${e}`).join("\n")}`);
|
|
105
|
-
}
|