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
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
-
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
-
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
/**
|
|
5
|
-
* Durable-v4 symbolic workflow environments.
|
|
6
|
-
*
|
|
7
|
-
* Env-file values are the deliberately narrow live-value exception to a
|
|
8
|
-
* frozen workflow plan. Freeze persists only the qualified owner, physical
|
|
9
|
-
* containment, exact key set, and secret-token topology. Materialization
|
|
10
|
-
* later reads current values directly through that descriptor, without
|
|
11
|
-
* consulting config, the index, or authored workflow source.
|
|
12
|
-
*/
|
|
13
|
-
import fs from "node:fs";
|
|
14
|
-
import path from "node:path";
|
|
15
|
-
import dotenv from "dotenv";
|
|
16
|
-
import { assetPathForName } from "../../core/asset/asset-placement.js";
|
|
17
|
-
import { isWithin } from "../../core/common.js";
|
|
18
|
-
import { NotFoundError, UsageError } from "../../core/errors.js";
|
|
19
|
-
import { warn } from "../../core/warn.js";
|
|
20
|
-
import { captureGuardedExecutionSource, GuardedExecutionSourceCollector } from "../../execution/guarded-source.js";
|
|
21
|
-
const SECRET_TOKEN_RE = /\$\{secret:([A-Za-z0-9_./-]+)\}/g;
|
|
22
|
-
const ENVIRONMENT_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
23
|
-
const QUALIFIED_ENV_REF_RE = /^([^/]+)\/\/env\/(.+)$/;
|
|
24
|
-
/** Freeze value-free descriptors in authored ref order. */
|
|
25
|
-
export function freezeWorkflowEnvironment(refs, options) {
|
|
26
|
-
const collector = options.collector ?? new GuardedExecutionSourceCollector();
|
|
27
|
-
const logical = new Set();
|
|
28
|
-
const physical = new Map();
|
|
29
|
-
const out = [];
|
|
30
|
-
for (const [precedence, inputRef] of refs.entries()) {
|
|
31
|
-
const resolved = options.resolveRef(inputRef);
|
|
32
|
-
const match = QUALIFIED_ENV_REF_RE.exec(resolved.ref);
|
|
33
|
-
if (!match || match[1] !== resolved.bundle) {
|
|
34
|
-
throw new UsageError(`Workflow env ref ${JSON.stringify(inputRef)} did not resolve to a canonical fully-qualified owner.`, "WORKFLOW_SOURCE_INVALID");
|
|
35
|
-
}
|
|
36
|
-
if (logical.has(resolved.ref)) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
logical.add(resolved.ref);
|
|
40
|
-
trackParentDirectories(collector, resolved.root, resolved.path);
|
|
41
|
-
const retained = collector.capture(resolved.path, resolved.root, { authored: true });
|
|
42
|
-
const captured = collector.bindIdentity(resolved.path, resolved.root, {
|
|
43
|
-
ref: resolved.ref,
|
|
44
|
-
bundle: resolved.bundle,
|
|
45
|
-
adapter: resolved.adapter,
|
|
46
|
-
file: retained.relativePath,
|
|
47
|
-
hash: retained.sha256,
|
|
48
|
-
});
|
|
49
|
-
const physicalKey = `${captured.containmentPhysicalIdentity}\0${captured.physicalIdentity}`;
|
|
50
|
-
const alias = physical.get(physicalKey);
|
|
51
|
-
if (alias !== undefined && alias !== resolved.ref) {
|
|
52
|
-
warn(`Workflow env ref ${resolved.ref} aliases the same physical environment source as ${alias} under a different logical owner. Using ${alias}.`);
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
physical.set(physicalKey, resolved.ref);
|
|
56
|
-
const parsed = dotenv.parse(Buffer.from(captured.bytesBase64, "base64"));
|
|
57
|
-
const keys = sortedCodePoints(Object.keys(parsed));
|
|
58
|
-
const secretNames = secretTokenNames(parsed);
|
|
59
|
-
out.push(Object.freeze({
|
|
60
|
-
kind: "env-ref",
|
|
61
|
-
ref: resolved.ref,
|
|
62
|
-
owner: Object.freeze({
|
|
63
|
-
bundle: resolved.bundle,
|
|
64
|
-
adapter: resolved.adapter,
|
|
65
|
-
requestedRoot: captured.containmentRoot,
|
|
66
|
-
realRoot: captured.containmentRealPath,
|
|
67
|
-
rootPhysicalIdentity: captured.containmentPhysicalIdentity,
|
|
68
|
-
requestedPath: captured.sourcePath,
|
|
69
|
-
realPath: captured.realPath,
|
|
70
|
-
relativePath: captured.relativePath,
|
|
71
|
-
}),
|
|
72
|
-
keys: Object.freeze(keys),
|
|
73
|
-
secretNames: Object.freeze(secretNames),
|
|
74
|
-
precedence,
|
|
75
|
-
}));
|
|
76
|
-
}
|
|
77
|
-
return out;
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Materialize all current values atomically from frozen descriptors. Nothing
|
|
81
|
-
* is returned until every owner/key/token check and every secret lookup has
|
|
82
|
-
* succeeded.
|
|
83
|
-
*/
|
|
84
|
-
export function materializeFrozenWorkflowEnvironment(descriptors, options = {}) {
|
|
85
|
-
const values = {};
|
|
86
|
-
const sensitive = new Set();
|
|
87
|
-
const audits = [];
|
|
88
|
-
const seenRefs = new Set();
|
|
89
|
-
let priorPrecedence = -1;
|
|
90
|
-
for (const descriptor of descriptors) {
|
|
91
|
-
if (!descriptor || typeof descriptor !== "object")
|
|
92
|
-
invalid("environment descriptor must be an object");
|
|
93
|
-
if (descriptor.kind === "literal") {
|
|
94
|
-
exactKeys(descriptor, ["kind", "name", "value"]);
|
|
95
|
-
environmentName(descriptor.name);
|
|
96
|
-
if (typeof descriptor.value !== "string")
|
|
97
|
-
invalid("literal environment value must be a string");
|
|
98
|
-
values[descriptor.name] = descriptor.value;
|
|
99
|
-
if (descriptor.value)
|
|
100
|
-
sensitive.add(descriptor.value);
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
if (descriptor.kind === "pass-through") {
|
|
104
|
-
exactKeys(descriptor, ["kind", "name"]);
|
|
105
|
-
environmentName(descriptor.name);
|
|
106
|
-
const value = options.readPassThrough ? options.readPassThrough(descriptor.name) : process.env[descriptor.name];
|
|
107
|
-
if (value !== undefined) {
|
|
108
|
-
values[descriptor.name] = value;
|
|
109
|
-
if (value)
|
|
110
|
-
sensitive.add(value);
|
|
111
|
-
}
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
if (descriptor.kind !== "env-ref")
|
|
115
|
-
invalid("environment descriptor has an unsupported kind");
|
|
116
|
-
exactKeys(descriptor, ["kind", "ref", "owner", "keys", "secretNames", "precedence"]);
|
|
117
|
-
validateEnvRefDescriptor(descriptor);
|
|
118
|
-
if (seenRefs.has(descriptor.ref))
|
|
119
|
-
invalid(`duplicate environment ref ${descriptor.ref}`);
|
|
120
|
-
if (descriptor.precedence <= priorPrecedence)
|
|
121
|
-
invalid("env-ref precedence must be strictly increasing");
|
|
122
|
-
seenRefs.add(descriptor.ref);
|
|
123
|
-
priorPrecedence = descriptor.precedence;
|
|
124
|
-
const source = options.readEnvFile ? options.readEnvFile(descriptor) : readFrozenEnvironmentFile(descriptor.owner);
|
|
125
|
-
const parsed = dotenv.parse(typeof source === "string" ? source : Buffer.from(source));
|
|
126
|
-
const keys = sortedCodePoints(Object.keys(parsed));
|
|
127
|
-
const tokenNames = secretTokenNames(parsed);
|
|
128
|
-
if (!sameStrings(keys, descriptor.keys)) {
|
|
129
|
-
invalid(`environment ${descriptor.ref} key set changed after it was frozen`);
|
|
130
|
-
}
|
|
131
|
-
if (!sameStrings(tokenNames, descriptor.secretNames)) {
|
|
132
|
-
invalid(`environment ${descriptor.ref} secret-token topology changed after it was frozen`);
|
|
133
|
-
}
|
|
134
|
-
const secretValues = new Map();
|
|
135
|
-
for (const name of descriptor.secretNames) {
|
|
136
|
-
const raw = options.readSecret
|
|
137
|
-
? options.readSecret({ name, descriptor })
|
|
138
|
-
: readFrozenSecret(descriptor.owner, name);
|
|
139
|
-
if (raw === undefined) {
|
|
140
|
-
throw new NotFoundError(`Environment ${descriptor.ref} references missing secret ${name}; nothing was materialized.`, "FILE_NOT_FOUND");
|
|
141
|
-
}
|
|
142
|
-
const value = typeof raw === "string" ? raw : Buffer.from(raw).toString("utf8");
|
|
143
|
-
secretValues.set(name, value);
|
|
144
|
-
if (value)
|
|
145
|
-
sensitive.add(value);
|
|
146
|
-
}
|
|
147
|
-
for (const [key, rawValue] of Object.entries(parsed)) {
|
|
148
|
-
const resolved = rawValue.replace(SECRET_TOKEN_RE, (_token, name) => {
|
|
149
|
-
const secret = secretValues.get(name);
|
|
150
|
-
if (secret === undefined)
|
|
151
|
-
invalid(`environment ${descriptor.ref} secret ${name} was not materialized`);
|
|
152
|
-
return secret;
|
|
153
|
-
});
|
|
154
|
-
values[key] = resolved;
|
|
155
|
-
if (resolved)
|
|
156
|
-
sensitive.add(resolved);
|
|
157
|
-
}
|
|
158
|
-
audits.push(Object.freeze({
|
|
159
|
-
eventType: "env_access",
|
|
160
|
-
ref: descriptor.ref,
|
|
161
|
-
keys: Object.freeze([...descriptor.keys]),
|
|
162
|
-
secretNames: Object.freeze([...descriptor.secretNames]),
|
|
163
|
-
}));
|
|
164
|
-
}
|
|
165
|
-
return {
|
|
166
|
-
values,
|
|
167
|
-
sensitiveValues: [...sensitive],
|
|
168
|
-
audits,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
function validateEnvRefDescriptor(descriptor) {
|
|
172
|
-
const match = QUALIFIED_ENV_REF_RE.exec(descriptor.ref);
|
|
173
|
-
if (!match || match[1] !== descriptor.owner.bundle)
|
|
174
|
-
invalid("env-ref has a noncanonical qualified owner");
|
|
175
|
-
exactKeys(descriptor.owner, [
|
|
176
|
-
"bundle",
|
|
177
|
-
"adapter",
|
|
178
|
-
"requestedRoot",
|
|
179
|
-
"realRoot",
|
|
180
|
-
"rootPhysicalIdentity",
|
|
181
|
-
"requestedPath",
|
|
182
|
-
"realPath",
|
|
183
|
-
"relativePath",
|
|
184
|
-
]);
|
|
185
|
-
for (const value of [descriptor.owner.bundle, descriptor.owner.adapter, descriptor.owner.rootPhysicalIdentity]) {
|
|
186
|
-
if (typeof value !== "string" || !value)
|
|
187
|
-
invalid("env-ref owner identity is incomplete");
|
|
188
|
-
}
|
|
189
|
-
for (const value of [
|
|
190
|
-
descriptor.owner.requestedRoot,
|
|
191
|
-
descriptor.owner.realRoot,
|
|
192
|
-
descriptor.owner.requestedPath,
|
|
193
|
-
descriptor.owner.realPath,
|
|
194
|
-
]) {
|
|
195
|
-
if (typeof value !== "string" || !path.isAbsolute(value))
|
|
196
|
-
invalid("env-ref owner paths must be absolute");
|
|
197
|
-
}
|
|
198
|
-
const relative = descriptor.owner.relativePath;
|
|
199
|
-
if (typeof relative !== "string" ||
|
|
200
|
-
!relative ||
|
|
201
|
-
relative.includes("\\") ||
|
|
202
|
-
relative.startsWith("../") ||
|
|
203
|
-
path.isAbsolute(relative)) {
|
|
204
|
-
invalid("env-ref owner relative path is noncanonical");
|
|
205
|
-
}
|
|
206
|
-
if (path.resolve(descriptor.owner.requestedRoot, relative) !== path.resolve(descriptor.owner.requestedPath)) {
|
|
207
|
-
invalid("env-ref requested path does not match its owner");
|
|
208
|
-
}
|
|
209
|
-
if (path.resolve(descriptor.owner.realRoot, relative) !== path.resolve(descriptor.owner.realPath)) {
|
|
210
|
-
invalid("env-ref real path does not match its owner");
|
|
211
|
-
}
|
|
212
|
-
sortedUnique(descriptor.keys, "env-ref keys", ENVIRONMENT_NAME_RE);
|
|
213
|
-
sortedUnique(descriptor.secretNames, "env-ref secret names", /^[A-Za-z0-9_./-]+$/);
|
|
214
|
-
if (!Number.isSafeInteger(descriptor.precedence) || descriptor.precedence < 0) {
|
|
215
|
-
invalid("env-ref precedence is invalid");
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
function readFrozenEnvironmentFile(owner) {
|
|
219
|
-
const rootLstat = fs.lstatSync(owner.requestedRoot, { bigint: true });
|
|
220
|
-
if (rootLstat.isSymbolicLink() || !rootLstat.isDirectory())
|
|
221
|
-
invalid("environment owner root physical identity changed");
|
|
222
|
-
const currentRealRoot = fs.realpathSync(owner.requestedRoot);
|
|
223
|
-
if (currentRealRoot !== owner.realRoot ||
|
|
224
|
-
physicalIdentity(currentRealRoot, rootLstat) !== owner.rootPhysicalIdentity) {
|
|
225
|
-
invalid("environment owner root physical identity changed");
|
|
226
|
-
}
|
|
227
|
-
const captured = captureGuardedExecutionSource(owner.requestedPath, owner.requestedRoot, { authored: true });
|
|
228
|
-
if (captured.realPath !== owner.realPath ||
|
|
229
|
-
captured.relativePath !== owner.relativePath ||
|
|
230
|
-
captured.containmentRealPath !== owner.realRoot ||
|
|
231
|
-
captured.containmentPhysicalIdentity !== owner.rootPhysicalIdentity) {
|
|
232
|
-
invalid("environment owner/path physical identity changed");
|
|
233
|
-
}
|
|
234
|
-
return Buffer.from(captured.bytesBase64, "base64");
|
|
235
|
-
}
|
|
236
|
-
function readFrozenSecret(owner, name) {
|
|
237
|
-
const secretsRoot = path.join(owner.requestedRoot, "secrets");
|
|
238
|
-
const secretPath = assetPathForName("secret", secretsRoot, name);
|
|
239
|
-
if (!isWithin(secretPath, secretsRoot))
|
|
240
|
-
invalid(`secret name ${name} escapes its frozen owner`);
|
|
241
|
-
let descriptor;
|
|
242
|
-
try {
|
|
243
|
-
const noFollow = typeof fs.constants.O_NOFOLLOW === "number" ? fs.constants.O_NOFOLLOW : 0;
|
|
244
|
-
descriptor = fs.openSync(secretPath, fs.constants.O_RDONLY | noFollow);
|
|
245
|
-
const before = fs.fstatSync(descriptor, { bigint: true });
|
|
246
|
-
if (!before.isFile())
|
|
247
|
-
invalid(`secret ${name} is not a regular file`);
|
|
248
|
-
const bytes = fs.readFileSync(descriptor);
|
|
249
|
-
const after = fs.fstatSync(descriptor, { bigint: true });
|
|
250
|
-
if (before.dev !== after.dev ||
|
|
251
|
-
before.ino !== after.ino ||
|
|
252
|
-
before.size !== after.size ||
|
|
253
|
-
before.mtimeNs !== after.mtimeNs) {
|
|
254
|
-
invalid(`secret ${name} changed while it was read`);
|
|
255
|
-
}
|
|
256
|
-
return bytes;
|
|
257
|
-
}
|
|
258
|
-
catch (cause) {
|
|
259
|
-
if (cause.code === "ENOENT")
|
|
260
|
-
return undefined;
|
|
261
|
-
throw cause;
|
|
262
|
-
}
|
|
263
|
-
finally {
|
|
264
|
-
if (descriptor !== undefined)
|
|
265
|
-
fs.closeSync(descriptor);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
function trackParentDirectories(collector, rootInput, fileInput) {
|
|
269
|
-
const root = path.resolve(rootInput);
|
|
270
|
-
const parent = path.dirname(path.resolve(fileInput));
|
|
271
|
-
const relative = path.relative(root, parent);
|
|
272
|
-
if (relative.startsWith("..") || path.isAbsolute(relative))
|
|
273
|
-
invalid("environment source escapes its owner root");
|
|
274
|
-
let current = root;
|
|
275
|
-
collector.trackDirectory(current, root);
|
|
276
|
-
if (relative === "")
|
|
277
|
-
return;
|
|
278
|
-
for (const segment of relative.split(path.sep)) {
|
|
279
|
-
current = path.join(current, segment);
|
|
280
|
-
collector.trackDirectory(current, root);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
function secretTokenNames(values) {
|
|
284
|
-
const names = new Set();
|
|
285
|
-
for (const value of Object.values(values)) {
|
|
286
|
-
for (const match of value.matchAll(SECRET_TOKEN_RE)) {
|
|
287
|
-
const name = match[1];
|
|
288
|
-
if (name)
|
|
289
|
-
names.add(name);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
return sortedCodePoints([...names]);
|
|
293
|
-
}
|
|
294
|
-
function sortedCodePoints(values) {
|
|
295
|
-
return values.sort((left, right) => (left < right ? -1 : left > right ? 1 : 0));
|
|
296
|
-
}
|
|
297
|
-
function sortedUnique(values, label, pattern) {
|
|
298
|
-
if (!Array.isArray(values))
|
|
299
|
-
invalid(`${label} must be an array`);
|
|
300
|
-
let prior;
|
|
301
|
-
for (const value of values) {
|
|
302
|
-
if (typeof value !== "string" || !pattern.test(value) || value.includes(".."))
|
|
303
|
-
invalid(`${label} is invalid`);
|
|
304
|
-
if (prior !== undefined && prior >= value)
|
|
305
|
-
invalid(`${label} must be sorted and unique`);
|
|
306
|
-
prior = value;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
function sameStrings(left, right) {
|
|
310
|
-
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
311
|
-
}
|
|
312
|
-
function exactKeys(value, keys) {
|
|
313
|
-
const allowed = new Set(keys);
|
|
314
|
-
for (const key of Object.keys(value))
|
|
315
|
-
if (!allowed.has(key))
|
|
316
|
-
invalid(`environment descriptor contains unknown key ${key}`);
|
|
317
|
-
for (const key of keys)
|
|
318
|
-
if (!Object.hasOwn(value, key))
|
|
319
|
-
invalid(`environment descriptor is missing ${key}`);
|
|
320
|
-
}
|
|
321
|
-
function environmentName(value) {
|
|
322
|
-
if (typeof value !== "string" || !ENVIRONMENT_NAME_RE.test(value))
|
|
323
|
-
invalid("environment name is invalid");
|
|
324
|
-
}
|
|
325
|
-
function physicalIdentity(realPath, stat) {
|
|
326
|
-
return stat.ino === 0n ? `path:${realPath}` : `inode:${stat.dev}:${stat.ino}`;
|
|
327
|
-
}
|
|
328
|
-
function invalid(message) {
|
|
329
|
-
throw new UsageError(`Invalid frozen workflow environment: ${message}.`, "WORKFLOW_SOURCE_INVALID");
|
|
330
|
-
}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
-
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
-
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { createHash } from "node:crypto";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { parseBundleRef } from "../../core/asset/asset-ref.js";
|
|
7
|
-
import { COMPOSITION_INVALID_MULTI_JOB_HINT, UsageError } from "../../core/errors.js";
|
|
8
|
-
import { GuardedExecutionSourceCollector } from "../../execution/guarded-source.js";
|
|
9
|
-
import { defaultMapConcurrency, workflowMaxConcurrency } from "../concurrency-policy.js";
|
|
10
|
-
import { assertChildOutputReferences } from "../freeze/child-output-references.js";
|
|
11
|
-
import { resolveWorkflowSourceV4 } from "../freeze/source-freeze.js";
|
|
12
|
-
import { compileWorkflowPlan } from "./compile.js";
|
|
13
|
-
import { canonicalJson } from "./plan-hash.js";
|
|
14
|
-
import { decodeWorkflowPlanV4, WORKFLOW_IR_V5_VERSION, } from "./schema-v4.js";
|
|
15
|
-
/** Compile, resolve, and freeze one executable plan without publishing any state. */
|
|
16
|
-
export async function compileResolveFreezeWorkflowV4(asset, config, options = {}) {
|
|
17
|
-
const sourceCollector = options.sourceCollector ?? new GuardedExecutionSourceCollector();
|
|
18
|
-
const composition = options.composition ?? {
|
|
19
|
-
depth: 0,
|
|
20
|
-
refPath: [asset.ref],
|
|
21
|
-
budget: { embeddedBytes: 0 },
|
|
22
|
-
};
|
|
23
|
-
// Injected rather than imported (A-N7/step-values.ts's `ChildCompositionContext`
|
|
24
|
-
// doc): `targets/child-workflow.ts` is downstream of this module (via
|
|
25
|
-
// `resolve-steps.ts` <- `source-freeze.ts`, imported directly above — the
|
|
26
|
-
// `source-freeze-v4.ts` shim P4 deleted used to sit on this edge), so it
|
|
27
|
-
// cannot import `compileResolveFreezeWorkflowV4` directly without closing
|
|
28
|
-
// a static import cycle
|
|
29
|
-
// (tests/architecture/import-cycle-ratchet.test.ts, shrink-only, empty
|
|
30
|
-
// baseline). This closure is this function's own recursive call, passed
|
|
31
|
-
// down as a plain value through `ResolutionContext.freezeChild`.
|
|
32
|
-
const freezeChild = async (request) => {
|
|
33
|
-
const child = await compileResolveFreezeWorkflowV4(request.asset, config, {
|
|
34
|
-
sourceCollector: request.sourceCollector,
|
|
35
|
-
composition: request.composition,
|
|
36
|
-
});
|
|
37
|
-
return { plan: child.plan, sourceCollector: child.sourceCollector };
|
|
38
|
-
};
|
|
39
|
-
const workflowSource = captureWorkflowSource(asset, sourceCollector);
|
|
40
|
-
const resolved = await resolveWorkflowSourceV4(asset, workflowSource, config, sourceCollector, composition, freezeChild);
|
|
41
|
-
const compiled = compileWorkflowPlan(resolved.sourceIr, asset.title, resolved.units);
|
|
42
|
-
if (!compiled.ok) {
|
|
43
|
-
// P4-N2's mapping (docs/plans/specs/p4-deletions-closeout.md §3.3.4)
|
|
44
|
-
// applies here too, though `resolved.sourceIr` is already guaranteed
|
|
45
|
-
// exactly one job by this point (source-freeze.ts's own compile already
|
|
46
|
-
// succeeded), so this compiler's own errors never carry the
|
|
47
|
-
// multi-job-unsupported code — the arm always resolves to
|
|
48
|
-
// WORKFLOW_SOURCE_INVALID.
|
|
49
|
-
const isMultiJob = compiled.errors.length === 1 && compiled.errors[0]?.code === "multi-job-unsupported";
|
|
50
|
-
const code = isMultiJob ? "COMPOSITION_INVALID" : "WORKFLOW_SOURCE_INVALID";
|
|
51
|
-
throw new UsageError(compiled.errors.map((error) => `${asset.path}:${error.line}: ${error.message}`).join("\n"), code, isMultiJob ? COMPOSITION_INVALID_MULTI_JOB_HINT : undefined);
|
|
52
|
-
}
|
|
53
|
-
const steps = compiled.plan.steps.map((step) => {
|
|
54
|
-
const frozenJudge = step.gate.criteria.length === 0 ? null : (resolved.judges.get(step.stepId) ?? null);
|
|
55
|
-
const gate = Object.freeze({ ...step.gate, maxLoops: step.gate.maxLoops ?? 1, frozenJudge });
|
|
56
|
-
if (!step.root) {
|
|
57
|
-
const { root: _root, ...withoutRoot } = step;
|
|
58
|
-
return Object.freeze({ ...withoutRoot, gate });
|
|
59
|
-
}
|
|
60
|
-
const frozen = resolved.units.get(step.stepId);
|
|
61
|
-
if (!frozen)
|
|
62
|
-
throw new Error(`resolved workflow target missing for step ${step.stepId}`);
|
|
63
|
-
const root = step.root.kind === "map"
|
|
64
|
-
? {
|
|
65
|
-
...step.root,
|
|
66
|
-
concurrency: step.root.concurrency ?? defaultMapConcurrency(config.workflow?.defaultMapConcurrency),
|
|
67
|
-
template: freezeResolvedUnit(step.root.template, frozen),
|
|
68
|
-
}
|
|
69
|
-
: freezeResolvedUnit(step.root, frozen);
|
|
70
|
-
return Object.freeze({ ...step, root, gate });
|
|
71
|
-
});
|
|
72
|
-
// P3b, spec §4.4: after every step's target is resolved (so every embedded
|
|
73
|
-
// child plan is available) and before the plan object is assembled.
|
|
74
|
-
assertChildOutputReferences(steps);
|
|
75
|
-
const sourceReadSet = sourceCollector
|
|
76
|
-
.snapshot()
|
|
77
|
-
.sources.filter((source) => Boolean(source.identity))
|
|
78
|
-
.map((source) => sourceSnapshot(source));
|
|
79
|
-
const plan = decodeWorkflowPlanV4({
|
|
80
|
-
irVersion: WORKFLOW_IR_V5_VERSION,
|
|
81
|
-
title: compiled.plan.title,
|
|
82
|
-
...(compiled.plan.params ? { params: compiled.plan.params } : {}),
|
|
83
|
-
...(compiled.plan.paramSchemas ? { paramSchemas: compiled.plan.paramSchemas } : {}),
|
|
84
|
-
...(compiled.plan.budget ? { budget: compiled.plan.budget } : {}),
|
|
85
|
-
execution: { maxConcurrency: workflowMaxConcurrency(config.workflow?.maxConcurrency) },
|
|
86
|
-
sourceReadSet,
|
|
87
|
-
steps,
|
|
88
|
-
...(compiled.plan.outputs ? { outputs: compiled.plan.outputs } : {}),
|
|
89
|
-
});
|
|
90
|
-
return Object.freeze({
|
|
91
|
-
plan,
|
|
92
|
-
warnings: compiled.warnings,
|
|
93
|
-
...(resolved.engineAnnouncement ? { engineAnnouncement: resolved.engineAnnouncement } : {}),
|
|
94
|
-
sourceCollector,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
function freezeResolvedUnit(unit, resolved) {
|
|
98
|
-
const frozenTarget = resolved.target.kind === "shell"
|
|
99
|
-
? Object.freeze({
|
|
100
|
-
...resolved.target,
|
|
101
|
-
contentHash: createHash("sha256")
|
|
102
|
-
.update("akm.workflow.shell.v1\0")
|
|
103
|
-
.update(canonicalJson({
|
|
104
|
-
exec: resolved.target.exec,
|
|
105
|
-
environment: resolved.environment,
|
|
106
|
-
cwdIdentity: resolved.target.cwdIdentity,
|
|
107
|
-
}))
|
|
108
|
-
.digest("hex"),
|
|
109
|
-
})
|
|
110
|
-
: resolved.target;
|
|
111
|
-
const { exec: _exec, ...common } = unit;
|
|
112
|
-
return Object.freeze({
|
|
113
|
-
...common,
|
|
114
|
-
isolation: common.isolation ?? "none",
|
|
115
|
-
frozenTarget,
|
|
116
|
-
environment: Object.freeze([...resolved.environment]),
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
function captureWorkflowSource(asset, collector) {
|
|
120
|
-
const root = path.resolve(asset.sourcePath);
|
|
121
|
-
const file = path.resolve(asset.path);
|
|
122
|
-
collector.trackDirectory(root, root);
|
|
123
|
-
const parent = path.dirname(file);
|
|
124
|
-
const relativeParent = path.relative(root, parent);
|
|
125
|
-
if (relativeParent.startsWith("..") || path.isAbsolute(relativeParent)) {
|
|
126
|
-
throw new UsageError(`${file} resolves outside its workflow source root.`, "PATH_ESCAPE_VIOLATION");
|
|
127
|
-
}
|
|
128
|
-
let current = root;
|
|
129
|
-
for (const segment of relativeParent === "" ? [] : relativeParent.split(path.sep)) {
|
|
130
|
-
current = path.join(current, segment);
|
|
131
|
-
collector.trackDirectory(current, root);
|
|
132
|
-
}
|
|
133
|
-
const captured = collector.capture(file, root, { authored: true });
|
|
134
|
-
const parsed = parseBundleRef(asset.ref);
|
|
135
|
-
if (!parsed.bundle || !asset.adapterId) {
|
|
136
|
-
throw new UsageError(`Workflow ${asset.ref} has no fully-qualified bundle/adapter owner for durable publication.`, "WORKFLOW_SOURCE_INVALID");
|
|
137
|
-
}
|
|
138
|
-
return collector.bindIdentity(file, root, {
|
|
139
|
-
ref: asset.ref,
|
|
140
|
-
bundle: parsed.bundle,
|
|
141
|
-
adapter: asset.adapterId,
|
|
142
|
-
file: captured.relativePath,
|
|
143
|
-
hash: captured.sha256,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
function sourceSnapshot(source) {
|
|
147
|
-
return Object.freeze({
|
|
148
|
-
identity: source.identity,
|
|
149
|
-
containmentPhysicalIdentity: source.containmentPhysicalIdentity,
|
|
150
|
-
physicalIdentity: source.physicalIdentity,
|
|
151
|
-
size: source.size,
|
|
152
|
-
});
|
|
153
|
-
}
|