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,354 +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 { isContainedRelativePath, isRecord } from "../../core/common.js";
|
|
5
|
-
import { UsageError } from "../../core/errors.js";
|
|
6
|
-
import { parseReference } from "../program/expressions.js";
|
|
7
|
-
import { PROGRAM_PARAM_NAME_PATTERN, PROGRAM_RETRY_REASONS, PROGRAM_STEP_ID_PATTERN } from "../program/schema.js";
|
|
8
|
-
import { jsonBytes, utf8Bytes, WORKFLOW_ENV_VAR_NAME_PATTERN, WORKFLOW_MAX_CONCURRENCY, WORKFLOW_MAX_INSTRUCTION_BYTES, WORKFLOW_MAX_SCHEMA_BYTES, WORKFLOW_MAX_TIMEOUT_MS, } from "../resource-limits.js";
|
|
9
|
-
// Shared dispatch-significant bounds now live in `../resource-limits` so the
|
|
10
|
-
// parser, the published JSON Schema, and this decoder enforce identical
|
|
11
|
-
// values. Re-exported here for existing importers (e.g. `commands/workflow-cli.ts`).
|
|
12
|
-
export { WORKFLOW_MAX_CONCURRENCY, WORKFLOW_MAX_TIMEOUT_MS };
|
|
13
|
-
const MAX_LIST_ITEMS = 1024;
|
|
14
|
-
const MAX_STRING_LENGTH = 1_000_000;
|
|
15
|
-
/** Validate the current durable execution graph. */
|
|
16
|
-
export function validateWorkflowPlanStructure(input, options) {
|
|
17
|
-
if (!isRecord(input) || input.irVersion !== options.expectedVersion) {
|
|
18
|
-
fail(`irVersion must be ${options.expectedVersion}`);
|
|
19
|
-
}
|
|
20
|
-
assertJson(input);
|
|
21
|
-
const plan = input;
|
|
22
|
-
assertKeys(input, ["irVersion", "title", "params", "paramSchemas", "budget", "execution", "steps", ...(options.planExtraKeys ?? [])], "plan");
|
|
23
|
-
assertString(plan.title, "title");
|
|
24
|
-
validateParams(plan.params, plan.paramSchemas);
|
|
25
|
-
validateBudget(plan.budget);
|
|
26
|
-
if (!isRecord(plan.execution) ||
|
|
27
|
-
!Number.isInteger(plan.execution.maxConcurrency) ||
|
|
28
|
-
plan.execution.maxConcurrency < 1 ||
|
|
29
|
-
plan.execution.maxConcurrency > WORKFLOW_MAX_CONCURRENCY) {
|
|
30
|
-
fail(`execution.maxConcurrency must be an integer from 1 through ${WORKFLOW_MAX_CONCURRENCY}`);
|
|
31
|
-
}
|
|
32
|
-
assertKeys(plan.execution, ["maxConcurrency"], "execution");
|
|
33
|
-
if (!Array.isArray(plan.steps) || plan.steps.length === 0)
|
|
34
|
-
fail("steps must be a non-empty array");
|
|
35
|
-
const stepIds = new Set();
|
|
36
|
-
const nodeIds = new Set();
|
|
37
|
-
for (let index = 0; index < plan.steps.length; index++) {
|
|
38
|
-
const step = plan.steps[index];
|
|
39
|
-
if (!isRecord(step) ||
|
|
40
|
-
typeof step.stepId !== "string" ||
|
|
41
|
-
!PROGRAM_STEP_ID_PATTERN.test(step.stepId) ||
|
|
42
|
-
stepIds.has(step.stepId))
|
|
43
|
-
fail("step ids must be unique non-empty strings");
|
|
44
|
-
stepIds.add(step.stepId);
|
|
45
|
-
if (step.sequenceIndex !== index)
|
|
46
|
-
fail("step sequence indices must be contiguous and unique");
|
|
47
|
-
assertString(step.title, `step ${step.stepId} title`);
|
|
48
|
-
if (!!step.root === !!step.route)
|
|
49
|
-
fail(`step ${step.stepId} must contain exactly one of root or route`);
|
|
50
|
-
assertKeys(step, ["stepId", "title", "sequenceIndex", "root", "route", "outputSchema", "gate"], `step ${step.stepId}`);
|
|
51
|
-
if (step.outputSchema !== undefined)
|
|
52
|
-
validateSchema(step.outputSchema, `step ${step.stepId} outputSchema`);
|
|
53
|
-
if (step.root)
|
|
54
|
-
validateNode(step.root, step.stepId, nodeIds, options.unitExtraKeys ?? []);
|
|
55
|
-
if (step.route)
|
|
56
|
-
validateRoute(step.route, step.stepId);
|
|
57
|
-
validateGate(step.gate, step.stepId, nodeIds, options.gateExtraKeys ?? []);
|
|
58
|
-
}
|
|
59
|
-
const stepIndex = new Map(plan.steps.map((step, index) => [step.stepId, index]));
|
|
60
|
-
for (const [index, step] of plan.steps.entries()) {
|
|
61
|
-
for (const target of step.route
|
|
62
|
-
? [...Object.values(step.route.when), ...(step.route.defaultStepId ? [step.route.defaultStepId] : [])]
|
|
63
|
-
: []) {
|
|
64
|
-
const targetIndex = stepIndex.get(target);
|
|
65
|
-
if (targetIndex === undefined)
|
|
66
|
-
fail(`route target ${target} does not name a step`);
|
|
67
|
-
if (targetIndex <= index)
|
|
68
|
-
fail(`route target ${target} must come after step ${step.stepId}`);
|
|
69
|
-
}
|
|
70
|
-
validateStepExpressions(step, index, stepIndex);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
function validateNode(node, stepId, nodeIds, unitExtraKeys) {
|
|
74
|
-
if (!isRecord(node) ||
|
|
75
|
-
(node.kind !== "unit" && node.kind !== "map") ||
|
|
76
|
-
typeof node.id !== "string" ||
|
|
77
|
-
!node.id ||
|
|
78
|
-
nodeIds.has(node.id))
|
|
79
|
-
fail("node ids must be unique non-empty strings");
|
|
80
|
-
nodeIds.add(node.id);
|
|
81
|
-
if (node.kind === "map") {
|
|
82
|
-
assertKeys(node, ["kind", "id", "over", "template", "concurrency", "reducer", "source"], `map ${node.id}`);
|
|
83
|
-
if (typeof node.over !== "string" ||
|
|
84
|
-
!node.over ||
|
|
85
|
-
!Number.isInteger(node.concurrency) ||
|
|
86
|
-
node.concurrency < 1 ||
|
|
87
|
-
node.concurrency > WORKFLOW_MAX_CONCURRENCY ||
|
|
88
|
-
(node.reducer !== "collect" && node.reducer !== "vote"))
|
|
89
|
-
fail(`map ${node.id} is invalid`);
|
|
90
|
-
if (node.id !== `${stepId}.map`)
|
|
91
|
-
fail(`map ${node.id} does not match step ${stepId}`);
|
|
92
|
-
validateSource(node.source, `map ${node.id} source`);
|
|
93
|
-
validateNode(node.template, stepId, nodeIds, unitExtraKeys);
|
|
94
|
-
if (!isRecord(node.template) || node.template.kind !== "unit")
|
|
95
|
-
fail(`map ${node.id} template must be a unit`);
|
|
96
|
-
if (node.template.id !== `${stepId}.unit`)
|
|
97
|
-
fail(`map ${node.id} template id is invalid`);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
assertKeys(node, [
|
|
101
|
-
"kind",
|
|
102
|
-
"id",
|
|
103
|
-
"instructions",
|
|
104
|
-
"inputs",
|
|
105
|
-
"schema",
|
|
106
|
-
"retry",
|
|
107
|
-
"onError",
|
|
108
|
-
"env",
|
|
109
|
-
"isolation",
|
|
110
|
-
"source",
|
|
111
|
-
...unitExtraKeys,
|
|
112
|
-
], `unit ${node.id}`);
|
|
113
|
-
if (typeof node.instructions !== "string" ||
|
|
114
|
-
!node.instructions ||
|
|
115
|
-
(node.onError !== "fail" && node.onError !== "continue") ||
|
|
116
|
-
(node.isolation !== "none" && node.isolation !== "worktree"))
|
|
117
|
-
fail(`unit ${node.id} is invalid`);
|
|
118
|
-
if (node.id !== stepId && node.id !== `${stepId}.unit`)
|
|
119
|
-
fail(`unit ${node.id} does not belong to step ${stepId}`);
|
|
120
|
-
if (utf8Bytes(node.instructions) > WORKFLOW_MAX_INSTRUCTION_BYTES)
|
|
121
|
-
fail(`unit ${node.id} instructions exceed the 256 KiB resource limit`);
|
|
122
|
-
if (node.schema !== undefined)
|
|
123
|
-
validateSchema(node.schema, `unit ${node.id} schema`);
|
|
124
|
-
validateRetry(node.retry, node.id);
|
|
125
|
-
validateStringArray(node.env, `unit ${node.id} env`, MAX_LIST_ITEMS, true);
|
|
126
|
-
validateStringArray(node.inputs, `unit ${node.id} inputs`, Infinity, true);
|
|
127
|
-
validateSource(node.source, `unit ${node.id} source`);
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Strictly decode a frozen {@link IrExecSpec}. This is the corruption gate for
|
|
131
|
-
* a persisted plan: the argv bounds, the relative-and-contained `cwd`, and the
|
|
132
|
-
* timeout range are all re-checked here, because `plan_json` may have been
|
|
133
|
-
* hand-edited between freeze and dispatch.
|
|
134
|
-
*/
|
|
135
|
-
function validateExecSpec(value, label) {
|
|
136
|
-
if (!isRecord(value))
|
|
137
|
-
fail(`${label} must be an object`);
|
|
138
|
-
assertKeys(value, ["command", "cwd", "passEnv", "timeoutMs"], label);
|
|
139
|
-
validateExecEnvScope(value, label);
|
|
140
|
-
const command = value.command;
|
|
141
|
-
if (!Array.isArray(command) ||
|
|
142
|
-
command.length === 0 ||
|
|
143
|
-
!command.every((arg) => typeof arg === "string" && arg.length > 0)) {
|
|
144
|
-
fail(`${label}.command must be an argv array of non-empty strings`);
|
|
145
|
-
}
|
|
146
|
-
if (value.cwd !== undefined) {
|
|
147
|
-
if (typeof value.cwd !== "string" || value.cwd.length === 0 || !isContainedRelativePath(value.cwd)) {
|
|
148
|
-
fail(`${label}.cwd must be a relative path contained in the unit working directory`);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (!(value.timeoutMs === null ||
|
|
152
|
-
(Number.isSafeInteger(value.timeoutMs) &&
|
|
153
|
-
value.timeoutMs >= 1 &&
|
|
154
|
-
value.timeoutMs <= WORKFLOW_MAX_TIMEOUT_MS))) {
|
|
155
|
-
fail(`${label}.timeoutMs must be null or an integer from 1 through ${WORKFLOW_MAX_TIMEOUT_MS}`);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
/** Decode one current frozen exec spec. */
|
|
159
|
-
export function decodeWorkflowExecSpec(value, label) {
|
|
160
|
-
validateExecSpec(value, label);
|
|
161
|
-
return value;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* The child's ENVIRONMENT SCOPE half of a frozen exec spec. Split out so
|
|
165
|
-
* {@link validateExecSpec} keeps its shape (and the src-fn-size ratchet stays
|
|
166
|
-
* shrink-only).
|
|
167
|
-
*
|
|
168
|
-
* `passEnv` is canonical-form-only and may only be a non-empty deduplicated
|
|
169
|
-
* name list. A persisted `[]` means exactly what absence means, and admitting a
|
|
170
|
-
* second spelling of the default would give the same unit two different input
|
|
171
|
-
* hashes.
|
|
172
|
-
*/
|
|
173
|
-
function validateExecEnvScope(value, label) {
|
|
174
|
-
if (value.passEnv === undefined)
|
|
175
|
-
return;
|
|
176
|
-
const passEnv = value.passEnv;
|
|
177
|
-
if (!Array.isArray(passEnv) ||
|
|
178
|
-
passEnv.length === 0 ||
|
|
179
|
-
!passEnv.every((name) => typeof name === "string" && WORKFLOW_ENV_VAR_NAME_PATTERN.test(name)) ||
|
|
180
|
-
new Set(passEnv).size !== passEnv.length) {
|
|
181
|
-
fail(`${label}.passEnv must be a non-empty list of distinct environment variable names matching ` +
|
|
182
|
-
`${WORKFLOW_ENV_VAR_NAME_PATTERN.source}`);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
function validateGate(gate, stepId, nodeIds, gateExtraKeys) {
|
|
186
|
-
if (!isRecord(gate) ||
|
|
187
|
-
gate.kind !== "gate" ||
|
|
188
|
-
gate.id !== `${stepId}.gate` ||
|
|
189
|
-
gate.stepId !== stepId ||
|
|
190
|
-
!Array.isArray(gate.criteria) ||
|
|
191
|
-
gate.criteria.length > MAX_LIST_ITEMS ||
|
|
192
|
-
!gate.criteria.every((x) => typeof x === "string" && x.length > 0 && x.length <= MAX_STRING_LENGTH) ||
|
|
193
|
-
!Number.isInteger(gate.maxLoops) ||
|
|
194
|
-
gate.maxLoops < 1)
|
|
195
|
-
fail(`gate for step ${stepId} is invalid`);
|
|
196
|
-
if (nodeIds.has(gate.id))
|
|
197
|
-
fail(`gate id ${gate.id} collides with a node`);
|
|
198
|
-
assertKeys(gate, ["kind", "id", "stepId", "criteria", "maxLoops", ...gateExtraKeys], `gate ${stepId}`);
|
|
199
|
-
nodeIds.add(gate.id);
|
|
200
|
-
}
|
|
201
|
-
function validateRoute(route, stepId) {
|
|
202
|
-
if (!isRecord(route) ||
|
|
203
|
-
typeof route.input !== "string" ||
|
|
204
|
-
!route.input ||
|
|
205
|
-
!isRecord(route.when) ||
|
|
206
|
-
Object.keys(route.when).length === 0 ||
|
|
207
|
-
!Object.keys(route.when).every((match) => match.length > 0 && match.length <= MAX_STRING_LENGTH) ||
|
|
208
|
-
!Object.values(route.when).every((target) => typeof target === "string" && target))
|
|
209
|
-
fail(`route for step ${stepId} is invalid`);
|
|
210
|
-
assertKeys(route, ["input", "when", "defaultStepId"], `route ${stepId}`);
|
|
211
|
-
if (route.defaultStepId !== undefined && (typeof route.defaultStepId !== "string" || !route.defaultStepId))
|
|
212
|
-
fail(`route for step ${stepId} has an invalid default target`);
|
|
213
|
-
}
|
|
214
|
-
function assertKeys(value, allowed, label) {
|
|
215
|
-
for (const key of Object.keys(value))
|
|
216
|
-
if (!allowed.includes(key))
|
|
217
|
-
fail(`${label} contains unknown key ${key}`);
|
|
218
|
-
}
|
|
219
|
-
function assertJson(value) {
|
|
220
|
-
if (value === null || typeof value === "boolean")
|
|
221
|
-
return;
|
|
222
|
-
if (typeof value === "string") {
|
|
223
|
-
if (value.length > MAX_STRING_LENGTH)
|
|
224
|
-
fail("plan contains an oversized string");
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
if (typeof value === "number") {
|
|
228
|
-
if (!Number.isFinite(value))
|
|
229
|
-
fail("plan contains a non-finite number");
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
if (Array.isArray(value)) {
|
|
233
|
-
for (const item of value)
|
|
234
|
-
assertJson(item);
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
if (isRecord(value)) {
|
|
238
|
-
for (const item of Object.values(value))
|
|
239
|
-
assertJson(item);
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
fail("plan contains a non-JSON value");
|
|
243
|
-
}
|
|
244
|
-
function validateParams(params, schemas) {
|
|
245
|
-
validateStringArray(params, "params", Infinity, true);
|
|
246
|
-
if (params?.some((name) => !PROGRAM_PARAM_NAME_PATTERN.test(name)))
|
|
247
|
-
fail("params contains an invalid name");
|
|
248
|
-
if (schemas !== undefined) {
|
|
249
|
-
if (!isRecord(schemas))
|
|
250
|
-
fail("paramSchemas must be an object");
|
|
251
|
-
for (const [name, schema] of Object.entries(schemas)) {
|
|
252
|
-
if (!PROGRAM_PARAM_NAME_PATTERN.test(name))
|
|
253
|
-
fail(`paramSchemas.${name} is invalid`);
|
|
254
|
-
validateSchema(schema, `paramSchemas.${name}`);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
const names = params ?? [];
|
|
258
|
-
if (schemas && (names.length !== Object.keys(schemas).length || names.some((name) => !Object.hasOwn(schemas, name))))
|
|
259
|
-
fail("params and paramSchemas must name the same parameters");
|
|
260
|
-
if (!schemas && names.length > 0) {
|
|
261
|
-
// Markdown workflows have named parameters but no schemas, which is valid.
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
function validateBudget(budget) {
|
|
266
|
-
if (budget === undefined)
|
|
267
|
-
return;
|
|
268
|
-
if (!isRecord(budget))
|
|
269
|
-
fail("budget must be an object");
|
|
270
|
-
assertKeys(budget, ["maxTokens", "maxUnits"], "budget");
|
|
271
|
-
if (budget.maxTokens === undefined && budget.maxUnits === undefined)
|
|
272
|
-
fail("budget must declare a ceiling");
|
|
273
|
-
validateOptionalPositiveInteger(budget.maxTokens, "budget.maxTokens");
|
|
274
|
-
const maxUnits = budget.maxUnits;
|
|
275
|
-
if (maxUnits !== undefined && (!Number.isSafeInteger(maxUnits) || maxUnits < 1))
|
|
276
|
-
fail("budget.maxUnits must be a positive integer");
|
|
277
|
-
}
|
|
278
|
-
function validateRetry(retry, nodeId) {
|
|
279
|
-
if (retry === undefined)
|
|
280
|
-
return;
|
|
281
|
-
if (!isRecord(retry))
|
|
282
|
-
fail(`unit ${nodeId} retry must be an object`);
|
|
283
|
-
assertKeys(retry, ["max", "on"], `unit ${nodeId} retry`);
|
|
284
|
-
if (!Number.isSafeInteger(retry.max) || retry.max < 0)
|
|
285
|
-
fail(`unit ${nodeId} retry.max is invalid`);
|
|
286
|
-
validateStringArray(retry.on, `unit ${nodeId} retry.on`, PROGRAM_RETRY_REASONS.length, true);
|
|
287
|
-
if (retry.on === undefined ||
|
|
288
|
-
retry.on.length === 0 ||
|
|
289
|
-
retry.on.some((reason) => !PROGRAM_RETRY_REASONS.includes(reason)))
|
|
290
|
-
fail(`unit ${nodeId} retry.on is invalid`);
|
|
291
|
-
}
|
|
292
|
-
function validateSchema(value, label) {
|
|
293
|
-
if (!isRecord(value))
|
|
294
|
-
fail(`${label} must be an object`);
|
|
295
|
-
if (jsonBytes(value) > WORKFLOW_MAX_SCHEMA_BYTES)
|
|
296
|
-
fail(`${label} exceeds the 256 KiB resource limit`);
|
|
297
|
-
}
|
|
298
|
-
function validateStepExpressions(step, index, steps) {
|
|
299
|
-
const validateReference = (text, label, paramsAllowed) => {
|
|
300
|
-
const parsed = parseReference(text);
|
|
301
|
-
if (!parsed.ok)
|
|
302
|
-
fail(`${label} contains an invalid reference`);
|
|
303
|
-
if (parsed.expr.kind === "param" && !paramsAllowed)
|
|
304
|
-
fail(`${label} must reference a step output`);
|
|
305
|
-
if (parsed.expr.kind === "stepOutput") {
|
|
306
|
-
const referenced = steps.get(parsed.expr.stepId);
|
|
307
|
-
if (referenced === undefined || referenced >= index)
|
|
308
|
-
fail(`${label} references a non-earlier step`);
|
|
309
|
-
}
|
|
310
|
-
};
|
|
311
|
-
if (step.root) {
|
|
312
|
-
const unit = step.root.kind === "map" ? step.root.template : step.root;
|
|
313
|
-
if (step.root.kind === "map")
|
|
314
|
-
validateReference(step.root.over, `map ${step.root.id} over`, true);
|
|
315
|
-
for (const reference of unit.inputs ?? [])
|
|
316
|
-
validateReference(reference, `unit ${unit.id} inputs`, false);
|
|
317
|
-
}
|
|
318
|
-
if (step.route)
|
|
319
|
-
validateReference(step.route.input, `route ${step.stepId} input`, true);
|
|
320
|
-
}
|
|
321
|
-
function validateSource(value, label) {
|
|
322
|
-
if (value === undefined)
|
|
323
|
-
return;
|
|
324
|
-
if (!isRecord(value))
|
|
325
|
-
fail(`${label} must be an object`);
|
|
326
|
-
assertKeys(value, ["path", "start", "end"], label);
|
|
327
|
-
if (typeof value.path !== "string" ||
|
|
328
|
-
!value.path ||
|
|
329
|
-
!Number.isSafeInteger(value.start) ||
|
|
330
|
-
!Number.isSafeInteger(value.end) ||
|
|
331
|
-
value.start < 1 ||
|
|
332
|
-
value.end < value.start)
|
|
333
|
-
fail(`${label} is invalid`);
|
|
334
|
-
}
|
|
335
|
-
function validateStringArray(value, label, max, unique) {
|
|
336
|
-
if (value === undefined)
|
|
337
|
-
return;
|
|
338
|
-
if (!Array.isArray(value) ||
|
|
339
|
-
value.length > max ||
|
|
340
|
-
!value.every((item) => typeof item === "string" && item.length > 0 && item.length <= MAX_STRING_LENGTH) ||
|
|
341
|
-
(unique && new Set(value).size !== value.length))
|
|
342
|
-
fail(`${label} is invalid`);
|
|
343
|
-
}
|
|
344
|
-
function validateOptionalPositiveInteger(value, label) {
|
|
345
|
-
if (value !== undefined && (!Number.isSafeInteger(value) || value < 1))
|
|
346
|
-
fail(`${label} must be a positive safe integer`);
|
|
347
|
-
}
|
|
348
|
-
function assertString(value, label) {
|
|
349
|
-
if (typeof value !== "string" || value.length === 0 || value.length > MAX_STRING_LENGTH)
|
|
350
|
-
fail(`${label} must be a non-empty bounded string`);
|
|
351
|
-
}
|
|
352
|
-
function fail(message) {
|
|
353
|
-
throw new UsageError(`Invalid frozen workflow plan: ${message}.`);
|
|
354
|
-
}
|
|
@@ -1,77 +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
|
-
/** How a map step folds its per-item unit results into the step artifact. */
|
|
5
|
-
export const PROGRAM_REDUCERS = ["collect", "vote"];
|
|
6
|
-
/** Failure policy: fail the step on first unit failure, or record and go on. */
|
|
7
|
-
export const PROGRAM_ON_ERROR = ["fail", "continue"];
|
|
8
|
-
/** Filesystem isolation for file-mutating units. */
|
|
9
|
-
export const PROGRAM_ISOLATION_KINDS = ["none", "worktree"];
|
|
10
|
-
/**
|
|
11
|
-
* `retry.on` vocabulary — exactly the persisted `AgentFailureReason` taxonomy
|
|
12
|
-
* from `src/integrations/agent/spawn.ts`. The `satisfies` clause fails the
|
|
13
|
-
* typecheck if spawn.ts adds/renames a reason without this list (and the JSON
|
|
14
|
-
* Schema, via the drift test) being updated.
|
|
15
|
-
*/
|
|
16
|
-
const RETRY_REASON_SET = {
|
|
17
|
-
timeout: true,
|
|
18
|
-
spawn_failed: true,
|
|
19
|
-
non_zero_exit: true,
|
|
20
|
-
parse_error: true,
|
|
21
|
-
cooldown: true,
|
|
22
|
-
llm_rate_limit: true,
|
|
23
|
-
llm_content_filter: true,
|
|
24
|
-
llm_invalid_json: true,
|
|
25
|
-
content_policy_reject: true,
|
|
26
|
-
unsupported_type: true,
|
|
27
|
-
no_change: true,
|
|
28
|
-
aborted: true,
|
|
29
|
-
};
|
|
30
|
-
export const PROGRAM_RETRY_REASONS = Object.keys(RETRY_REASON_SET);
|
|
31
|
-
/**
|
|
32
|
-
* Step ids: `[A-Za-z_][A-Za-z0-9_-]*` (also pinned in the JSON Schema) — the
|
|
33
|
-
* ONE id grammar for the shared source IR (workflow-format-unification, spec
|
|
34
|
-
* §2.2). This is EXACTLY the `<ident>` grammar `readIdent` accepts in
|
|
35
|
-
* `program/expressions.ts` for `steps.<id>.output` references: a
|
|
36
|
-
* letter/underscore first char, then letters/digits/underscores/dashes, and
|
|
37
|
-
* NO dots (the expression parser treats `.` as the `.output` path separator,
|
|
38
|
-
* so a dotted id could never be addressed). Keeping step ids inside the
|
|
39
|
-
* addressable grammar guarantees every step can be referenced from map
|
|
40
|
-
* inputs, routes, and `inputs:` without renaming.
|
|
41
|
-
*
|
|
42
|
-
* Forbidding dots additionally keeps the engine's internal gate-row node id
|
|
43
|
-
* `<stepId>.gate` collision-free: no user step id can contain a dot, so it can
|
|
44
|
-
* never equal another step's `<stepId>.gate` synthetic id.
|
|
45
|
-
*/
|
|
46
|
-
export const PROGRAM_STEP_ID_PATTERN = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
47
|
-
/**
|
|
48
|
-
* Param names must be `params.<ident>`-addressable, so they are plain
|
|
49
|
-
* identifiers (no dots/dashes). Re-exported from the shared input contract
|
|
50
|
-
* (`src/execution/input-contract.ts`'s `INPUT_NAME_PATTERN`) so task source
|
|
51
|
-
* v4's `inputs:` declarations share the exact same name pattern rather than a
|
|
52
|
-
* second, hand-maintained copy (P2a, D3-N1).
|
|
53
|
-
*/
|
|
54
|
-
export { INPUT_NAME_PATTERN as PROGRAM_PARAM_NAME_PATTERN } from "../../execution/input-contract.js";
|
|
55
|
-
/**
|
|
56
|
-
* The ONE structural projection of an exec spec — ONE encoding per state.
|
|
57
|
-
*
|
|
58
|
-
* Every layer that carries an exec forward derives from this: the compiled
|
|
59
|
-
* draft, the frozen plan (which layers `timeoutMs` on top), and the summary
|
|
60
|
-
* `akm workflow show` prints. Written out per layer instead, a field added to
|
|
61
|
-
* {@link ProgramExec} reaches whichever copies were remembered and silently
|
|
62
|
-
* vanishes from the rest — and nothing catches it, because every key here is
|
|
63
|
-
* optional, so an omitted spread is not a type error. What it would cost:
|
|
64
|
-
* either the frozen plan loses a field the author wrote (and the canonical
|
|
65
|
-
* hash preimage stops matching the authored intent), or `show` describes
|
|
66
|
-
* something other than what runs.
|
|
67
|
-
*
|
|
68
|
-
* The ABSENCE of both env keys is the default allowlist. The parser rejects an
|
|
69
|
-
* empty `pass_env` outright, so no layer has to distinguish absent from empty.
|
|
70
|
-
*/
|
|
71
|
-
export function projectExecCore(exec) {
|
|
72
|
-
return {
|
|
73
|
-
command: [...exec.command],
|
|
74
|
-
...(exec.cwd ? { cwd: exec.cwd } : {}),
|
|
75
|
-
...(exec.passEnv && exec.passEnv.length > 0 ? { passEnv: [...exec.passEnv] } : {}),
|
|
76
|
-
};
|
|
77
|
-
}
|
|
@@ -1,57 +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
|
-
* Agent check-in: a no-background-thread "continue" nudge for stalled workflow
|
|
6
|
-
* runs (#506).
|
|
7
|
-
*
|
|
8
|
-
* The design decision (the workflow-agent check-in ADR)
|
|
9
|
-
* reconciles #506 (file/command-loop signal) with #501 (background thread) in
|
|
10
|
-
* favour of the former. There is intentionally NO timer or resident process
|
|
11
|
-
* here. Arming a check-in writes a timestamp (`checkin_armed_at`) on the run
|
|
12
|
-
* row; the next time the agent polls the engine via `workflow run`/`status`,
|
|
13
|
-
* {@link evaluateCheckin} is called to decide — purely from timestamps — whether
|
|
14
|
-
* the run looks stalled and a strong `continue` directive should be surfaced
|
|
15
|
-
* through the normal command output.
|
|
16
|
-
*
|
|
17
|
-
* @module workflows/checkin
|
|
18
|
-
*/
|
|
19
|
-
/**
|
|
20
|
-
* Default stall window. If a run has been active and untouched for at least
|
|
21
|
-
* this long since the later of its last update and its armed timestamp, the
|
|
22
|
-
* next poll surfaces a check-in directive.
|
|
23
|
-
*/
|
|
24
|
-
export const CHECKIN_STALL_MS = 90_000;
|
|
25
|
-
function parseIso(value) {
|
|
26
|
-
if (!value)
|
|
27
|
-
return null;
|
|
28
|
-
const ms = Date.parse(value);
|
|
29
|
-
return Number.isNaN(ms) ? null : ms;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Pure check-in evaluator. Returns a `continue` directive when an *active* run
|
|
33
|
-
* has been idle past the stall window, otherwise `null`. Deterministic in
|
|
34
|
-
* `now`, so it is trivially unit-testable and free of timer flakiness.
|
|
35
|
-
*/
|
|
36
|
-
export function evaluateCheckin(run, now = Date.now(), stallMs = CHECKIN_STALL_MS) {
|
|
37
|
-
if (run.status !== "active")
|
|
38
|
-
return null;
|
|
39
|
-
const updated = parseIso(run.updatedAt);
|
|
40
|
-
const armed = parseIso(run.checkinArmedAt);
|
|
41
|
-
// Never armed → no check-in (opt-in per run via startWorkflowRun).
|
|
42
|
-
if (armed === null)
|
|
43
|
-
return null;
|
|
44
|
-
const last = Math.max(updated ?? armed, armed);
|
|
45
|
-
const idleMs = now - last;
|
|
46
|
-
if (idleMs < stallMs)
|
|
47
|
-
return null;
|
|
48
|
-
return {
|
|
49
|
-
signal: "continue",
|
|
50
|
-
directive: "CONTINUE: this workflow run has stalled with no progress. Resume immediately — " +
|
|
51
|
-
"inspect its status, then call `akm workflow run` with the run id to finish the outstanding work. " +
|
|
52
|
-
"Do not stop until the run reaches a terminal state or reports a verification rejection.",
|
|
53
|
-
idleMs,
|
|
54
|
-
agentHarness: run.agentHarness ?? null,
|
|
55
|
-
agentSessionId: run.agentSessionId ?? null,
|
|
56
|
-
};
|
|
57
|
-
}
|