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,24 +1,14 @@
|
|
|
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
|
-
* File-private helpers prepareTaskV3Execution depends on, moved body-intact
|
|
6
|
-
* out of the pre-P1b src/tasks/runtime-v3.ts (spec
|
|
7
|
-
* docs/plans/specs/p1b-model-extraction.md §4.1, Lane B / D4 module map).
|
|
8
|
-
* None of these was exported at head either; only the subset prepare.ts's
|
|
9
|
-
* moved function body calls is exported here.
|
|
10
|
-
*/
|
|
11
|
-
import path from "node:path";
|
|
12
4
|
import { makeBundleRef, parseBundleRef } from "../../core/asset/asset-ref.js";
|
|
13
5
|
import { COMPOSITION_INVALID_MULTI_JOB_HINT, ConfigError, NotFoundError, UsageError } from "../../core/errors.js";
|
|
14
6
|
import { DURATION_UNITS, parseDuration } from "../../core/time.js";
|
|
15
7
|
import { isPortableExecutionAgentSelector } from "../../execution/source.js";
|
|
16
|
-
import {
|
|
17
|
-
import { lowerResolvedExecutionRequest } from "../../integrations/agent/execution-lowering.js";
|
|
8
|
+
import { buildExecution } from "../../integrations/agent/execution.js";
|
|
18
9
|
import { resolveAssetPath } from "../../sources/resolve.js";
|
|
10
|
+
import { checkWorkflowPlan, compileWorkflowSource } from "../../workflows/compile.js";
|
|
19
11
|
import { detectSecretShapedParams } from "../../workflows/exec/param-secrets.js";
|
|
20
|
-
import { compileWorkflowPlan } from "../../workflows/ir/compile.js";
|
|
21
|
-
import { compileWorkflowSource } from "../../workflows/source-ir/compile.js";
|
|
22
12
|
import { isInferredSecretName } from "../log-redaction.js";
|
|
23
13
|
import { SCHEDULED_TASK_CONTEXT_KEYS } from "../scheduler-invocation.js";
|
|
24
14
|
function own(value, key) {
|
|
@@ -118,14 +108,14 @@ export function defaultTaskShell(platform) {
|
|
|
118
108
|
return platform === "win32" ? "powershell" : "sh";
|
|
119
109
|
}
|
|
120
110
|
export function validatePreparedCommand(invocation, context) {
|
|
121
|
-
const request =
|
|
111
|
+
const { request } = invocation;
|
|
122
112
|
if (!request.engine.name) {
|
|
123
113
|
throw new ConfigError(`Task ${JSON.stringify(context.taskRef)} has no resolved execution engine. Configure defaults.engine or akm.engine before running it.`, "INVALID_CONFIG_FILE");
|
|
124
114
|
}
|
|
125
115
|
// Lowering is pure. Running it before the durable-attempt boundary proves
|
|
126
116
|
// the selected target is transport-projectable; dispatch repeats the same
|
|
127
117
|
// deterministic projection from this frozen request/config snapshot.
|
|
128
|
-
|
|
118
|
+
buildExecution(request, invocation.runner);
|
|
129
119
|
return invocation;
|
|
130
120
|
}
|
|
131
121
|
export function validateWorkflowRuntimeSource(file, workspaceRoot, readFile) {
|
|
@@ -141,7 +131,7 @@ export function validateWorkflowRuntimeSource(file, workspaceRoot, readFile) {
|
|
|
141
131
|
const code = isMultiJob ? "COMPOSITION_INVALID" : "WORKFLOW_SOURCE_INVALID";
|
|
142
132
|
throw new UsageError(`Task workflow target is not projectable: ${detail}`, code, isMultiJob ? COMPOSITION_INVALID_MULTI_JOB_HINT : undefined);
|
|
143
133
|
}
|
|
144
|
-
const planned =
|
|
134
|
+
const planned = checkWorkflowPlan(compiled.plan);
|
|
145
135
|
if (!planned.ok) {
|
|
146
136
|
// Same mapping applied for consistency; `compiled.ir` is already
|
|
147
137
|
// guaranteed exactly one job here, so this arm always resolves to
|
|
@@ -54,7 +54,6 @@ export async function prepareTaskV3Execution(document, context) {
|
|
|
54
54
|
const invocation = validatePreparedCommand(await (context.prepareCommand ?? prepareCommandInvocation)({
|
|
55
55
|
action,
|
|
56
56
|
config: context.config,
|
|
57
|
-
invocationKind: "task",
|
|
58
57
|
current: currentExecutionValues(document, context, commandEnvironment),
|
|
59
58
|
...(context.commandSourceLoader ? { sourceLoader: context.commandSourceLoader } : {}),
|
|
60
59
|
}), context);
|
|
@@ -71,7 +70,6 @@ export async function prepareTaskV3Execution(document, context) {
|
|
|
71
70
|
const invocation = validatePreparedCommand(await (context.prepareCommand ?? prepareCommandInvocation)({
|
|
72
71
|
action: { ref: qualified },
|
|
73
72
|
config: context.config,
|
|
74
|
-
invocationKind: "task",
|
|
75
73
|
current: currentExecutionValues(document, context, commandEnvironment),
|
|
76
74
|
...(context.commandSourceLoader ? { sourceLoader: context.commandSourceLoader } : {}),
|
|
77
75
|
}), context);
|
|
@@ -10,17 +10,16 @@
|
|
|
10
10
|
* Resolution order:
|
|
11
11
|
*
|
|
12
12
|
* 1. `process.execPath` alone for a Bun standalone executable.
|
|
13
|
-
* 2. Absolute Node plus the public `dist/akm` package launcher
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* checkout that requires explicit `--rebind` for scheduler writes.
|
|
13
|
+
* 2. Absolute Node plus the public `dist/akm` package launcher.
|
|
14
|
+
* 3. Absolute runtime plus the source/build CLI entry of a checkout.
|
|
15
|
+
*
|
|
16
|
+
* `via` names which one was used. `checkout` — a package launcher inside a
|
|
17
|
+
* git work tree, or a source/build entry — runs whatever the checkout holds
|
|
18
|
+
* when the scheduler fires; `task sync` says so once when it writes one.
|
|
20
19
|
*
|
|
21
20
|
* Returns the argv array the scheduler should execute (e.g.
|
|
22
|
-
* `["/usr/local/bin/node", "/
|
|
23
|
-
* subcommand args (`"task", "run", "<id>"`).
|
|
21
|
+
* `["/usr/local/bin/node", "/usr/lib/node_modules/akm-cli/dist/akm"]`). The
|
|
22
|
+
* caller appends subcommand args (`"task", "run", "<id>"`).
|
|
24
23
|
*/
|
|
25
24
|
import { spawnSync } from "node:child_process";
|
|
26
25
|
import fs from "node:fs";
|
|
@@ -28,6 +27,8 @@ import path from "node:path";
|
|
|
28
27
|
import { fileURLToPath } from "node:url";
|
|
29
28
|
import { ConfigError } from "../core/errors.js";
|
|
30
29
|
import { mainPath as runtimeMainPath } from "../runtime.js";
|
|
30
|
+
/** A source entry or local build run by a runtime: `src/cli.ts`, `dist/cli.js`, `dist/cli-node.mjs`. */
|
|
31
|
+
const CHECKOUT_ENTRY = /(?:^|[\\/])src[\\/]cli\.ts$|(?:^|[\\/])dist[\\/](?:cli\.js|cli-node\.mjs)$/i;
|
|
31
32
|
/** True only for Bun's virtual main path inside a compiled standalone executable. */
|
|
32
33
|
export function isBunStandaloneMain(mainPath = runtimeMainPath) {
|
|
33
34
|
return (mainPath?.startsWith("/$bunfs/") === true || (mainPath !== undefined && /^[A-Za-z]:[\\/]~BUN[\\/]/i.test(mainPath)));
|
|
@@ -37,44 +38,27 @@ export function resolveAkmInvocation(options = {}) {
|
|
|
37
38
|
const runtime = options.runtime ?? (process.versions.bun ? "bun" : "node");
|
|
38
39
|
const execPath = options.execPath ?? process.execPath;
|
|
39
40
|
const mainPath = options.mainPath ?? runtimeMainPath;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return { argv: [absoluteInvocationPath(execPath)], via: "standalone", kind: "standalone", eligible: true };
|
|
41
|
+
if (runtime === "bun" && isBunStandaloneMain(mainPath) && execPath) {
|
|
42
|
+
return { argv: [absoluteInvocationPath(execPath)], via: "standalone" };
|
|
43
43
|
}
|
|
44
44
|
const launcherPath = options.launcherPath ?? env.AKM_LAUNCHER_PATH?.trim();
|
|
45
45
|
const nodePath = options.nodePath ?? env.AKM_LAUNCHER_NODE?.trim() ?? (runtime === "node" ? execPath : undefined);
|
|
46
46
|
if (launcherPath && nodePath && isPublicPackageLauncher(launcherPath)) {
|
|
47
|
-
const checkout = isCheckoutLauncher(launcherPath);
|
|
48
|
-
let npmGlobalRoot;
|
|
49
|
-
if (!checkout) {
|
|
50
|
-
try {
|
|
51
|
-
npmGlobalRoot = (options.resolveNpmGlobalRoot ?? ((node) => resolveNpmGlobalRoot(node, env)))(nodePath);
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
// An unprovable package installation is intentionally ineligible.
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
const npmGlobal = !checkout && packageBelongsToNpmGlobalRoot(launcherPath, npmGlobalRoot);
|
|
58
|
-
const readOnlyInstall = !checkout && !npmGlobal && !(options.isPathWritable ?? isPathWritable)(path.dirname(launcherPath));
|
|
59
|
-
const kind = checkout ? "checkout" : npmGlobal ? "npm" : "package-local";
|
|
60
47
|
return {
|
|
61
48
|
argv: [absoluteInvocationPath(nodePath), absoluteInvocationPath(launcherPath)],
|
|
62
|
-
via:
|
|
63
|
-
kind,
|
|
64
|
-
eligible: npmGlobal || readOnlyInstall,
|
|
49
|
+
via: isCheckoutLauncher(launcherPath) ? "checkout" : "npm",
|
|
65
50
|
};
|
|
66
51
|
}
|
|
67
52
|
const checkoutEntry = resolveCheckoutEntry(options.cliEntryUrl ?? import.meta.url, runtime, mainPath);
|
|
68
53
|
if (checkoutEntry && execPath) {
|
|
69
|
-
return {
|
|
70
|
-
argv: [absoluteInvocationPath(execPath), absoluteInvocationPath(checkoutEntry)],
|
|
71
|
-
via: "checkout",
|
|
72
|
-
kind: "checkout",
|
|
73
|
-
eligible: false,
|
|
74
|
-
};
|
|
54
|
+
return { argv: [absoluteInvocationPath(execPath), absoluteInvocationPath(checkoutEntry)], via: "checkout" };
|
|
75
55
|
}
|
|
76
56
|
throw new ConfigError("Cannot resolve absolute path to the akm binary for scheduler registration.", "INVALID_CONFIG_FILE", "Run the npm-global launcher or a standalone akm executable.");
|
|
77
57
|
}
|
|
58
|
+
/** Whether an installed launcher argv runs akm out of a source checkout. */
|
|
59
|
+
export function isCheckoutInvocation(argv) {
|
|
60
|
+
return argv.some((part) => CHECKOUT_ENTRY.test(part) || (isPublicPackageLauncher(part) && isCheckoutLauncher(part)));
|
|
61
|
+
}
|
|
78
62
|
function resolveCheckoutEntry(moduleUrl, runtime, mainPath) {
|
|
79
63
|
try {
|
|
80
64
|
const modulePath = fileURLToPath(moduleUrl);
|
|
@@ -111,6 +95,7 @@ function isPublicPackageLauncher(file) {
|
|
|
111
95
|
path.basename(path.dirname(file)).toLowerCase() === "dist" &&
|
|
112
96
|
fs.existsSync(file));
|
|
113
97
|
}
|
|
98
|
+
/** A package launcher whose package root is a git work tree (`npm link`, a local clone). */
|
|
114
99
|
function isCheckoutLauncher(file) {
|
|
115
100
|
let launcher = path.resolve(file);
|
|
116
101
|
try {
|
|
@@ -122,52 +107,8 @@ function isCheckoutLauncher(file) {
|
|
|
122
107
|
const packageRoot = path.dirname(path.dirname(launcher));
|
|
123
108
|
return fs.existsSync(path.join(packageRoot, ".git"));
|
|
124
109
|
}
|
|
125
|
-
/**
|
|
126
|
-
function isPathWritable(dir) {
|
|
127
|
-
try {
|
|
128
|
-
fs.accessSync(dir, fs.constants.W_OK);
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
catch {
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
function packageBelongsToNpmGlobalRoot(launcherPath, npmGlobalRoot) {
|
|
136
|
-
if (!npmGlobalRoot)
|
|
137
|
-
return false;
|
|
138
|
-
try {
|
|
139
|
-
const packageRoot = path.dirname(path.dirname(fs.realpathSync(launcherPath)));
|
|
140
|
-
const globalRoot = fs.realpathSync(npmGlobalRoot);
|
|
141
|
-
const metadata = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8"));
|
|
142
|
-
return metadata.name === "akm-cli" && samePath(path.dirname(packageRoot), globalRoot);
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
function samePath(left, right) {
|
|
149
|
-
const normalize = (value) => {
|
|
150
|
-
const resolved = path.resolve(value);
|
|
151
|
-
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
152
|
-
};
|
|
153
|
-
return normalize(left) === normalize(right);
|
|
154
|
-
}
|
|
155
|
-
// #901: the global root can't change within a process lifetime, and every
|
|
156
|
-
// `resolveAkmInvocation()` call in a scheduler-sync process re-derives the
|
|
157
|
-
// same `nodePath` — so this spawns `npm root --global` at most once per
|
|
158
|
-
// process instead of once per call. Keyed by nodePath (rather than a bare
|
|
159
|
-
// once-only flag) so a differently-invoked probe later in the same process
|
|
160
|
-
// still gets its own answer instead of a stale one.
|
|
161
|
-
let cachedNpmGlobalRoot;
|
|
110
|
+
/** `npm root --global` for the npm that ships with `nodePath`; `akm upgrade` uses it to detect a global install. */
|
|
162
111
|
export function resolveNpmGlobalRoot(nodePath, env) {
|
|
163
|
-
if (cachedNpmGlobalRoot && cachedNpmGlobalRoot.nodePath === nodePath) {
|
|
164
|
-
return cachedNpmGlobalRoot.value;
|
|
165
|
-
}
|
|
166
|
-
const value = resolveNpmGlobalRootUncached(nodePath, env);
|
|
167
|
-
cachedNpmGlobalRoot = { nodePath, value };
|
|
168
|
-
return value;
|
|
169
|
-
}
|
|
170
|
-
function resolveNpmGlobalRootUncached(nodePath, env) {
|
|
171
112
|
const npmCli = resolveAssociatedNpmCli(nodePath);
|
|
172
113
|
if (!npmCli)
|
|
173
114
|
return undefined;
|
|
@@ -100,7 +100,7 @@ export async function loadPreparedTask(id, options) {
|
|
|
100
100
|
bundleRoot: bundleDir,
|
|
101
101
|
config,
|
|
102
102
|
// Agent profiles build child env from an allowlist, so freeze the closed
|
|
103
|
-
//
|
|
103
|
+
// AKM directory context the scheduled row set before command preparation.
|
|
104
104
|
...(options.scheduled ? { schedulerContext: scheduledTaskContextEnv() } : {}),
|
|
105
105
|
resolveAsset: async ({ bundle, type, name }) => {
|
|
106
106
|
if (bundle === bundleName) {
|
|
@@ -2,12 +2,14 @@
|
|
|
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
|
-
* Secret-free input to every native scheduler backend
|
|
5
|
+
* Secret-free input to every native scheduler backend, and the backend
|
|
6
|
+
* contract itself.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* environment
|
|
10
|
-
*
|
|
8
|
+
* A binding carries only stable source identity, trigger identity, and the
|
|
9
|
+
* public CLI tail; its install options add the launcher and the AKM
|
|
10
|
+
* directory environment the row sets inline. Source content, action inputs,
|
|
11
|
+
* task environment values, and credentials never cross this boundary or
|
|
12
|
+
* reach an OS scheduler.
|
|
11
13
|
*/
|
|
12
14
|
import { createHash } from "node:crypto";
|
|
13
15
|
import { bundleRefToString, parseBundleRef } from "../core/asset/asset-ref.js";
|
|
@@ -20,20 +22,8 @@ export function compileTaskSchedulerBindings(input) {
|
|
|
20
22
|
const bundle = parseBundleRef(ref).bundle;
|
|
21
23
|
if (!bundle)
|
|
22
24
|
throw new Error("invariant: qualified scheduler task ref lost its bundle");
|
|
23
|
-
// P2b Lane B (B-N3): the invocation is compiled PER schedule entry now —
|
|
24
|
-
// each entry's own `inputs` produces its own trailing flag tail, so it can
|
|
25
|
-
// no longer be hoisted as one binding shared by every entry.
|
|
26
25
|
return Object.freeze(input.schedules.map((schedule) => {
|
|
27
26
|
const bindingId = schedule.ordinal === 0 ? id : digestBindingId("task", ref, schedule.ordinal);
|
|
28
|
-
const invocation = Object.freeze([
|
|
29
|
-
"task",
|
|
30
|
-
"run",
|
|
31
|
-
id,
|
|
32
|
-
"--bundle",
|
|
33
|
-
bundle,
|
|
34
|
-
"--scheduled",
|
|
35
|
-
...schedulerInputFlagTail(schedule.inputs),
|
|
36
|
-
]);
|
|
37
27
|
return freezeBinding({
|
|
38
28
|
id: bindingId,
|
|
39
29
|
nativeId: schedulerNativeBindingId(bindingId),
|
|
@@ -42,39 +32,21 @@ export function compileTaskSchedulerBindings(input) {
|
|
|
42
32
|
source: schedule.source,
|
|
43
33
|
ordinal: schedule.ordinal,
|
|
44
34
|
enabled: true,
|
|
45
|
-
invocation,
|
|
35
|
+
invocation: ["task", "run", id, "--bundle", bundle, "--scheduled", ...schedulerInputFlagTail(schedule.inputs)],
|
|
46
36
|
});
|
|
47
37
|
}));
|
|
48
38
|
}
|
|
49
39
|
/**
|
|
50
40
|
* The canonically-sorted `--<name> <value>` flag tail for one schedule
|
|
51
|
-
* entry's `inputs
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* Code-review finding (scheduler-binding.ts:536): a value whose exact text
|
|
56
|
-
* begins with `-` (a negative number, or a string that just happens to
|
|
57
|
-
* start with a dash) is indistinguishable from a NEW flag in the two-token
|
|
58
|
-
* `--<name> <value>` form — `isValidSchedulerInputFlagTail`
|
|
59
|
-
* (scheduler-invocation.ts) refuses it outright, and even a looser parser
|
|
60
|
-
* would still be wrong for a non-numeric dash-leading string: the real `akm
|
|
61
|
-
* task run` flag parser (`parseTaskInputFlags`, tasks-cli.ts) only
|
|
62
|
-
* special-cases a dash-DIGIT lead, so it would silently treat `--scope
|
|
63
|
-
* -urgent` as the boolean flag `--scope` followed by an orphaned,
|
|
64
|
-
* dropped `-urgent` token. The inline `--<name>=<value>` form has no such
|
|
65
|
-
* ambiguity on EITHER side — `isValidSchedulerInputFlagTail` accepts it
|
|
66
|
-
* unconditionally, and `parseTaskInputFlags`'s own inline-`=` branch splits
|
|
67
|
-
* on the first `=` without ever inspecting the value's leading character —
|
|
68
|
-
* so it is used whenever the value's exact text would otherwise be
|
|
69
|
-
* ambiguous. Every other value keeps the existing two-token form
|
|
70
|
-
* byte-identical to before this fix (B-03/B-45).
|
|
41
|
+
* entry's `inputs`. A value whose text starts with `-` uses the inline
|
|
42
|
+
* `--<name>=<value>` form, the only spelling `parseTaskInputFlags` cannot
|
|
43
|
+
* mistake for a flag.
|
|
71
44
|
*/
|
|
72
45
|
function schedulerInputFlagTail(inputs) {
|
|
73
46
|
if (!inputs)
|
|
74
47
|
return [];
|
|
75
|
-
const names = Object.keys(inputs).sort();
|
|
76
48
|
const tail = [];
|
|
77
|
-
for (const name of
|
|
49
|
+
for (const name of Object.keys(inputs).sort()) {
|
|
78
50
|
const text = schedulerInputFlagValueText(inputs[name]);
|
|
79
51
|
if (text.startsWith("-"))
|
|
80
52
|
tail.push(`--${name}=${text}`);
|
|
@@ -83,14 +55,6 @@ function schedulerInputFlagTail(inputs) {
|
|
|
83
55
|
}
|
|
84
56
|
return tail;
|
|
85
57
|
}
|
|
86
|
-
/**
|
|
87
|
-
* One input value's argv text. A scalar is its exact text — `String(value)`
|
|
88
|
-
* for a number/boolean (a `true` boolean is `"true"`, never a bare flag, so
|
|
89
|
-
* the tail round-trips through one parser), the string itself for a string.
|
|
90
|
-
* An object/array value is its `canonicalInputJson` text, which
|
|
91
|
-
* `materializeInputFlags`'s JSON-shorthand path already coerces back through
|
|
92
|
-
* the declaration.
|
|
93
|
-
*/
|
|
94
58
|
function schedulerInputFlagValueText(value) {
|
|
95
59
|
if (typeof value === "string")
|
|
96
60
|
return value;
|
|
@@ -100,7 +64,6 @@ function schedulerInputFlagValueText(value) {
|
|
|
100
64
|
}
|
|
101
65
|
export function compileWorkflowSchedulerBindings(input) {
|
|
102
66
|
const ref = assertQualifiedRef(input.qualifiedRef, "workflow");
|
|
103
|
-
const invocation = Object.freeze(["workflow", "run", ref]);
|
|
104
67
|
return Object.freeze(input.schedules.map((schedule) => {
|
|
105
68
|
const bindingId = digestBindingId("workflow", ref, schedule.ordinal);
|
|
106
69
|
return freezeBinding({
|
|
@@ -111,23 +74,14 @@ export function compileWorkflowSchedulerBindings(input) {
|
|
|
111
74
|
source: schedule.source,
|
|
112
75
|
ordinal: schedule.ordinal,
|
|
113
76
|
enabled: true,
|
|
114
|
-
invocation,
|
|
115
|
-
...(input.executionEvidenceDigest !== undefined
|
|
116
|
-
? { executionEvidenceDigest: assertSchedulerExecutionEvidenceDigest(input.executionEvidenceDigest) }
|
|
117
|
-
: {}),
|
|
77
|
+
invocation: ["workflow", "run", ref],
|
|
118
78
|
});
|
|
119
79
|
}));
|
|
120
80
|
}
|
|
121
|
-
export function assertSchedulerExecutionEvidenceDigest(value) {
|
|
122
|
-
if (!/^[a-f0-9]{64}$/u.test(value)) {
|
|
123
|
-
throw new UsageError("Scheduler workflow execution evidence must be a lowercase SHA-256 digest.", "INVALID_FLAG_VALUE");
|
|
124
|
-
}
|
|
125
|
-
return value;
|
|
126
|
-
}
|
|
127
81
|
/**
|
|
128
82
|
* Map a logical binding id to the flat portable token persisted by native
|
|
129
|
-
* schedulers.
|
|
130
|
-
* component
|
|
83
|
+
* schedulers. Flat ids are byte-for-byte stable; only nested standalone
|
|
84
|
+
* component ids need an encoded native spelling.
|
|
131
85
|
*/
|
|
132
86
|
export function schedulerNativeBindingId(id) {
|
|
133
87
|
if (!id.includes("/"))
|
|
@@ -138,183 +92,17 @@ export function schedulerNativeBindingId(id) {
|
|
|
138
92
|
.slice(0, 32);
|
|
139
93
|
return `task-${digest}`;
|
|
140
94
|
}
|
|
141
|
-
/** Portable collision key for scheduler namespaces with Windows semantics. */
|
|
142
|
-
export function schedulerNativeArtifactKey(nativeId) {
|
|
143
|
-
return nativeId.toLowerCase().replace(/\.+$/u, "");
|
|
144
|
-
}
|
|
145
|
-
export function schedulerNativeArtifactsForKey(artifacts, nativeId) {
|
|
146
|
-
const key = schedulerNativeArtifactKey(nativeId);
|
|
147
|
-
return artifacts.filter((artifact) => schedulerNativeArtifactKey(artifact.nativeId) === key);
|
|
148
|
-
}
|
|
149
|
-
export function assertSchedulerNativeArtifactCardinality(artifacts, nativeId, expectedCount) {
|
|
150
|
-
const matches = schedulerNativeArtifactsForKey(artifacts, nativeId);
|
|
151
|
-
if (matches.length !== expectedCount) {
|
|
152
|
-
const expectedState = expectedCount === 0 ? "absence" : "one present owner";
|
|
153
|
-
throw new UsageError(`Native scheduler artifact ${JSON.stringify(nativeId)} changed: normalized cardinality ${matches.length} violates the expected ${expectedState} before mutation.`, "RESOURCE_ALREADY_EXISTS");
|
|
154
|
-
}
|
|
155
|
-
return matches[0];
|
|
156
|
-
}
|
|
157
|
-
/** Return a logical owner only when the public invocation proves the mapping. */
|
|
158
|
-
export function schedulerLogicalBindingOwner(nativeId, invocation) {
|
|
159
|
-
return schedulerNativeArtifactOwner(nativeId, invocation)?.logicalId;
|
|
160
|
-
}
|
|
161
|
-
export function schedulerNativeArtifactOwner(nativeId, invocation) {
|
|
162
|
-
if (invocation[0] === "workflow" && invocation[1] === "run" && invocation.length === 3) {
|
|
163
|
-
const ref = invocation[2];
|
|
164
|
-
if (ref && workflowRefDigestsToNativeId(ref, nativeId)) {
|
|
165
|
-
return { logicalId: nativeId, logicalKind: "workflow" };
|
|
166
|
-
}
|
|
167
|
-
return undefined;
|
|
168
|
-
}
|
|
169
|
-
const taskId = invocation[0] === "task" && invocation[1] === "run" ? invocation[2] : undefined;
|
|
170
|
-
if (!taskId)
|
|
171
|
-
return undefined;
|
|
172
|
-
return {
|
|
173
|
-
logicalId: schedulerNativeBindingId(taskId) === nativeId ? taskId : nativeId,
|
|
174
|
-
logicalKind: "task",
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
export function assertSchedulerNativeArtifactOwner(nativeId, intended, invocation) {
|
|
178
|
-
const intendedNativeId = intended.nativeId ?? schedulerNativeBindingId(intended.id);
|
|
179
|
-
if (nativeId === intendedNativeId && invocation && sameInvocation(invocation, intended.invocation))
|
|
180
|
-
return;
|
|
181
|
-
const description = invocation ? JSON.stringify(invocation) : "an unproven or malformed invocation";
|
|
182
|
-
throw new UsageError(`Native scheduler artifact ${JSON.stringify(nativeId)} belongs to ${description}, not the exact ${intended.logicalSource.kind} owner ${JSON.stringify(intended.logicalSource.ref)} with binding ${JSON.stringify(intended.id)}.`, "RESOURCE_ALREADY_EXISTS");
|
|
183
|
-
}
|
|
184
|
-
/** Recover binding identity without treating the native hash as source ownership. */
|
|
185
|
-
export function schedulerLogicalBindingId(nativeId, invocation) {
|
|
186
|
-
return schedulerLogicalBindingOwner(nativeId, invocation) ?? nativeId;
|
|
187
|
-
}
|
|
188
95
|
export function schedulerBindingNativeId(binding) {
|
|
189
96
|
return binding.nativeId ?? schedulerNativeBindingId(binding.id);
|
|
190
97
|
}
|
|
191
|
-
export function assertSchedulerRemovalArtifact(nativeId, expected, invocation, fingerprint) {
|
|
192
|
-
const normalized = normalizeRemovalExpectation(expected);
|
|
193
|
-
assertSchedulerExpectationIdentity(normalized);
|
|
194
|
-
const fingerprintMatches = normalized.fingerprint === undefined || normalized.fingerprint === fingerprint;
|
|
195
|
-
if (nativeId === normalized.nativeId &&
|
|
196
|
-
invocation !== undefined &&
|
|
197
|
-
sameInvocation(invocation, normalized.invocation) &&
|
|
198
|
-
fingerprintMatches) {
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
throw new UsageError(`Native scheduler artifact ${JSON.stringify(nativeId)} changed owner or fingerprint; refusing to remove an unverified ${normalized.logicalSource.kind} owner ${JSON.stringify(normalized.logicalSource.ref)}.`, "RESOURCE_ALREADY_EXISTS");
|
|
202
|
-
}
|
|
203
|
-
export function assertSchedulerExpectationIdentity(expected, binding) {
|
|
204
|
-
const identity = canonicalSchedulerIdentity(expected.logicalSource, expected.ordinal, expected.invocation);
|
|
205
|
-
if (identity.bindingId !== expected.bindingId ||
|
|
206
|
-
identity.nativeId !== expected.nativeId ||
|
|
207
|
-
!sameInvocation(identity.invocation, expected.invocation) ||
|
|
208
|
-
(binding !== undefined &&
|
|
209
|
-
(binding.id !== expected.bindingId ||
|
|
210
|
-
schedulerBindingNativeId(binding) !== expected.nativeId ||
|
|
211
|
-
binding.ordinal !== expected.ordinal ||
|
|
212
|
-
binding.logicalSource.kind !== expected.logicalSource.kind ||
|
|
213
|
-
binding.logicalSource.ref !== expected.logicalSource.ref ||
|
|
214
|
-
!sameInvocation(binding.invocation, expected.invocation)))) {
|
|
215
|
-
throw new UsageError("Scheduler mutation expectation has a forged or inconsistent binding identity.", "INVALID_FLAG_VALUE");
|
|
216
|
-
}
|
|
217
|
-
if (expected.state === "absent" && expected.fingerprint !== undefined) {
|
|
218
|
-
throw new UsageError("An absent scheduler expectation cannot carry prior artifact state.", "INVALID_FLAG_VALUE");
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
export function assertSchedulerMutationArtifact(artifact, expected) {
|
|
222
|
-
assertSchedulerExpectationIdentity(expected);
|
|
223
|
-
if (expected.state === "absent") {
|
|
224
|
-
if (artifact === undefined)
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
else if (artifact !== undefined &&
|
|
228
|
-
artifact.nativeId === expected.nativeId &&
|
|
229
|
-
artifact.bindingId === expected.bindingId &&
|
|
230
|
-
artifact.invocation !== undefined &&
|
|
231
|
-
expected.fingerprint !== undefined &&
|
|
232
|
-
artifact.fingerprint === expected.fingerprint) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
throw new UsageError(`Native scheduler artifact ${JSON.stringify(expected.nativeId)} changed from its frozen ${expected.state} state; refusing mutation.`, "RESOURCE_ALREADY_EXISTS");
|
|
236
|
-
}
|
|
237
|
-
export function assertSchedulerRollbackArtifact(artifact, expected) {
|
|
238
|
-
const matches = expected.allowed.some((state) => {
|
|
239
|
-
if (state.state === "absent")
|
|
240
|
-
return artifact === undefined;
|
|
241
|
-
if (!artifact || artifact.nativeId !== expected.nativeId)
|
|
242
|
-
return false;
|
|
243
|
-
if (artifact.fingerprint !== state.fingerprint || artifact.bindingId !== state.bindingId)
|
|
244
|
-
return false;
|
|
245
|
-
return state.invocation === undefined
|
|
246
|
-
? artifact.invocation === undefined
|
|
247
|
-
: artifact.invocation !== undefined && sameInvocation(artifact.invocation, state.invocation);
|
|
248
|
-
});
|
|
249
|
-
if (matches)
|
|
250
|
-
return;
|
|
251
|
-
throw new UsageError(`Native scheduler artifact ${JSON.stringify(expected.nativeId)} changed after the transaction began; refusing rollback over a concurrent owner or fingerprint.`, "RESOURCE_ALREADY_EXISTS");
|
|
252
|
-
}
|
|
253
98
|
/**
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
99
|
+
* Recover the logical id of an installed row from its native spelling and
|
|
100
|
+
* public invocation: an ordinal-zero task row is its task id (possibly a
|
|
101
|
+
* nested one behind a digest spelling); every other row is its native id.
|
|
257
102
|
*/
|
|
258
|
-
export function
|
|
259
|
-
const matches = schedulerNativeArtifactsForKey(artifacts, expected.nativeId);
|
|
260
|
-
if (matches.length > 1) {
|
|
261
|
-
throw new UsageError(`Native scheduler artifact ${JSON.stringify(expected.nativeId)} changed after the transaction began: normalized rollback cardinality ${matches.length} exceeds one.`, "RESOURCE_ALREADY_EXISTS");
|
|
262
|
-
}
|
|
263
|
-
const artifact = matches[0];
|
|
264
|
-
assertSchedulerRollbackArtifact(artifact, expected);
|
|
265
|
-
return artifact;
|
|
266
|
-
}
|
|
267
|
-
export function canonicalSchedulerIdentity(logicalSource, ordinal, invocation) {
|
|
268
|
-
const parsed = parseBundleRef(logicalSource.ref);
|
|
269
|
-
if (!parsed.bundle || parsed.fragment !== undefined || bundleRefToString(parsed) !== logicalSource.ref) {
|
|
270
|
-
throw new UsageError("Scheduler expectation requires one canonical fully-qualified source.", "INVALID_FLAG_VALUE");
|
|
271
|
-
}
|
|
272
|
-
if (!Number.isSafeInteger(ordinal) || ordinal < 0) {
|
|
273
|
-
throw new UsageError("Scheduler expectation ordinal must be a non-negative integer.", "INVALID_FLAG_VALUE");
|
|
274
|
-
}
|
|
275
|
-
if (logicalSource.kind === "workflow") {
|
|
276
|
-
const canonicalInvocation = ["workflow", "run", logicalSource.ref];
|
|
277
|
-
if (!sameInvocation(invocation, canonicalInvocation)) {
|
|
278
|
-
throw new UsageError("Workflow scheduler expectation invocation does not match its qualified source.", "INVALID_FLAG_VALUE");
|
|
279
|
-
}
|
|
280
|
-
const bindingId = digestBindingId("workflow", logicalSource.ref, ordinal);
|
|
281
|
-
return Object.freeze({ bindingId, nativeId: bindingId, invocation: Object.freeze(canonicalInvocation) });
|
|
282
|
-
}
|
|
103
|
+
export function schedulerLogicalBindingId(nativeId, invocation) {
|
|
283
104
|
const taskId = invocation[0] === "task" && invocation[1] === "run" ? invocation[2] : undefined;
|
|
284
|
-
|
|
285
|
-
throw new UsageError("Task scheduler expectation has an invalid public task id.", "INVALID_FLAG_VALUE");
|
|
286
|
-
}
|
|
287
|
-
const canonicalInvocation = ["task", "run", taskId, "--bundle", parsed.bundle, "--scheduled"];
|
|
288
|
-
if (!sameInvocation(invocation, canonicalInvocation)) {
|
|
289
|
-
throw new UsageError(`Task scheduler expectation invocation does not match its qualified source: expected ${JSON.stringify(canonicalInvocation)}, got ${JSON.stringify(invocation)}.`, "INVALID_FLAG_VALUE");
|
|
290
|
-
}
|
|
291
|
-
if (parsed.conceptId !== taskId && parsed.conceptId !== `tasks/${taskId}`) {
|
|
292
|
-
throw new UsageError("Task scheduler expectation id does not match its qualified source.", "INVALID_FLAG_VALUE");
|
|
293
|
-
}
|
|
294
|
-
const bindingId = ordinal === 0 ? taskId : digestBindingId("task", logicalSource.ref, ordinal);
|
|
295
|
-
return Object.freeze({
|
|
296
|
-
bindingId,
|
|
297
|
-
nativeId: schedulerNativeBindingId(bindingId),
|
|
298
|
-
invocation: Object.freeze(canonicalInvocation),
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
/** Recover the authored schedule ordinal from the exact source/binding identity. */
|
|
302
|
-
export function schedulerBindingOrdinal(bindingId, logicalSource, invocation) {
|
|
303
|
-
if (logicalSource.kind === "task" && bindingId === invocation[2])
|
|
304
|
-
return 0;
|
|
305
|
-
for (let ordinal = 0; ordinal < 4096; ordinal += 1) {
|
|
306
|
-
if (digestBindingId(logicalSource.kind, logicalSource.ref, ordinal) === bindingId)
|
|
307
|
-
return ordinal;
|
|
308
|
-
}
|
|
309
|
-
return undefined;
|
|
310
|
-
}
|
|
311
|
-
/** Whether some schedule ordinal on `ref` would digest to `nativeId` (mirrors schedulerBindingOrdinal). */
|
|
312
|
-
function workflowRefDigestsToNativeId(ref, nativeId) {
|
|
313
|
-
for (let ordinal = 0; ordinal < 4096; ordinal += 1) {
|
|
314
|
-
if (digestBindingId("workflow", ref, ordinal) === nativeId)
|
|
315
|
-
return true;
|
|
316
|
-
}
|
|
317
|
-
return false;
|
|
105
|
+
return taskId !== undefined && schedulerNativeBindingId(taskId) === nativeId ? taskId : nativeId;
|
|
318
106
|
}
|
|
319
107
|
function digestBindingId(kind, ref, ordinal) {
|
|
320
108
|
const prefix = kind === "workflow" ? "wf" : "task";
|
|
@@ -338,9 +126,3 @@ function freezeBinding(binding) {
|
|
|
338
126
|
invocation: Object.freeze([...binding.invocation]),
|
|
339
127
|
});
|
|
340
128
|
}
|
|
341
|
-
function sameInvocation(left, right) {
|
|
342
|
-
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
343
|
-
}
|
|
344
|
-
function normalizeRemovalExpectation(expected) {
|
|
345
|
-
return { ...expected, state: "present" };
|
|
346
|
-
}
|