akm-cli 0.9.0-rc.1 → 0.9.0-rc.13
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 +1190 -52
- package/README.md +62 -37
- package/SECURITY.md +46 -31
- package/dist/akm +162 -38
- package/dist/akm-migrate +44 -0
- package/dist/assets/backends/schtasks-template.xml +2 -1
- package/dist/assets/hints/cli-hints-full.md +268 -118
- package/dist/assets/hints/cli-hints-short.md +87 -24
- package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
- package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
- package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
- package/dist/assets/improve-strategies/frequent.json +15 -0
- package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
- package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
- package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
- package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
- package/dist/assets/improve-strategies/reflect-distill.json +30 -0
- package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +5 -5
- package/dist/assets/prompts/extract-session.md +2 -6
- package/dist/assets/prompts/memory-infer-user.md +2 -3
- package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
- package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
- package/dist/assets/prompts/reflect-output-repair.md +3 -0
- package/dist/assets/stash-skeleton/README.md +38 -10
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
- package/dist/assets/tasks/core/extract.yml +3 -2
- package/dist/assets/tasks/core/improve.yml +2 -1
- package/dist/assets/tasks/core/index-refresh.yml +1 -0
- package/dist/assets/tasks/core/sync.yml +1 -0
- package/dist/assets/tasks/core/version-check.yml +2 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
- package/dist/assets/templates/html/health.html +5 -4
- package/dist/assets/workflows/workflow-template.md +31 -15
- package/dist/cli/invocation.js +279 -0
- package/dist/cli/parse-args.js +5 -90
- package/dist/cli/retired-commands.js +78 -0
- package/dist/cli/shared.js +158 -48
- package/dist/cli-node.mjs +2 -1
- package/dist/cli.js +747 -293
- package/dist/commands/agent/agent-dispatch.js +19 -18
- package/dist/commands/agent/agent-support.js +0 -24
- package/dist/commands/agent/contribute-cli.js +43 -97
- package/dist/commands/completions.js +80 -23
- package/dist/commands/config-cli.js +44 -281
- package/dist/commands/env/env-binding.js +13 -9
- package/dist/commands/env/env-cli.js +76 -159
- package/dist/commands/env/env.js +12 -163
- package/dist/commands/env/marker-path.js +6 -0
- package/dist/commands/env/secret-cli.js +45 -61
- package/dist/commands/env/secret.js +32 -62
- package/dist/commands/feedback-cli.js +179 -85
- package/dist/commands/health/accept-rate.js +58 -0
- package/dist/commands/health/advisories.js +7 -8
- package/dist/commands/health/checks.js +279 -94
- package/dist/commands/health/html-report.js +197 -578
- package/dist/commands/health/improve-metrics.js +277 -246
- package/dist/commands/health/llm-usage.js +19 -19
- package/dist/commands/health/md-report.js +16 -7
- package/dist/commands/health/metrics.js +67 -32
- package/dist/commands/health/renderers.js +47 -0
- package/dist/commands/health/report-view-model.js +508 -0
- package/dist/commands/health/stash-exposure.js +1 -1
- package/dist/commands/health/surfaces.js +16 -56
- package/dist/commands/health/task-runs.js +3 -67
- package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
- package/dist/commands/health/types-improve.js +29 -0
- package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
- package/dist/commands/health/types-result.js +7 -0
- package/dist/commands/health/types-runs.js +4 -0
- package/dist/commands/health/types-session-log.js +4 -0
- package/dist/commands/health/types-windows.js +4 -0
- package/dist/commands/health/types.js +26 -21
- package/dist/commands/health/windows.js +2 -3
- package/dist/commands/health.js +296 -167
- package/dist/commands/improve/anti-collapse.js +5 -5
- package/dist/commands/improve/autonomy-gate.js +68 -0
- package/dist/commands/improve/collapse-detector.js +65 -52
- package/dist/commands/improve/consolidate/chunking.js +9 -7
- package/dist/commands/improve/consolidate/eligibility.js +1 -23
- package/dist/commands/improve/consolidate/merge.js +4 -0
- package/dist/commands/improve/consolidate.js +454 -1354
- package/dist/commands/improve/content-hash.js +39 -0
- package/dist/commands/improve/distill/content-repair.js +4 -10
- package/dist/commands/improve/distill/promote-memory.js +89 -64
- package/dist/commands/improve/distill/quality-gate.js +118 -42
- package/dist/commands/improve/distill-guards.js +1 -1
- package/dist/commands/improve/distill-promotion-policy.js +33 -888
- package/dist/commands/improve/distill.js +607 -363
- package/dist/commands/improve/eligibility.js +165 -79
- package/dist/commands/improve/extract-cli.js +35 -126
- package/dist/commands/improve/extract-prompt.js +6 -35
- package/dist/commands/improve/extract.js +640 -391
- package/dist/commands/improve/feedback-valence.js +2 -12
- package/dist/commands/improve/improve-cli.js +134 -135
- package/dist/commands/improve/improve-result-file.js +30 -50
- package/dist/commands/improve/improve-run-types.js +4 -0
- package/dist/commands/improve/improve-strategies.js +135 -0
- package/dist/commands/improve/improve.js +904 -701
- package/dist/commands/improve/locks.js +64 -111
- package/dist/commands/improve/loop-stages.js +1110 -923
- package/dist/commands/improve/memory/derived-ref.js +124 -0
- package/dist/commands/improve/memory/memory-belief.js +79 -7
- package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
- package/dist/commands/improve/memory/memory-improve.js +25 -37
- package/dist/commands/improve/outcome-loop.js +25 -88
- package/dist/commands/improve/preparation.js +1034 -813
- package/dist/commands/improve/proactive-maintenance.js +34 -9
- package/dist/commands/improve/proposal-envelope.js +31 -0
- package/dist/commands/improve/reflect.js +983 -794
- package/dist/commands/improve/run-context.js +119 -0
- package/dist/commands/improve/salience.js +24 -127
- package/dist/commands/improve/session-asset.js +7 -3
- package/dist/commands/improve/shared.js +14 -34
- package/dist/commands/improve/source-identity.js +28 -0
- package/dist/commands/improve/triage.js +20 -17
- package/dist/commands/lint/base-linter.js +340 -313
- package/dist/commands/lint/env-key-rules.js +31 -47
- package/dist/commands/lint/index.js +185 -30
- package/dist/commands/{events.js → log.js} +28 -38
- package/dist/commands/migrate-cli.js +54 -0
- package/dist/commands/migration-tool.js +55 -0
- package/dist/commands/observability-cli.js +70 -208
- package/dist/commands/proposal/diff-format.js +50 -0
- package/dist/commands/proposal/drain-policies.js +0 -6
- package/dist/commands/proposal/drain.js +91 -40
- package/dist/commands/proposal/proposal-cli.js +134 -132
- package/dist/commands/proposal/proposal-types.js +56 -0
- package/dist/commands/proposal/proposal.js +83 -65
- package/dist/commands/proposal/propose-cli.js +88 -0
- package/dist/commands/proposal/propose.js +105 -88
- package/dist/commands/proposal/repository.js +1303 -278
- package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
- package/dist/commands/proposal/validators/proposal-validators.js +61 -12
- package/dist/commands/proposal/validators/proposals.js +6 -8
- package/dist/commands/read/curate.js +78 -73
- package/dist/commands/read/knowledge.js +510 -13
- package/dist/commands/read/registry-search.js +2 -2
- package/dist/commands/read/remember-cli.js +84 -15
- package/dist/commands/read/search-cli.js +203 -96
- package/dist/commands/read/search.js +126 -94
- package/dist/commands/read/show.js +226 -250
- package/dist/commands/registry-cli.js +34 -60
- package/dist/commands/remember.js +18 -57
- package/dist/commands/sources/add-cli.js +104 -49
- package/dist/commands/sources/bundle-cli.js +166 -0
- package/dist/commands/sources/bundle-config-ops.js +63 -0
- package/dist/commands/sources/info.js +27 -15
- package/dist/commands/sources/init.js +30 -40
- package/dist/commands/sources/installed-stashes.js +469 -172
- package/dist/commands/sources/schema-repair.js +10 -9
- package/dist/commands/sources/self-update.js +182 -121
- package/dist/commands/sources/source-add.js +169 -178
- package/dist/commands/sources/source-clone.js +144 -41
- package/dist/commands/sources/source-manage.js +94 -59
- package/dist/commands/sources/sources-cli.js +64 -205
- package/dist/commands/sources/stash-cli.js +91 -54
- package/dist/commands/sources/stash-skeleton.js +1 -1
- package/dist/commands/tasks/tasks-cli.js +106 -104
- package/dist/commands/tasks/tasks.js +445 -262
- package/dist/commands/workflow-cli.js +75 -228
- package/dist/core/action-contributors.js +1 -1
- package/dist/core/activation-policy.js +49 -0
- package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
- package/dist/core/adapter/adapters/akm-adapter.js +528 -0
- package/dist/core/adapter/adapters/akm-lint.js +392 -0
- package/dist/core/adapter/adapters/akm-metadata.js +387 -0
- package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
- package/dist/core/adapter/adapters/claude-adapter.js +61 -0
- package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
- package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
- package/dist/core/adapter/adapters/index.js +80 -0
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
- package/dist/core/adapter/adapters/okf-adapter.js +391 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
- package/dist/core/adapter/adapters/shared.js +286 -0
- package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
- package/dist/core/adapter/bundle-adapter.js +4 -0
- package/dist/core/adapter/detect-adapter.js +17 -0
- package/dist/core/adapter/recognize-match.js +44 -0
- package/dist/core/adapter/registry.js +56 -0
- package/dist/core/adapter/types.js +4 -0
- package/dist/core/asset/akm-markdown.js +30 -0
- package/dist/core/asset/asset-placement.js +243 -0
- package/dist/core/asset/asset-ref.js +110 -79
- package/dist/core/asset/asset-serialize.js +20 -0
- package/dist/core/asset/frontmatter.js +28 -12
- package/dist/core/asset/markdown.js +40 -51
- package/dist/core/asset/resolve-ref.js +274 -0
- package/dist/core/asset/stash-meta.js +2 -2
- package/dist/core/bundle-id.js +51 -0
- package/dist/core/common.js +281 -86
- package/dist/core/config/config-io.js +42 -128
- package/dist/core/config/config-schema.js +233 -855
- package/dist/core/config/config-sources.js +162 -39
- package/dist/core/config/config-types.js +16 -11
- package/dist/core/config/config-version.js +29 -0
- package/dist/core/config/config-walker.js +126 -37
- package/dist/core/config/config.js +154 -331
- package/dist/core/config/deep-merge.js +41 -0
- package/dist/core/config/engine-semantics.js +28 -0
- package/dist/core/config/experimental.js +21 -0
- package/dist/core/config/schema/embedding.js +38 -0
- package/dist/core/config/schema/engines.js +116 -0
- package/dist/core/config/schema/experimental.js +47 -0
- package/dist/core/config/schema/feedback.js +31 -0
- package/dist/core/config/schema/improve-processes.js +389 -0
- package/dist/core/config/schema/improve.js +94 -0
- package/dist/core/config/schema/index-config.js +176 -0
- package/dist/core/config/schema/output.js +18 -0
- package/dist/core/config/schema/primitives.js +94 -0
- package/dist/core/config/schema/search.js +30 -0
- package/dist/core/config/schema/setup.js +18 -0
- package/dist/core/config/schema/sources-bundles.js +169 -0
- package/dist/core/config/schema/workflow.js +29 -0
- package/dist/core/env-secret-ref.js +155 -20
- package/dist/core/errors.js +17 -15
- package/dist/core/events-types.js +4 -0
- package/dist/core/events.js +46 -128
- package/dist/core/extra-params.js +62 -0
- package/dist/core/file-change.js +17 -0
- package/dist/core/file-lock.js +202 -57
- package/dist/core/fs-txn.js +392 -0
- package/dist/core/git-message.js +59 -0
- package/dist/core/improve-result.js +167 -0
- package/dist/core/lesson-lint.js +1 -17
- package/dist/core/logs-db.js +1 -1
- package/dist/core/maintenance-barrier.js +135 -0
- package/dist/core/migration-operation.js +44 -0
- package/dist/core/mutation-target.js +78 -0
- package/dist/core/paths.js +22 -25
- package/dist/core/platform.js +10 -0
- package/dist/core/recognition-util.js +128 -0
- package/dist/core/redaction.js +392 -0
- package/dist/core/standards/resolve-standards-context.js +36 -65
- package/dist/core/standards/resolve-stash-standards.js +2 -2
- package/dist/core/standards/resolve-type-conventions.js +5 -5
- package/dist/core/state/migrations.js +242 -11
- package/dist/core/state-db.js +98 -10
- package/dist/core/structured.js +1 -1
- package/dist/core/subprocess.js +303 -0
- package/dist/core/text-truncation.js +9 -5
- package/dist/core/time.js +20 -0
- package/dist/core/type-presentation.js +130 -0
- package/dist/core/warn.js +0 -3
- package/dist/core/write-source.js +834 -118
- package/dist/indexer/bundle-identity-guard.js +92 -0
- package/dist/indexer/db/graph-db.js +1 -25
- package/dist/indexer/db/llm-cache.js +1 -1
- package/dist/indexer/ensure-index.js +30 -9
- package/dist/indexer/graph/graph-boost.js +9 -30
- package/dist/indexer/graph/graph-extraction.js +41 -27
- package/dist/indexer/graph/graph-types.js +4 -0
- package/dist/indexer/index-writer-lock.js +93 -49
- package/dist/indexer/index-written-assets.js +100 -53
- package/dist/indexer/indexer.js +746 -329
- package/dist/indexer/init.js +18 -25
- package/dist/indexer/installations.js +142 -0
- package/dist/indexer/passes/dir-staleness.js +18 -10
- package/dist/indexer/passes/memory-inference.js +25 -15
- package/dist/indexer/passes/metadata.js +412 -243
- package/dist/indexer/scan/doc-to-entry.js +160 -0
- package/dist/indexer/scan/drain-dir.js +134 -0
- package/dist/indexer/search/db-search.js +292 -108
- package/dist/indexer/search/fts-query.js +64 -0
- package/dist/indexer/search/ranking-contributors.js +145 -25
- package/dist/indexer/search/ranking-types.js +4 -0
- package/dist/indexer/search/ranking.js +28 -71
- package/dist/indexer/search/search-attribution.js +67 -0
- package/dist/indexer/search/search-fields.js +18 -3
- package/dist/indexer/search/search-hit-enrichers.js +30 -40
- package/dist/indexer/search/search-source.js +157 -111
- package/dist/indexer/search/semantic-status.js +4 -1
- package/dist/indexer/usage/usage-events.js +10 -30
- package/dist/indexer/walk/file-context.js +3 -45
- package/dist/indexer/walk/matchers.js +42 -73
- package/dist/indexer/walk/path-resolver.js +11 -5
- package/dist/indexer/walk/walker.js +42 -14
- package/dist/integrations/agent/builder-shared.js +7 -0
- package/dist/integrations/agent/builders.js +5 -58
- package/dist/integrations/agent/config.js +3 -143
- package/dist/integrations/agent/detect.js +17 -2
- package/dist/integrations/agent/engine-resolution.js +231 -0
- package/dist/integrations/agent/index.js +1 -2
- package/dist/integrations/agent/model-aliases.js +8 -3
- package/dist/integrations/agent/profiles.js +6 -99
- package/dist/integrations/agent/prompts.js +46 -18
- package/dist/integrations/agent/runner-dispatch.js +78 -13
- package/dist/integrations/agent/runner.js +76 -208
- package/dist/integrations/agent/spawn.js +48 -279
- package/dist/integrations/harnesses/aider/agent-builder.js +9 -8
- package/dist/integrations/harnesses/aider/index.js +2 -12
- package/dist/integrations/harnesses/amazonq/agent-builder.js +10 -16
- package/dist/integrations/harnesses/amazonq/index.js +3 -17
- package/dist/integrations/harnesses/claude/agent-builder.js +2 -3
- package/dist/integrations/harnesses/claude/config-import.js +1 -3
- package/dist/integrations/harnesses/claude/index.js +1 -14
- package/dist/integrations/harnesses/claude/session-log.js +27 -75
- package/dist/integrations/harnesses/codex/agent-builder.js +8 -7
- package/dist/integrations/harnesses/codex/index.js +2 -13
- package/dist/integrations/harnesses/copilot/agent-builder.js +9 -9
- package/dist/integrations/harnesses/copilot/index.js +1 -13
- package/dist/integrations/harnesses/gemini/agent-builder.js +8 -9
- package/dist/integrations/harnesses/gemini/index.js +1 -13
- package/dist/integrations/harnesses/ids.js +24 -0
- package/dist/integrations/harnesses/index.js +31 -33
- package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
- package/dist/integrations/harnesses/opencode/config-import.js +1 -3
- package/dist/integrations/harnesses/opencode/index.js +1 -18
- package/dist/integrations/harnesses/opencode/session-log.js +67 -125
- package/dist/integrations/harnesses/opencode-sdk/harness.js +3 -17
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +274 -191
- package/dist/integrations/harnesses/openhands/agent-builder.js +12 -10
- package/dist/integrations/harnesses/openhands/index.js +2 -12
- package/dist/integrations/harnesses/pi/agent-builder.js +11 -18
- package/dist/integrations/harnesses/pi/index.js +3 -16
- package/dist/integrations/harnesses/shared.js +17 -0
- package/dist/integrations/harnesses/types.js +38 -34
- package/dist/integrations/lockfile.js +211 -24
- package/dist/integrations/session-logs/index.js +24 -40
- package/dist/integrations/session-logs/provider-base.js +113 -0
- package/dist/llm/client.js +182 -110
- package/dist/llm/embedders/deterministic.js +2 -2
- package/dist/llm/embedders/remote.js +21 -9
- package/dist/llm/feature-gate.js +17 -57
- package/dist/llm/graph-extract.js +12 -13
- package/dist/llm/index-passes.js +8 -42
- package/dist/llm/memory-infer.js +144 -1
- package/dist/llm/metadata-enhance.js +45 -30
- package/dist/llm/structured-call.js +16 -8
- package/dist/llm/usage-persist.js +30 -5
- package/dist/llm/usage-telemetry.js +59 -6
- package/dist/output/cli-hints.js +1 -2
- package/dist/output/command-registry.js +27 -0
- package/dist/output/context.js +22 -7
- package/dist/output/format-exempt.js +80 -0
- package/dist/output/generic-render.js +251 -0
- package/dist/output/html-render.js +11 -16
- package/dist/output/render-registry.js +57 -0
- package/dist/output/renderers.js +15 -281
- package/dist/output/shapes/curate.js +10 -1
- package/dist/output/shapes/events.js +12 -7
- package/dist/output/shapes/helpers.js +58 -84
- package/dist/output/shapes/passthrough.js +8 -40
- package/dist/output/shapes/proposal/producer.js +15 -7
- package/dist/output/shapes/registry.js +12 -6
- package/dist/output/shapes.js +0 -9
- package/dist/output/text/{init.js → bundle-create.js} +3 -1
- package/dist/output/text/bundle-show.js +7 -0
- package/dist/output/text/command-format.js +562 -0
- package/dist/output/text/env.js +1 -3
- package/dist/output/text/events.js +8 -7
- package/dist/output/text/helpers.js +15 -1375
- package/dist/output/text/proposal/producer.js +4 -2
- package/dist/output/text/proposal-format.js +202 -0
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/registry.js +12 -6
- package/dist/output/text/show-directives.js +117 -0
- package/dist/output/text/show-format.js +103 -0
- package/dist/output/text/sync.js +5 -0
- package/dist/output/text/workflow-format.js +332 -0
- package/dist/output/text/workflow.js +1 -2
- package/dist/output/text.js +10 -19
- package/dist/registry/factory.js +4 -6
- package/dist/registry/origin-resolve.js +16 -27
- package/dist/registry/providers/skills-sh.js +3 -3
- package/dist/registry/providers/static-index.js +15 -25
- package/dist/registry/resolve.js +43 -94
- package/dist/registry/semver.js +43 -0
- package/dist/runtime.js +81 -12
- package/dist/scripts/akm-migrate.js +35529 -0
- package/dist/setup/detect.js +5 -7
- package/dist/setup/detected-engines.js +136 -0
- package/dist/setup/engine-config.js +100 -0
- package/dist/setup/registry-stash-loader.js +3 -3
- package/dist/setup/semantic-assets.js +12 -9
- package/dist/setup/setup.js +444 -208
- package/dist/setup/steps/connection-shared.js +120 -0
- package/dist/setup/steps/connection.js +108 -305
- package/dist/setup/steps/platforms.js +13 -12
- package/dist/setup/steps/semantic.js +15 -3
- package/dist/setup/steps/sources.js +21 -15
- package/dist/setup/steps/stashdir.js +6 -4
- package/dist/setup/steps/tasks.js +236 -119
- package/dist/setup/steps.js +3 -2
- package/dist/sources/freshness.js +39 -0
- package/dist/sources/provider-factory.js +11 -17
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +278 -34
- package/dist/sources/providers/git-provider.js +54 -56
- package/dist/sources/providers/git-stash.js +420 -91
- package/dist/sources/providers/git.js +2 -2
- package/dist/sources/providers/npm.js +16 -19
- package/dist/sources/providers/provider-utils.js +47 -22
- package/dist/sources/providers/sync-from-ref.js +3 -9
- package/dist/sources/providers/website.js +2 -2
- package/dist/sources/resolve.js +11 -10
- package/dist/sources/snapshot-fetchers/types.js +4 -0
- package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
- package/dist/storage/database.js +60 -4
- package/dist/storage/engines/sqlite-migrations.js +156 -5
- package/dist/storage/locations.js +1 -2
- package/dist/storage/repositories/canaries-repository.js +1 -1
- package/dist/storage/repositories/events-repository.js +51 -11
- package/dist/storage/repositories/improve-runs-repository.js +6 -32
- package/dist/storage/repositories/index-connection.js +79 -0
- package/dist/storage/repositories/index-db.js +4 -3
- package/dist/storage/repositories/index-entries-repository.js +863 -0
- package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
- package/dist/storage/repositories/index-entry-types.js +4 -0
- package/dist/storage/repositories/index-fts-repository.js +167 -0
- package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
- package/dist/storage/repositories/index-meta-repository.js +49 -0
- package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
- package/dist/storage/repositories/index-sql.js +12 -0
- package/dist/storage/repositories/index-utility-repository.js +356 -0
- package/dist/storage/repositories/index-vec-repository.js +250 -0
- package/dist/storage/repositories/outcome-repository.js +119 -0
- package/dist/storage/repositories/proposals-repository.js +317 -75
- package/dist/storage/repositories/registry-cache.js +1 -1
- package/dist/storage/repositories/salience-repository.js +172 -0
- package/dist/storage/repositories/task-history-repository.js +110 -3
- package/dist/storage/repositories/workflow-runs-repository.js +68 -35
- package/dist/tasks/backends/cron.js +169 -46
- package/dist/tasks/backends/exec-utils.js +76 -3
- package/dist/tasks/backends/index.js +6 -9
- package/dist/tasks/backends/launchd.js +292 -55
- package/dist/tasks/backends/schtasks.js +557 -70
- package/dist/tasks/backends/types.js +4 -0
- package/dist/tasks/command-executable.js +93 -0
- package/dist/tasks/embedded.js +56 -38
- package/dist/tasks/parser.js +156 -64
- package/dist/tasks/resolve-akm-bin.js +144 -51
- package/dist/tasks/runner.js +377 -209
- package/dist/tasks/schedule.js +108 -19
- package/dist/tasks/scheduler-invocation.js +296 -0
- package/dist/tasks/schema.js +1 -1
- package/dist/tasks/task-id.js +35 -0
- package/dist/tasks/validator.js +30 -16
- package/dist/workflows/authoring/authoring.js +96 -148
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/cli.js +0 -20
- package/dist/workflows/concurrency-policy.js +15 -0
- package/dist/workflows/exec/brief.js +25 -59
- package/dist/workflows/exec/frozen-judge.js +47 -0
- package/dist/workflows/exec/native-executor.js +157 -94
- package/dist/workflows/exec/report.js +365 -200
- package/dist/workflows/exec/run-workflow.js +46 -40
- package/dist/workflows/exec/scheduler.js +12 -41
- package/dist/workflows/exec/step-work.js +239 -205
- package/dist/workflows/exec/workflow-engine-gate.js +67 -0
- package/dist/workflows/ir/compile.js +141 -283
- package/dist/workflows/ir/freeze.js +233 -0
- package/dist/workflows/ir/plan-hash.js +40 -5
- package/dist/workflows/ir/schema.js +537 -1
- package/dist/workflows/parser.js +878 -306
- package/dist/workflows/program/expressions.js +20 -208
- package/dist/workflows/program/schema.js +7 -10
- package/dist/workflows/renderer.js +99 -121
- package/dist/workflows/resource-limits.js +22 -0
- package/dist/workflows/runtime/checkin.js +1 -1
- package/dist/workflows/runtime/plan-classifier.js +131 -0
- package/dist/workflows/runtime/runs.js +200 -113
- package/dist/workflows/runtime/unit-checkin.js +1 -1
- package/dist/workflows/runtime/unit-phases.js +20 -0
- package/dist/workflows/runtime/workflow-asset-loader.js +235 -97
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +4 -26
- package/dist/workflows/validator.js +52 -30
- package/docs/README.md +42 -78
- package/docs/migration/README.md +8 -0
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +9 -8
- package/docs/migration/release-notes/0.9.0.md +158 -14
- package/docs/migration/v0.7-to-v0.8.md +46 -47
- package/docs/migration/v0.8-to-v0.9.md +844 -0
- package/docs/reference/README.md +12 -0
- package/docs/reference/data-and-telemetry.md +333 -0
- package/package.json +21 -17
- package/schemas/akm-asset-envelope.json +93 -0
- package/schemas/akm-config.json +4636 -0
- package/schemas/akm-task.json +87 -0
- package/{dist/schemas → schemas}/akm-workflow.json +127 -82
- package/dist/akm-migrate-storage +0 -38
- package/dist/assets/help/help-accept.md +0 -12
- package/dist/assets/help/help-improve.md +0 -84
- package/dist/assets/help/help-proposals.md +0 -17
- package/dist/assets/help/help-propose.md +0 -17
- package/dist/assets/help/help-reject.md +0 -11
- package/dist/assets/profiles/frequent.json +0 -13
- package/dist/assets/profiles/recombine-only.json +0 -21
- package/dist/assets/profiles/reflect-distill.json +0 -30
- package/dist/assets/profiles/synthesize.json +0 -15
- package/dist/assets/prompts/procedural-system.md +0 -44
- package/dist/assets/prompts/recombine-system.md +0 -40
- package/dist/assets/prompts/staleness-detect-system.md +0 -6
- package/dist/assets/tasks/core/backup.yml +0 -4
- package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
- package/dist/assets/templates/html/default.html +0 -78
- package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
- package/dist/assets/wiki/index-template.md +0 -12
- package/dist/assets/wiki/ingest-workflow-template.md +0 -83
- package/dist/assets/wiki/log-template.md +0 -8
- package/dist/assets/wiki/schema-template.md +0 -61
- package/dist/cli/config-migrate.js +0 -150
- package/dist/cli/config-validate.js +0 -39
- package/dist/commands/graph/graph-cli.js +0 -124
- package/dist/commands/graph/graph.js +0 -487
- package/dist/commands/improve/calibration.js +0 -161
- package/dist/commands/improve/dedup.js +0 -482
- package/dist/commands/improve/extract-watch.js +0 -140
- package/dist/commands/improve/hot-probation.js +0 -45
- package/dist/commands/improve/improve-auto-accept.js +0 -276
- package/dist/commands/improve/improve-profiles.js +0 -168
- package/dist/commands/improve/procedural.js +0 -398
- package/dist/commands/improve/recombine.js +0 -818
- package/dist/commands/improve/schema-similarity-gate.js +0 -168
- package/dist/commands/lint/agent-linter.js +0 -44
- package/dist/commands/lint/command-linter.js +0 -44
- package/dist/commands/lint/default-linter.js +0 -16
- package/dist/commands/lint/fact-linter.js +0 -39
- package/dist/commands/lint/knowledge-linter.js +0 -16
- package/dist/commands/lint/memory-linter.js +0 -61
- package/dist/commands/lint/registry.js +0 -41
- package/dist/commands/lint/skill-linter.js +0 -45
- package/dist/commands/lint/task-linter.js +0 -50
- package/dist/commands/lint/workflow-linter.js +0 -81
- package/dist/commands/proposal/legacy-import.js +0 -115
- package/dist/commands/sources/history.js +0 -196
- package/dist/commands/tasks/default-tasks.js +0 -186
- package/dist/commands/wiki-cli.js +0 -292
- package/dist/core/asset/asset-registry.js +0 -76
- package/dist/core/asset/asset-spec.js +0 -316
- package/dist/core/config/config-migration.js +0 -602
- package/dist/core/deep-merge.js +0 -38
- package/dist/core/eval/rank-metrics.js +0 -113
- package/dist/core/ripgrep/install.js +0 -163
- package/dist/core/ripgrep/resolve.js +0 -81
- package/dist/indexer/db/db.js +0 -1414
- package/dist/indexer/manifest.js +0 -170
- package/dist/indexer/passes/metadata-contributors.js +0 -31
- package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
- package/dist/integrations/harnesses/opencode-sdk/index.js +0 -25
- package/dist/llm/call-ai.js +0 -62
- package/dist/llm/memory-infer-impl.js +0 -138
- package/dist/output/shapes/distill.js +0 -14
- package/dist/output/shapes/history.js +0 -11
- package/dist/output/text/distill.js +0 -6
- package/dist/output/text/enable-disable.js +0 -8
- package/dist/output/text/history.js +0 -6
- package/dist/output/text/wiki.js +0 -16
- package/dist/registry/build-index.js +0 -386
- package/dist/schemas/akm-config.json +0 -14225
- package/dist/scripts/migrate-storage.js +0 -13169
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -10169
- package/dist/scripts/migrations/v16-to-v17.js +0 -141
- package/dist/setup/legacy-config.js +0 -106
- package/dist/storage/repositories/consolidation-repository.js +0 -38
- package/dist/storage/repositories/recombine-repository.js +0 -213
- package/dist/wiki/wiki-templates.js +0 -15
- package/dist/wiki/wiki.js +0 -1012
- package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
- package/dist/workflows/db.js +0 -350
- package/dist/workflows/exec/watch.js +0 -116
- package/dist/workflows/program/parser.js +0 -760
- package/dist/workflows/program/project.js +0 -105
- package/docs/data-and-telemetry.md +0 -227
- package/docs/migration/release-notes/0.9.0-beta.60.md +0 -19
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
package/dist/tasks/schedule.js
CHANGED
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
* • a launchd plist `<StartCalendarInterval>` / `<StartInterval>` (macOS),
|
|
16
16
|
* • Task Scheduler XML triggers (Windows).
|
|
17
17
|
*
|
|
18
|
-
* The shared subset is `*`, single integers, `*\/N`, plus the `@hourly /
|
|
18
|
+
* The shared subset is `*`, single integers, `*\/N`, `A-B/N`, plus the `@hourly /
|
|
19
19
|
* @daily / @weekly / @monthly` aliases. Patterns outside that — multi-value
|
|
20
|
-
* lists, ranges,
|
|
20
|
+
* lists, plain ranges, day-of-month AND
|
|
21
21
|
* day-of-week combinations — are rejected with a {@link UsageError}.
|
|
22
22
|
*
|
|
23
23
|
* Cron is the most permissive of the three backends; some patterns it
|
|
@@ -41,9 +41,9 @@ const FIELD_LIMITS = {
|
|
|
41
41
|
month: { min: 1, max: 12 },
|
|
42
42
|
dow: { min: 0, max: 6 },
|
|
43
43
|
};
|
|
44
|
-
const SUPPORTED_HINT = "Supported subset: `*`, single integers (`5`),
|
|
44
|
+
const SUPPORTED_HINT = "Supported subset: `*`, single integers (`5`), steps (`*/N`, `A-B/N`), and comma lists (`7,37`). " +
|
|
45
45
|
"Aliases: `@hourly`, `@daily`, `@weekly`, `@monthly`. " +
|
|
46
|
-
"
|
|
46
|
+
"Plain ranges and named days/months are not supported.";
|
|
47
47
|
export function parseSchedule(input, backend) {
|
|
48
48
|
const cron = expandAlias(input);
|
|
49
49
|
const fields = parseCronFields(cron, input);
|
|
@@ -99,6 +99,16 @@ function parseField(raw, name, limit, original) {
|
|
|
99
99
|
}
|
|
100
100
|
return { kind: "step", step };
|
|
101
101
|
}
|
|
102
|
+
const rangeStepMatch = raw.match(/^(\d+)-(\d+)\/(\d+)$/);
|
|
103
|
+
if (rangeStepMatch) {
|
|
104
|
+
const start = Number(rangeStepMatch[1]);
|
|
105
|
+
const end = Number(rangeStepMatch[2]);
|
|
106
|
+
const step = Number(rangeStepMatch[3]);
|
|
107
|
+
if (start < limit.min || end > limit.max || start > end || step <= 0) {
|
|
108
|
+
throw new UsageError(`Invalid ${name} range-step "${raw}" in schedule "${original}" (allowed ${limit.min}-${limit.max}).`, "INVALID_FLAG_VALUE");
|
|
109
|
+
}
|
|
110
|
+
return { kind: "rangeStep", start, end, step };
|
|
111
|
+
}
|
|
102
112
|
if (/^\d+$/.test(raw)) {
|
|
103
113
|
const value = Number(raw);
|
|
104
114
|
if (value < limit.min || value > limit.max) {
|
|
@@ -128,22 +138,28 @@ export function translateToCron(spec) {
|
|
|
128
138
|
}
|
|
129
139
|
export function translateToLaunchd(spec) {
|
|
130
140
|
const f = spec.fields;
|
|
131
|
-
|
|
132
|
-
|
|
141
|
+
rejectDomDowCombination(spec, "macOS launchd");
|
|
142
|
+
// Expand minute steps into clock-minute anchors. StartInterval would drift
|
|
143
|
+
// from cron whenever the agent is loaded away from a matching boundary.
|
|
144
|
+
if ((f.minute.kind === "step" || f.minute.kind === "rangeStep") &&
|
|
133
145
|
f.hour.kind === "star" &&
|
|
134
146
|
f.dom.kind === "star" &&
|
|
135
147
|
f.month.kind === "star" &&
|
|
136
148
|
f.dow.kind === "star") {
|
|
137
|
-
return {
|
|
149
|
+
return { calendars: expandFieldValues(f.minute, FIELD_LIMITS.minute).map((Minute) => ({ Minute })) };
|
|
138
150
|
}
|
|
139
|
-
//
|
|
151
|
+
// Likewise, anchor hour steps to the same hours cron selects each day.
|
|
140
152
|
if (f.minute.kind === "value" &&
|
|
141
|
-
f.
|
|
142
|
-
f.hour.kind === "step" &&
|
|
153
|
+
(f.hour.kind === "step" || f.hour.kind === "rangeStep") &&
|
|
143
154
|
f.dom.kind === "star" &&
|
|
144
155
|
f.month.kind === "star" &&
|
|
145
156
|
f.dow.kind === "star") {
|
|
146
|
-
return {
|
|
157
|
+
return {
|
|
158
|
+
calendars: expandFieldValues(f.hour, FIELD_LIMITS.hour).map((Hour) => ({
|
|
159
|
+
Minute: f.minute.kind === "value" ? f.minute.value : 0,
|
|
160
|
+
Hour,
|
|
161
|
+
})),
|
|
162
|
+
};
|
|
147
163
|
}
|
|
148
164
|
// Otherwise build a calendar dict from concrete values. launchd treats any
|
|
149
165
|
// omitted key as "every value", so a `*` field translates to "no key".
|
|
@@ -166,39 +182,101 @@ export function translateToLaunchd(spec) {
|
|
|
166
182
|
if (f.dow.kind === "value")
|
|
167
183
|
calendar.Weekday = f.dow.value;
|
|
168
184
|
// launchd's CalendarInterval requires at least one specific key. If every
|
|
169
|
-
//
|
|
170
|
-
//
|
|
185
|
+
// Expand every-minute to explicit minute boundaries rather than a
|
|
186
|
+
// load-relative 60-second interval.
|
|
171
187
|
if (Object.keys(calendar).length === 0) {
|
|
172
|
-
return {
|
|
188
|
+
return {
|
|
189
|
+
calendars: expandFieldValues({ kind: "step", step: 1 }, FIELD_LIMITS.minute).map((Minute) => ({ Minute })),
|
|
190
|
+
};
|
|
173
191
|
}
|
|
174
192
|
return { calendar };
|
|
175
193
|
}
|
|
194
|
+
function expandFieldValues(field, limit) {
|
|
195
|
+
const start = field.kind === "rangeStep" ? field.start : limit.min;
|
|
196
|
+
const end = field.kind === "rangeStep" ? field.end : limit.max;
|
|
197
|
+
const values = [];
|
|
198
|
+
for (let value = start; value <= end; value += field.step)
|
|
199
|
+
values.push(value);
|
|
200
|
+
return values;
|
|
201
|
+
}
|
|
176
202
|
function rejectStepInsideCalendar(field, name, spec) {
|
|
177
203
|
if (field.kind === "step") {
|
|
178
204
|
throw new UsageError(`Schedule "${spec.raw}" uses step (${name} = */N) in a position macOS launchd cannot express. ${SUPPORTED_HINT}`, "INVALID_FLAG_VALUE", "Either restrict the step to the minute or hour field only, or rewrite the schedule with concrete values.");
|
|
179
205
|
}
|
|
206
|
+
if (field.kind === "rangeStep") {
|
|
207
|
+
throw new UsageError(`Schedule "${spec.raw}" uses range-step (${name} = A-B/N) in a position macOS launchd cannot express. ${SUPPORTED_HINT}`, "INVALID_FLAG_VALUE", "Restrict the range-step to the minute or hour field, or rewrite the schedule with a concrete value.");
|
|
208
|
+
}
|
|
180
209
|
if (field.kind === "list") {
|
|
181
210
|
throw new UsageError(`Schedule "${spec.raw}" uses comma list (${name} = a,b,...) which macOS launchd cannot express as a single trigger. ${SUPPORTED_HINT}`, "INVALID_FLAG_VALUE", "Either install one task per list element, or rewrite the schedule with a step (`*/N`) or single value.");
|
|
182
211
|
}
|
|
183
212
|
}
|
|
213
|
+
const MAX_SCHTASKS_TRIGGERS = 48;
|
|
184
214
|
export function translateToSchtasks(spec) {
|
|
185
215
|
const f = spec.fields;
|
|
186
|
-
|
|
216
|
+
rejectDomDowCombination(spec, "Windows Task Scheduler");
|
|
217
|
+
// A repetition interval is cron-equivalent indefinitely only when it divides
|
|
218
|
+
// the field's wall-clock cycle. Other steps must reset at every hour.
|
|
187
219
|
if (f.minute.kind === "step" &&
|
|
188
220
|
f.hour.kind === "star" &&
|
|
189
221
|
f.dom.kind === "star" &&
|
|
190
222
|
f.month.kind === "star" &&
|
|
191
223
|
f.dow.kind === "star") {
|
|
224
|
+
if (60 % f.minute.step !== 0) {
|
|
225
|
+
return minuteValuesTrigger(expandFieldValues(f.minute, FIELD_LIMITS.minute), spec);
|
|
226
|
+
}
|
|
192
227
|
return { kind: "minute", everyMinutes: f.minute.step };
|
|
193
228
|
}
|
|
194
|
-
|
|
229
|
+
if (f.minute.kind === "rangeStep" &&
|
|
230
|
+
f.hour.kind === "star" &&
|
|
231
|
+
f.dom.kind === "star" &&
|
|
232
|
+
f.month.kind === "star" &&
|
|
233
|
+
f.dow.kind === "star") {
|
|
234
|
+
if (f.minute.start === FIELD_LIMITS.minute.min && f.minute.end === FIELD_LIMITS.minute.max) {
|
|
235
|
+
if (60 % f.minute.step === 0)
|
|
236
|
+
return { kind: "minute", everyMinutes: f.minute.step };
|
|
237
|
+
}
|
|
238
|
+
return minuteValuesTrigger(expandFieldValues(f.minute, FIELD_LIMITS.minute), spec);
|
|
239
|
+
}
|
|
240
|
+
// Fixed-minute hour schedules can use one daily-reset repetition only when
|
|
241
|
+
// the interval divides 24 hours. Non-divisors become explicit daily times.
|
|
195
242
|
if (f.minute.kind === "value" &&
|
|
196
|
-
f.minute.value === 0 &&
|
|
197
243
|
f.hour.kind === "step" &&
|
|
198
244
|
f.dom.kind === "star" &&
|
|
199
245
|
f.month.kind === "star" &&
|
|
200
246
|
f.dow.kind === "star") {
|
|
201
|
-
|
|
247
|
+
if (24 % f.hour.step === 0 && f.hour.step < 24) {
|
|
248
|
+
return { kind: "hour", everyHours: f.hour.step, atMinute: f.minute.value };
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
kind: "hourValues",
|
|
252
|
+
hours: expandFieldValues(f.hour, FIELD_LIMITS.hour),
|
|
253
|
+
atMinute: f.minute.value,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
if (f.minute.kind === "value" &&
|
|
257
|
+
f.hour.kind === "rangeStep" &&
|
|
258
|
+
f.dom.kind === "star" &&
|
|
259
|
+
f.month.kind === "star" &&
|
|
260
|
+
f.dow.kind === "star") {
|
|
261
|
+
if (f.hour.start === FIELD_LIMITS.hour.min && f.hour.end === FIELD_LIMITS.hour.max) {
|
|
262
|
+
if (24 % f.hour.step === 0 && f.hour.step < 24) {
|
|
263
|
+
return { kind: "hour", everyHours: f.hour.step, atMinute: f.minute.value };
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
kind: "hourValues",
|
|
268
|
+
hours: expandFieldValues(f.hour, FIELD_LIMITS.hour),
|
|
269
|
+
atMinute: f.minute.value,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
// `M * * * *` includes the shipped top-of-hour task and arbitrary fixed
|
|
273
|
+
// minutes. A daily calendar trigger resets the hourly repetition each day.
|
|
274
|
+
if (f.minute.kind === "value" &&
|
|
275
|
+
f.hour.kind === "star" &&
|
|
276
|
+
f.dom.kind === "star" &&
|
|
277
|
+
f.month.kind === "star" &&
|
|
278
|
+
f.dow.kind === "star") {
|
|
279
|
+
return { kind: "hour", everyHours: 1, atMinute: f.minute.value };
|
|
202
280
|
}
|
|
203
281
|
// `M H * * *` → DAILY at H:M.
|
|
204
282
|
if (f.minute.kind === "value" &&
|
|
@@ -221,7 +299,18 @@ export function translateToSchtasks(spec) {
|
|
|
221
299
|
daysOfWeek: [f.dow.value],
|
|
222
300
|
};
|
|
223
301
|
}
|
|
224
|
-
throw new UsageError(`Schedule "${spec.raw}" cannot be expressed as a Windows Task Scheduler trigger. ${SUPPORTED_HINT}`, "INVALID_FLAG_VALUE", "Use one of:
|
|
302
|
+
throw new UsageError(`Schedule "${spec.raw}" cannot be expressed as a Windows Task Scheduler trigger. ${SUPPORTED_HINT}`, "INVALID_FLAG_VALUE", "Use one of: minute steps/range-steps, fixed-minute hour steps/range-steps, hourly, daily, or weekly on a single weekday.");
|
|
303
|
+
}
|
|
304
|
+
function minuteValuesTrigger(minutes, spec) {
|
|
305
|
+
if (minutes.length > MAX_SCHTASKS_TRIGGERS) {
|
|
306
|
+
throw new UsageError(`Schedule "${spec.raw}" requires ${minutes.length} native triggers; Windows Task Scheduler allows at most ${MAX_SCHTASKS_TRIGGERS}.`, "INVALID_FLAG_VALUE", "Use a full-field step whose interval divides 60, or reduce the minute range.");
|
|
307
|
+
}
|
|
308
|
+
return { kind: "minuteValues", minutes };
|
|
309
|
+
}
|
|
310
|
+
function rejectDomDowCombination(spec, backend) {
|
|
311
|
+
if (spec.fields.dom.kind !== "star" && spec.fields.dow.kind !== "star") {
|
|
312
|
+
throw new UsageError(`Schedule "${spec.raw}": day-of-month and day-of-week use OR semantics in cron, which ${backend} cannot express portably.`, "INVALID_FLAG_VALUE", "Use either day-of-month or day-of-week, but not both.");
|
|
313
|
+
}
|
|
225
314
|
}
|
|
226
315
|
/** Human-readable summary used by `tasks doctor`. */
|
|
227
316
|
export const SCHEDULE_SUPPORTED_SUBSET_HINT = SUPPORTED_HINT;
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { resolveStashDir } from "../core/common.js";
|
|
8
|
+
import { ConfigError } from "../core/errors.js";
|
|
9
|
+
import { getCacheDir, getConfigDir, getDataDir, getTaskContextDir } from "../core/paths.js";
|
|
10
|
+
export const SCHEDULED_TASK_CONTEXT_KEYS = [
|
|
11
|
+
"AKM_BUNDLE_DIR",
|
|
12
|
+
"AKM_CONFIG_DIR",
|
|
13
|
+
"AKM_DATA_DIR",
|
|
14
|
+
"AKM_CACHE_DIR",
|
|
15
|
+
"AKM_STATE_DIR",
|
|
16
|
+
];
|
|
17
|
+
export const SCHEDULER_CONTEXT_ARG = "--scheduler-context";
|
|
18
|
+
/** Resolve the complete non-secret AKM directory context captured by schedulers. */
|
|
19
|
+
export function resolveScheduledTaskContext(env = process.env, platform = process.platform) {
|
|
20
|
+
return canonicalContext({
|
|
21
|
+
AKM_BUNDLE_DIR: path.resolve(resolveStashDir(env)),
|
|
22
|
+
AKM_CONFIG_DIR: path.resolve(getConfigDir(env, platform)),
|
|
23
|
+
AKM_DATA_DIR: path.resolve(getDataDir(env, platform)),
|
|
24
|
+
AKM_CACHE_DIR: path.resolve(getCacheDir(env)),
|
|
25
|
+
// Capture the complete process directory context used by scheduled commands.
|
|
26
|
+
AKM_STATE_DIR: path.resolve(resolveStateDir(env, platform)),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the one scheduler-generated argv shape consumed by all backends.
|
|
31
|
+
*
|
|
32
|
+
* `target` records the bundle a non-primary task lives in as a `--bundle
|
|
33
|
+
* <bundle>` token so the scheduled `akm task run` resolves the task (and its
|
|
34
|
+
* relative asset refs) from that bundle. It is emitted ONLY when supplied and
|
|
35
|
+
* non-empty — callers pass it exclusively for a non-default bundle, so a
|
|
36
|
+
* primary-bundle (or default) task omits the target pair.
|
|
37
|
+
*/
|
|
38
|
+
export function buildScheduledTaskInvocation(akmArgv, id, contextPath, target) {
|
|
39
|
+
const targetArgs = target !== undefined && target !== "" ? ["--bundle", target] : [];
|
|
40
|
+
return {
|
|
41
|
+
argv: [
|
|
42
|
+
...akmArgv,
|
|
43
|
+
SCHEDULER_CONTEXT_ARG,
|
|
44
|
+
assertAbsolutePath(contextPath),
|
|
45
|
+
"task",
|
|
46
|
+
"run",
|
|
47
|
+
id,
|
|
48
|
+
...targetArgs,
|
|
49
|
+
"--scheduled",
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function schedulerContextDescriptor(context = resolveScheduledTaskContext(), envPath = process.env.PATH ?? "") {
|
|
54
|
+
return {
|
|
55
|
+
version: 1,
|
|
56
|
+
environment: { ...canonicalContext(context), PATH: validatePathValue(envPath) },
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function schedulerContextPath(descriptor) {
|
|
60
|
+
const bytes = serializeDescriptor(descriptor);
|
|
61
|
+
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
62
|
+
return path.join(getTaskContextDir(descriptor.environment), `${digest}.json`);
|
|
63
|
+
}
|
|
64
|
+
/** Write a content-addressed descriptor without ever replacing existing content. */
|
|
65
|
+
export function writeSchedulerContextDescriptor(descriptor = schedulerContextDescriptor()) {
|
|
66
|
+
const file = schedulerContextPath(descriptor);
|
|
67
|
+
const bytes = serializeDescriptor(descriptor);
|
|
68
|
+
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
69
|
+
if (process.platform !== "win32") {
|
|
70
|
+
fs.chmodSync(path.dirname(file), 0o700);
|
|
71
|
+
}
|
|
72
|
+
if (lstatIfExists(file)) {
|
|
73
|
+
if (serializeDescriptor(validateSchedulerContextDescriptor(file)) !== bytes)
|
|
74
|
+
throw invalidSchedulerContext();
|
|
75
|
+
return file;
|
|
76
|
+
}
|
|
77
|
+
const temp = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${Date.now()}.tmp`);
|
|
78
|
+
try {
|
|
79
|
+
fs.writeFileSync(temp, bytes, { encoding: "utf8", mode: 0o600, flag: "wx" });
|
|
80
|
+
try {
|
|
81
|
+
fs.renameSync(temp, file);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (!lstatIfExists(file) || serializeDescriptor(validateSchedulerContextDescriptor(file)) !== bytes)
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
restrictDescriptor(file);
|
|
88
|
+
validateSchedulerContextDescriptor(file);
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
fs.rmSync(temp, { force: true });
|
|
92
|
+
}
|
|
93
|
+
return file;
|
|
94
|
+
}
|
|
95
|
+
export function loadSchedulerContextDescriptor(file, env = process.env) {
|
|
96
|
+
const descriptor = validateSchedulerContextDescriptor(file);
|
|
97
|
+
for (const key of SCHEDULED_TASK_CONTEXT_KEYS)
|
|
98
|
+
env[key] = descriptor.environment[key];
|
|
99
|
+
env.PATH = descriptor.environment.PATH;
|
|
100
|
+
}
|
|
101
|
+
export function validateSchedulerContextDescriptor(file) {
|
|
102
|
+
const absolute = assertAbsolutePath(file);
|
|
103
|
+
let linkStat;
|
|
104
|
+
try {
|
|
105
|
+
linkStat = fs.lstatSync(absolute);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw schedulerContextFileError(absolute, error instanceof Error ? error.message : String(error));
|
|
109
|
+
}
|
|
110
|
+
if (linkStat.isSymbolicLink())
|
|
111
|
+
throw schedulerContextFileError(absolute, "symbolic links are not allowed");
|
|
112
|
+
if (!linkStat.isFile())
|
|
113
|
+
throw schedulerContextFileError(absolute, "path is not a regular file");
|
|
114
|
+
let descriptorBytes;
|
|
115
|
+
let fd;
|
|
116
|
+
try {
|
|
117
|
+
const noFollow = process.platform === "win32" ? 0 : fs.constants.O_NOFOLLOW;
|
|
118
|
+
fd = fs.openSync(absolute, fs.constants.O_RDONLY | noFollow);
|
|
119
|
+
const stat = fs.fstatSync(fd);
|
|
120
|
+
if (!stat.isFile())
|
|
121
|
+
throw schedulerContextFileError(absolute, "path is not a regular file");
|
|
122
|
+
if (process.platform !== "win32") {
|
|
123
|
+
if (typeof process.getuid !== "function") {
|
|
124
|
+
throw schedulerContextFileError(absolute, "current uid is unavailable for ownership verification");
|
|
125
|
+
}
|
|
126
|
+
const uid = process.getuid();
|
|
127
|
+
if (stat.uid !== uid)
|
|
128
|
+
throw schedulerContextFileError(absolute, `file owner ${stat.uid} does not match uid ${uid}`);
|
|
129
|
+
if ((stat.mode & 0o077) !== 0) {
|
|
130
|
+
throw schedulerContextFileError(absolute, "group or other permissions must be disabled");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
descriptorBytes = fs.readFileSync(fd);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error instanceof ConfigError)
|
|
137
|
+
throw error;
|
|
138
|
+
throw schedulerContextFileError(absolute, error instanceof Error ? error.message : String(error));
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
if (fd !== undefined)
|
|
142
|
+
fs.closeSync(fd);
|
|
143
|
+
}
|
|
144
|
+
const filename = path.basename(absolute);
|
|
145
|
+
const match = /^([a-f0-9]{64})\.json$/.exec(filename);
|
|
146
|
+
const digest = createHash("sha256").update(descriptorBytes).digest("hex");
|
|
147
|
+
if (!match || match[1] !== digest) {
|
|
148
|
+
throw schedulerContextFileError(absolute, "content SHA-256 does not match the descriptor filename");
|
|
149
|
+
}
|
|
150
|
+
let parsed;
|
|
151
|
+
try {
|
|
152
|
+
parsed = JSON.parse(descriptorBytes.toString("utf8"));
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
throw schedulerContextFileError(absolute, error instanceof Error ? error.message : String(error));
|
|
156
|
+
}
|
|
157
|
+
return canonicalDescriptor(parsed);
|
|
158
|
+
}
|
|
159
|
+
/** Load and remove the hidden descriptor argument before citty parses argv. */
|
|
160
|
+
export function consumeSchedulerContextArg(argv, env = process.env) {
|
|
161
|
+
const separator = argv.indexOf("--");
|
|
162
|
+
const index = argv.slice(0, separator === -1 ? argv.length : separator).indexOf(SCHEDULER_CONTEXT_ARG);
|
|
163
|
+
if (index === -1)
|
|
164
|
+
return argv;
|
|
165
|
+
const file = argv[index + 1];
|
|
166
|
+
if (!file) {
|
|
167
|
+
throw new ConfigError(`${SCHEDULER_CONTEXT_ARG} requires an absolute descriptor path.`, "INVALID_CONFIG_FILE");
|
|
168
|
+
}
|
|
169
|
+
loadSchedulerContextDescriptor(file, env);
|
|
170
|
+
return [...argv.slice(0, index), ...argv.slice(index + 2)];
|
|
171
|
+
}
|
|
172
|
+
export function parseScheduledTaskArgv(argv) {
|
|
173
|
+
const contextIndex = argv.indexOf(SCHEDULER_CONTEXT_ARG);
|
|
174
|
+
if (contextIndex < 1 || argv.indexOf(SCHEDULER_CONTEXT_ARG, contextIndex + 1) !== -1)
|
|
175
|
+
return undefined;
|
|
176
|
+
const contextPath = argv[contextIndex + 1];
|
|
177
|
+
const tasksIndex = contextIndex + 2;
|
|
178
|
+
if (!contextPath || argv[tasksIndex] !== "task" || argv[tasksIndex + 1] !== "run" || !argv[tasksIndex + 2]) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
let index = tasksIndex + 3;
|
|
182
|
+
let target;
|
|
183
|
+
if (argv[index] === "--bundle") {
|
|
184
|
+
target = argv[index + 1];
|
|
185
|
+
if (!target)
|
|
186
|
+
return undefined;
|
|
187
|
+
index += 2;
|
|
188
|
+
}
|
|
189
|
+
if (argv[index] !== "--scheduled" || index !== argv.length - 1)
|
|
190
|
+
return undefined;
|
|
191
|
+
return {
|
|
192
|
+
binding: [...argv.slice(0, contextIndex)],
|
|
193
|
+
contextPath: assertAbsolutePath(contextPath),
|
|
194
|
+
...(target !== undefined ? { target } : {}),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function canonicalContext(input) {
|
|
198
|
+
const inputKeys = Object.keys(input);
|
|
199
|
+
if (inputKeys.length !== SCHEDULED_TASK_CONTEXT_KEYS.length ||
|
|
200
|
+
inputKeys.some((key) => !SCHEDULED_TASK_CONTEXT_KEYS.includes(key))) {
|
|
201
|
+
throw invalidSchedulerContext();
|
|
202
|
+
}
|
|
203
|
+
const context = {};
|
|
204
|
+
for (const key of SCHEDULED_TASK_CONTEXT_KEYS) {
|
|
205
|
+
const value = input[key];
|
|
206
|
+
if (typeof value !== "string" ||
|
|
207
|
+
value.trim().length === 0 ||
|
|
208
|
+
containsControlCharacter(value) ||
|
|
209
|
+
(!path.posix.isAbsolute(value) && !path.win32.isAbsolute(value))) {
|
|
210
|
+
throw invalidSchedulerContext();
|
|
211
|
+
}
|
|
212
|
+
context[key] = value;
|
|
213
|
+
}
|
|
214
|
+
return context;
|
|
215
|
+
}
|
|
216
|
+
function canonicalDescriptor(input) {
|
|
217
|
+
if (typeof input !== "object" || input === null || Array.isArray(input))
|
|
218
|
+
throw invalidSchedulerContext();
|
|
219
|
+
const record = input;
|
|
220
|
+
if (Object.keys(record).length !== 2 || record.version !== 1)
|
|
221
|
+
throw invalidSchedulerContext();
|
|
222
|
+
const rawEnvironment = record.environment;
|
|
223
|
+
if (typeof rawEnvironment !== "object" || rawEnvironment === null || Array.isArray(rawEnvironment)) {
|
|
224
|
+
throw invalidSchedulerContext();
|
|
225
|
+
}
|
|
226
|
+
const environment = rawEnvironment;
|
|
227
|
+
if (Object.keys(environment).length !== SCHEDULED_TASK_CONTEXT_KEYS.length + 1)
|
|
228
|
+
throw invalidSchedulerContext();
|
|
229
|
+
const PATH = validatePathValue(environment.PATH);
|
|
230
|
+
const { PATH: _, ...rawContext } = environment;
|
|
231
|
+
return { version: 1, environment: { ...canonicalContext(rawContext), PATH } };
|
|
232
|
+
}
|
|
233
|
+
function serializeDescriptor(descriptor) {
|
|
234
|
+
return `${JSON.stringify(canonicalDescriptor(descriptor))}\n`;
|
|
235
|
+
}
|
|
236
|
+
function validatePathValue(value) {
|
|
237
|
+
if (typeof value !== "string" || containsControlCharacter(value))
|
|
238
|
+
throw invalidSchedulerContext();
|
|
239
|
+
return value;
|
|
240
|
+
}
|
|
241
|
+
function assertAbsolutePath(value) {
|
|
242
|
+
if (containsControlCharacter(value) || (!path.posix.isAbsolute(value) && !path.win32.isAbsolute(value))) {
|
|
243
|
+
throw invalidSchedulerContext();
|
|
244
|
+
}
|
|
245
|
+
return value;
|
|
246
|
+
}
|
|
247
|
+
function restrictDescriptor(file) {
|
|
248
|
+
if (process.platform !== "win32")
|
|
249
|
+
fs.chmodSync(file, 0o600);
|
|
250
|
+
}
|
|
251
|
+
function lstatIfExists(file) {
|
|
252
|
+
try {
|
|
253
|
+
return fs.lstatSync(file);
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
if (error.code === "ENOENT")
|
|
257
|
+
return undefined;
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function schedulerContextFileError(file, reason) {
|
|
262
|
+
return new ConfigError(`Invalid scheduler context descriptor "${file}": ${reason}.`, "INVALID_CONFIG_FILE");
|
|
263
|
+
}
|
|
264
|
+
function containsControlCharacter(value) {
|
|
265
|
+
for (const char of value) {
|
|
266
|
+
const code = char.codePointAt(0) ?? 0;
|
|
267
|
+
if (code < 0x20 || (code >= 0x7f && code <= 0x9f))
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
function resolveStateDir(env, platform) {
|
|
273
|
+
const override = env.AKM_STATE_DIR?.trim();
|
|
274
|
+
if (override)
|
|
275
|
+
return override;
|
|
276
|
+
if (platform === "win32") {
|
|
277
|
+
const localAppData = env.LOCALAPPDATA?.trim();
|
|
278
|
+
if (localAppData)
|
|
279
|
+
return path.join(localAppData, "akm", "state");
|
|
280
|
+
const userProfile = env.USERPROFILE?.trim();
|
|
281
|
+
if (userProfile)
|
|
282
|
+
return path.join(userProfile, "AppData", "Local", "akm", "state");
|
|
283
|
+
const appData = env.APPDATA?.trim();
|
|
284
|
+
if (appData)
|
|
285
|
+
return path.join(appData, "..", "Local", "akm", "state");
|
|
286
|
+
throw new ConfigError("Unable to determine state directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
|
|
287
|
+
}
|
|
288
|
+
const xdgStateHome = env.XDG_STATE_HOME?.trim();
|
|
289
|
+
if (xdgStateHome)
|
|
290
|
+
return path.join(xdgStateHome, "akm");
|
|
291
|
+
const home = env.HOME?.trim();
|
|
292
|
+
return home ? path.join(home, ".local", "state", "akm") : path.join("/tmp", "akm-state");
|
|
293
|
+
}
|
|
294
|
+
function invalidSchedulerContext() {
|
|
295
|
+
return new ConfigError(`Invalid scheduler context; expected exactly ${SCHEDULED_TASK_CONTEXT_KEYS.join(", ")} as absolute paths.`, "INVALID_CONFIG_FILE");
|
|
296
|
+
}
|
package/dist/tasks/schema.js
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
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 { UsageError } from "../core/errors.js";
|
|
5
|
+
const VALID_TASK_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
6
|
+
const TASK_FILE_SUFFIX_RE = /\.(?:yml|yaml)$/i;
|
|
7
|
+
const WINDOWS_RESERVED_DEVICE_RE = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\.|$)/i;
|
|
8
|
+
const WINDOWS_TASK_PATH_MAX_LENGTH = 238;
|
|
9
|
+
const WINDOWS_TASK_FOLDER_PREFIX_LENGTH = "\\akm\\".length;
|
|
10
|
+
const PORTABLE_FILENAME_COMPONENT_MAX_LENGTH = 255;
|
|
11
|
+
const LAUNCHD_FILENAME_OVERHEAD = "com.akm.task.".length + ".plist".length;
|
|
12
|
+
const TASK_FILENAME_OVERHEAD = ".yml".length;
|
|
13
|
+
const SCHTASKS_TEMP_FILENAME_OVERHEAD = "akm-task-".length + "-".length + 13 + ".xml".length;
|
|
14
|
+
export const MAX_PORTABLE_TASK_ID_LENGTH = Math.min(WINDOWS_TASK_PATH_MAX_LENGTH - WINDOWS_TASK_FOLDER_PREFIX_LENGTH, PORTABLE_FILENAME_COMPONENT_MAX_LENGTH - LAUNCHD_FILENAME_OVERHEAD, PORTABLE_FILENAME_COMPONENT_MAX_LENGTH - TASK_FILENAME_OVERHEAD, PORTABLE_FILENAME_COMPONENT_MAX_LENGTH - SCHTASKS_TEMP_FILENAME_OVERHEAD);
|
|
15
|
+
export function validateTaskId(id) {
|
|
16
|
+
if (!id) {
|
|
17
|
+
throw new UsageError("Task id must be non-empty.", "MISSING_REQUIRED_ARGUMENT");
|
|
18
|
+
}
|
|
19
|
+
if (!VALID_TASK_ID_RE.test(id)) {
|
|
20
|
+
throw new UsageError(`Task id "${id}" is invalid. Use letters, digits, dots, underscores, and dashes only.`, "INVALID_FLAG_VALUE");
|
|
21
|
+
}
|
|
22
|
+
if (id.length > MAX_PORTABLE_TASK_ID_LENGTH) {
|
|
23
|
+
throw new UsageError(`Task id "${id}" is invalid. Use at most ${MAX_PORTABLE_TASK_ID_LENGTH} characters for all supported schedulers.`, "INVALID_FLAG_VALUE");
|
|
24
|
+
}
|
|
25
|
+
if (TASK_FILE_SUFFIX_RE.test(id)) {
|
|
26
|
+
throw new UsageError(`Task id "${id}" is invalid. Use the bare task id without a .yml or .yaml suffix.`, "INVALID_FLAG_VALUE");
|
|
27
|
+
}
|
|
28
|
+
if (WINDOWS_RESERVED_DEVICE_RE.test(id)) {
|
|
29
|
+
throw new UsageError(`Task id "${id}" uses a reserved Windows device name. Choose a different task id.`, "INVALID_FLAG_VALUE");
|
|
30
|
+
}
|
|
31
|
+
return id;
|
|
32
|
+
}
|
|
33
|
+
export function normaliseTaskId(raw) {
|
|
34
|
+
return validateTaskId(raw.trim());
|
|
35
|
+
}
|
package/dist/tasks/validator.js
CHANGED
|
@@ -8,27 +8,27 @@
|
|
|
8
8
|
* • the schedule is parseable and translates to the active backend
|
|
9
9
|
* • the workflow ref resolves (workflow targets)
|
|
10
10
|
* • the asset/file source exists (prompt targets)
|
|
11
|
-
* • the
|
|
11
|
+
* • the selected engine resolves (prompt targets)
|
|
12
12
|
*
|
|
13
|
-
* Validation is deliberately split from parsing: callers that only
|
|
14
|
-
*
|
|
15
|
-
* `
|
|
13
|
+
* Validation is deliberately split from parsing: callers that only inspect
|
|
14
|
+
* task metadata (e.g. `akm show`) can skip these checks, while
|
|
15
|
+
* `task add` and `task run` should always run them.
|
|
16
16
|
*/
|
|
17
17
|
import fs from "node:fs";
|
|
18
18
|
import path from "node:path";
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
19
|
+
import { placementSpecFor } from "../core/asset/asset-placement.js";
|
|
20
|
+
import { parseRefInput } from "../core/asset/resolve-ref.js";
|
|
21
21
|
import { loadConfig } from "../core/config/config.js";
|
|
22
22
|
import { NotFoundError } from "../core/errors.js";
|
|
23
|
-
import {
|
|
23
|
+
import { resolveEngine } from "../integrations/agent/engine-resolution.js";
|
|
24
24
|
import { resolveAssetPath } from "../sources/resolve.js";
|
|
25
25
|
import { parseSchedule } from "./schedule.js";
|
|
26
26
|
export async function validateTaskDocument(task, options) {
|
|
27
27
|
// Schedule must parse and translate.
|
|
28
28
|
parseSchedule(task.schedule, options.backend);
|
|
29
29
|
if (task.target.kind === "workflow") {
|
|
30
|
-
const stashDir = options.stashDir
|
|
31
|
-
const ref =
|
|
30
|
+
const stashDir = options.stashDir;
|
|
31
|
+
const ref = parseRefInput(task.target.ref);
|
|
32
32
|
if (ref.type !== "workflow") {
|
|
33
33
|
throw new NotFoundError(`Task "${task.id}" workflow target must be a workflow ref (got "${task.target.ref}").`, "WORKFLOW_NOT_FOUND");
|
|
34
34
|
}
|
|
@@ -38,17 +38,31 @@ export async function validateTaskDocument(task, options) {
|
|
|
38
38
|
if (task.target.kind !== "prompt") {
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
|
-
// Prompt target. Resolve the
|
|
42
|
-
// set on the task,
|
|
43
|
-
//
|
|
44
|
-
// `tasks add` / `tasks sync` time is much more useful than failing only
|
|
41
|
+
// Prompt target. Resolve the engine unconditionally — when no engine is
|
|
42
|
+
// set on the task, defaults.engine is required. Catching this at
|
|
43
|
+
// `task add` / `task sync` time is much more useful than failing only
|
|
45
44
|
// when the OS scheduler fires.
|
|
46
45
|
const config = loadConfig();
|
|
47
|
-
|
|
46
|
+
const engine = task.target.engine ?? config.defaults?.engine;
|
|
47
|
+
if (!engine)
|
|
48
|
+
throw new NotFoundError(`Task "${task.id}" has no selected engine.`, "ASSET_NOT_FOUND");
|
|
49
|
+
const resolved = resolveEngine(engine, config);
|
|
50
|
+
if (task.target.llm !== undefined && resolved.kind !== "llm") {
|
|
51
|
+
throw new NotFoundError(`Task "${task.id}" uses llm overrides with non-LLM engine "${engine}".`, "ASSET_NOT_FOUND");
|
|
52
|
+
}
|
|
48
53
|
const src = task.target.source;
|
|
49
54
|
if (src.kind === "asset") {
|
|
50
|
-
const stashDir = options.stashDir
|
|
51
|
-
const ref =
|
|
55
|
+
const stashDir = options.stashDir;
|
|
56
|
+
const ref = parseRefInput(src.ref);
|
|
57
|
+
// D11 — `parseRefInput` now also accepts an opaque adapter conceptId (a
|
|
58
|
+
// ref whose leading segment is not an AKM placement dir), but
|
|
59
|
+
// `resolveAssetPath` (src/sources/resolve.ts) is placement-dir-only: it
|
|
60
|
+
// has no stash-subdir to route an opaque type through. Surface a clean
|
|
61
|
+
// domain error here rather than let that helper crash on a missing
|
|
62
|
+
// directory mapping.
|
|
63
|
+
if (placementSpecFor(ref.type) === undefined) {
|
|
64
|
+
throw new NotFoundError(`Task "${task.id}" prompt asset ref "${src.ref}" is not an AKM-placed asset — adapter-owned (opaque) prompt sources are not resolvable as task inputs yet.`, "ASSET_NOT_FOUND");
|
|
65
|
+
}
|
|
52
66
|
await resolveAssetPath(stashDir, ref.type, ref.name);
|
|
53
67
|
}
|
|
54
68
|
else if (src.kind === "file") {
|