akm-cli 0.9.0-rc.8 → 0.9.0
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 +1063 -44
- package/README.md +51 -25
- package/SECURITY.md +14 -1
- package/STABILITY.md +497 -0
- package/dist/akm +148 -35
- package/dist/{akm-migrate-storage → akm-migrate} +6 -9
- package/dist/assets/hints/cli-hints-full.md +223 -95
- package/dist/assets/hints/cli-hints-short.md +85 -22
- package/dist/assets/improve-strategies/default.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/prompts/memory-infer-user.md +2 -3
- package/dist/assets/stash-skeleton/README.md +6 -5
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
- package/dist/assets/tasks/core/extract.yml +1 -1
- package/dist/assets/tasks/core/version-check.yml +1 -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 +1 -3
- package/dist/assets/workflows/workflow-template.md +32 -15
- package/dist/cli/invocation.js +40 -15
- package/dist/cli/parse-args.js +0 -22
- package/dist/cli/retired-commands.js +121 -0
- package/dist/cli/shared.js +154 -22
- package/dist/cli/unknown-flags.js +236 -0
- package/dist/cli-node.mjs +2 -1
- package/dist/cli.js +696 -258
- package/dist/commands/agent/agent-dispatch.js +14 -3
- package/dist/commands/agent/contribute-cli.js +73 -88
- package/dist/commands/completions.js +79 -22
- package/dist/commands/config-cli.js +17 -150
- package/dist/commands/env/env-cli.js +59 -143
- package/dist/commands/env/env.js +12 -163
- package/dist/commands/env/marker-path.js +6 -0
- package/dist/commands/env/secret-cli.js +36 -66
- package/dist/commands/env/secret.js +24 -57
- package/dist/commands/feedback-cli.js +141 -87
- package/dist/commands/health/accept-rate.js +58 -0
- package/dist/commands/health/advisories.js +3 -4
- package/dist/commands/health/checks.js +85 -23
- package/dist/commands/health/html-report.js +7 -10
- package/dist/commands/health/improve-metrics.js +25 -83
- package/dist/commands/health/md-report.js +5 -9
- package/dist/commands/health/metrics.js +62 -20
- package/dist/commands/health/renderers.js +47 -0
- package/dist/commands/health/report-view-model.js +4 -5
- package/dist/commands/health/stash-exposure.js +1 -1
- package/dist/commands/health/surfaces.js +3 -48
- package/dist/commands/health/task-runs.js +3 -67
- package/dist/commands/health/types-improve.js +7 -0
- package/dist/commands/health.js +99 -28
- package/dist/commands/improve/anti-collapse.js +2 -2
- package/dist/commands/improve/autonomy-gate.js +68 -0
- package/dist/commands/improve/collapse-detector.js +41 -40
- package/dist/commands/improve/consolidate/eligibility.js +1 -23
- package/dist/commands/improve/consolidate/merge.js +4 -0
- package/dist/commands/improve/consolidate.js +140 -1000
- package/dist/commands/improve/distill/promote-memory.js +12 -12
- package/dist/commands/improve/distill/quality-gate.js +6 -6
- package/dist/commands/improve/distill.js +58 -69
- package/dist/commands/improve/eligibility.js +105 -57
- package/dist/commands/improve/extract-cli.js +14 -133
- package/dist/commands/improve/improve-cli.js +98 -114
- package/dist/commands/improve/improve-result-file.js +1 -28
- package/dist/commands/improve/improve-strategies.js +8 -5
- package/dist/commands/improve/improve.js +128 -91
- package/dist/commands/improve/loop-stages.js +182 -20
- package/dist/commands/improve/memory/derived-ref.js +45 -43
- package/dist/commands/improve/memory/memory-belief.js +1 -1
- package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
- package/dist/commands/improve/memory/memory-improve.js +6 -5
- package/dist/commands/improve/outcome-loop.js +22 -65
- package/dist/commands/improve/preparation.js +114 -123
- package/dist/commands/improve/proactive-maintenance.js +2 -5
- package/dist/commands/improve/reflect.js +56 -160
- package/dist/commands/improve/salience.js +11 -122
- package/dist/commands/improve/source-identity.js +10 -38
- package/dist/commands/lint/base-linter.js +20 -124
- package/dist/commands/lint/env-key-rules.js +31 -47
- package/dist/commands/lint/index.js +249 -43
- package/dist/commands/{events.js → log.js} +33 -38
- package/dist/commands/migrate-cli.js +92 -12
- package/dist/commands/migration-tool.js +46 -0
- package/dist/commands/observability-cli.js +70 -209
- package/dist/commands/proposal/drain.js +101 -29
- package/dist/commands/proposal/proposal-cli.js +76 -48
- package/dist/commands/proposal/proposal.js +54 -18
- package/dist/commands/proposal/propose-cli.js +88 -0
- package/dist/commands/proposal/propose.js +23 -15
- package/dist/commands/proposal/repository.js +701 -278
- package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
- package/dist/commands/proposal/validators/proposal-validators.js +55 -7
- package/dist/commands/proposal/validators/proposals.js +4 -7
- package/dist/commands/read/curate.js +34 -53
- package/dist/commands/read/knowledge.js +150 -95
- package/dist/commands/read/registry-search.js +2 -2
- package/dist/commands/read/remember-cli.js +42 -15
- package/dist/commands/read/search-cli.js +180 -78
- package/dist/commands/read/search.js +58 -43
- package/dist/commands/read/show.js +197 -141
- package/dist/commands/registry-cli.js +12 -51
- package/dist/commands/remember.js +14 -57
- package/dist/commands/sources/add-cli.js +100 -31
- package/dist/commands/sources/bundle-cli.js +166 -0
- package/dist/commands/sources/bundle-config-ops.js +7 -2
- package/dist/commands/sources/info.js +18 -5
- package/dist/commands/sources/init.js +12 -12
- package/dist/commands/sources/installed-stashes.js +382 -98
- package/dist/commands/sources/schema-repair.js +3 -2
- package/dist/commands/sources/self-update.js +131 -38
- package/dist/commands/sources/source-add.js +72 -17
- package/dist/commands/sources/source-clone.js +129 -45
- package/dist/commands/sources/source-manage.js +43 -23
- package/dist/commands/sources/sources-cli.js +57 -208
- package/dist/commands/sources/stash-cli.js +46 -53
- package/dist/commands/tasks/tasks-cli.js +91 -97
- package/dist/commands/tasks/tasks.js +276 -421
- package/dist/commands/workflow-cli.js +175 -450
- package/dist/core/adapter/adapters/akm-adapter.js +47 -28
- package/dist/core/adapter/adapters/akm-lint.js +42 -27
- package/dist/core/adapter/adapters/akm-metadata.js +15 -44
- package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
- package/dist/core/adapter/adapters/index.js +6 -6
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
- package/dist/core/adapter/adapters/okf-adapter.js +187 -19
- package/dist/core/adapter/adapters/shared.js +3 -19
- package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
- package/dist/core/adapter/detect-adapter.js +17 -0
- package/dist/core/adapter/recognize-match.js +6 -4
- package/dist/core/adapter/validate-context.js +214 -0
- package/dist/core/asset/akm-markdown.js +63 -0
- package/dist/core/asset/asset-placement.js +20 -6
- package/dist/core/asset/asset-ref.js +11 -9
- package/dist/core/asset/frontmatter-lint.js +30 -0
- package/dist/core/asset/frontmatter.js +37 -9
- package/dist/core/asset/markdown.js +40 -51
- package/dist/core/asset/resolve-ref.js +89 -18
- package/dist/core/asset/stash-meta.js +1 -1
- package/dist/core/bundle-id.js +51 -0
- package/dist/core/common.js +152 -38
- package/dist/core/config/config-io.js +12 -1
- package/dist/core/config/config-schema.js +35 -8
- package/dist/core/config/config-sources.js +55 -11
- package/dist/core/config/config-walker.js +25 -9
- package/dist/core/config/config.js +9 -48
- package/dist/core/config/experimental.js +21 -0
- package/dist/core/config/schema/embedding.js +5 -1
- package/dist/core/config/schema/experimental.js +30 -0
- package/dist/core/config/schema/improve-processes.js +0 -6
- package/dist/core/config/schema/improve.js +21 -3
- package/dist/core/config/schema/index-config.js +8 -15
- package/dist/core/config/schema/output.js +4 -1
- package/dist/core/config/schema/setup.js +9 -18
- package/dist/core/config/schema/sources-bundles.js +49 -33
- package/dist/core/config/schema/workflow.js +3 -3
- package/dist/core/env-secret-ref.js +76 -46
- package/dist/core/errors.js +18 -12
- package/dist/core/events.js +46 -128
- package/dist/core/file-change.js +6 -5
- package/dist/core/fs-txn.js +83 -7
- package/dist/core/git-message.js +2 -2
- package/dist/core/improve-result.js +1 -100
- package/dist/core/lesson-lint.js +1 -17
- package/dist/core/logs-db.js +2 -1
- package/dist/core/migration-operation.js +16 -0
- package/dist/core/mutation-target.js +78 -0
- package/dist/core/parse.js +4 -1
- package/dist/core/paths.js +17 -20
- package/dist/core/recognition-util.js +12 -14
- package/dist/core/redaction.js +34 -0
- package/dist/core/standards/resolve-standards-context.js +2 -14
- package/dist/core/standards/resolve-stash-standards.js +2 -2
- package/dist/core/standards/resolve-type-conventions.js +2 -2
- package/dist/core/state/migrations.js +41 -18
- package/dist/core/state-db.js +5 -14
- package/dist/core/structured.js +1 -1
- package/dist/core/subprocess.js +6 -4
- package/dist/core/text-truncation.js +9 -5
- package/dist/core/type-presentation.js +3 -3
- package/dist/core/warn.js +0 -3
- package/dist/core/write-source.js +771 -95
- package/dist/indexer/bundle-identity-guard.js +3 -2
- package/dist/indexer/db/graph-db.js +0 -24
- package/dist/indexer/ensure-index.js +1 -0
- package/dist/indexer/graph/graph-boost.js +9 -34
- package/dist/indexer/graph/graph-extraction.js +8 -5
- package/dist/indexer/index-writer-lock.js +53 -17
- package/dist/indexer/index-written-assets.js +16 -22
- package/dist/indexer/indexer.js +497 -239
- package/dist/indexer/installations.js +14 -96
- package/dist/indexer/passes/dir-staleness.js +16 -9
- package/dist/indexer/passes/memory-inference.js +11 -9
- package/dist/indexer/passes/metadata.js +113 -47
- package/dist/indexer/scan/doc-to-entry.js +38 -1
- package/dist/indexer/scan/drain-dir.js +13 -23
- package/dist/indexer/search/db-search.js +99 -54
- package/dist/indexer/search/fts-query.js +47 -24
- package/dist/indexer/search/ranking-contributors.js +42 -20
- package/dist/indexer/search/ranking.js +18 -99
- package/dist/indexer/search/search-fields.js +7 -2
- package/dist/indexer/search/search-source.js +82 -93
- package/dist/indexer/usage/usage-events.js +0 -89
- package/dist/indexer/walk/file-context.js +2 -1
- package/dist/indexer/walk/matchers.js +30 -43
- package/dist/indexer/walk/path-resolver.js +7 -2
- package/dist/indexer/walk/walker.js +38 -12
- package/dist/integrations/agent/builders.js +0 -6
- package/dist/integrations/agent/config.js +2 -2
- package/dist/integrations/agent/detect.js +49 -19
- package/dist/integrations/agent/engine-fallback.js +76 -0
- package/dist/integrations/agent/profiles.js +14 -0
- package/dist/integrations/agent/prompts.js +12 -8
- package/dist/integrations/agent/runner-dispatch.js +4 -2
- package/dist/integrations/agent/runner.js +0 -1
- package/dist/integrations/agent/spawn.js +5 -6
- package/dist/integrations/github.js +1 -1
- package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
- package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
- package/dist/integrations/harnesses/claude/session-log.js +0 -10
- package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
- package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
- package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
- package/dist/integrations/harnesses/index.js +3 -7
- package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
- package/dist/integrations/harnesses/opencode/session-log.js +0 -15
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
- package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
- package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
- package/dist/integrations/lockfile.js +101 -6
- package/dist/integrations/session-logs/index.js +3 -28
- package/dist/llm/client.js +136 -100
- package/dist/llm/embedders/remote.js +13 -5
- package/dist/llm/feature-gate.js +4 -12
- package/dist/llm/graph-extract.js +5 -11
- package/dist/llm/memory-infer.js +144 -1
- package/dist/llm/metadata-enhance.js +5 -7
- package/dist/llm/structured-call.js +1 -1
- package/dist/llm/usage-persist.js +26 -5
- package/dist/llm/usage-telemetry.js +25 -2
- package/dist/output/cli-hints.js +1 -2
- package/dist/output/context.js +22 -7
- package/dist/output/format-exempt.js +80 -0
- package/dist/output/generic-render.js +259 -0
- package/dist/output/render-registry.js +57 -0
- package/dist/output/renderers.js +14 -36
- package/dist/output/shapes/curate.js +10 -1
- package/dist/output/shapes/events.js +12 -7
- package/dist/output/shapes/helpers.js +56 -83
- package/dist/output/shapes/migrate.js +8 -0
- package/dist/output/shapes/passthrough.js +7 -41
- package/dist/output/shapes/proposal/producer.js +15 -7
- package/dist/output/shapes.js +2 -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 +164 -96
- package/dist/output/text/env.js +1 -3
- package/dist/output/text/events.js +8 -7
- package/dist/output/text/health-format.js +103 -0
- package/dist/output/text/health.js +7 -0
- package/dist/output/text/helpers.js +10 -8
- package/dist/output/text/lint-format.js +43 -0
- package/dist/output/text/{save.js → lint.js} +2 -2
- package/dist/output/text/migrate.js +88 -0
- package/dist/output/text/proposal/producer.js +4 -2
- package/dist/output/text/proposal-format.js +44 -72
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/show-directives.js +15 -7
- package/dist/output/text/status-list.js +32 -0
- package/dist/output/text/sync.js +5 -0
- package/dist/output/text/workflow-format.js +24 -203
- package/dist/output/text/workflow.js +1 -7
- package/dist/output/text.js +16 -17
- 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 +13 -23
- package/dist/registry/resolve.js +42 -7
- package/dist/registry/semver.js +34 -84
- package/dist/runtime.js +2 -23
- package/dist/scripts/akm-migrate-node.js +60290 -0
- package/dist/scripts/akm-migrate.js +59628 -0
- package/dist/setup/detect.js +42 -15
- package/dist/setup/registry-stash-loader.js +2 -2
- package/dist/setup/setup.js +236 -136
- package/dist/setup/steps/connection.js +7 -9
- package/dist/setup/steps/platforms.js +9 -9
- package/dist/setup/steps/semantic.js +15 -3
- package/dist/setup/steps/sources.js +12 -13
- package/dist/setup/steps/stashdir.js +2 -3
- package/dist/setup/steps/tasks.js +237 -120
- package/dist/sources/freshness.js +1 -1
- 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 +25 -23
- package/dist/sources/providers/git-stash.js +395 -106
- package/dist/sources/providers/git.js +2 -2
- package/dist/sources/providers/npm.js +16 -19
- package/dist/sources/providers/provider-utils.js +7 -4
- package/dist/sources/providers/sync-from-ref.js +3 -9
- package/dist/sources/providers/website.js +6 -1
- package/dist/sources/resolve.js +6 -5
- package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
- package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
- package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
- package/dist/sources/snapshot-fetchers/github.js +100 -0
- package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
- package/dist/sources/snapshot-fetchers/registry.js +17 -1
- package/dist/sources/snapshot-fetchers/robots.js +348 -0
- package/dist/sources/snapshot-fetchers/rss.js +282 -0
- package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
- package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
- package/dist/sources/snapshot-fetchers/x.js +910 -0
- package/dist/storage/database.js +7 -0
- package/dist/storage/engines/sqlite-migrations.js +23 -111
- package/dist/storage/managed-db.js +2 -2
- package/dist/storage/repositories/canaries-repository.js +1 -1
- package/dist/storage/repositories/events-repository.js +27 -11
- package/dist/storage/repositories/improve-runs-repository.js +6 -12
- package/dist/storage/repositories/index-connection.js +17 -6
- package/dist/storage/repositories/index-entries-repository.js +151 -240
- package/dist/storage/repositories/index-entry-mapper.js +15 -11
- package/dist/storage/repositories/index-fts-repository.js +5 -2
- package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
- package/dist/storage/repositories/index-meta-repository.js +2 -3
- package/dist/storage/repositories/index-schema.js +10 -25
- package/dist/storage/repositories/index-utility-repository.js +15 -28
- package/dist/storage/repositories/index-vec-repository.js +6 -1
- package/dist/storage/repositories/outcome-repository.js +119 -0
- package/dist/storage/repositories/proposals-repository.js +296 -59
- package/dist/storage/repositories/registry-cache.js +19 -0
- package/dist/storage/repositories/salience-repository.js +172 -0
- package/dist/storage/repositories/task-history-repository.js +15 -13
- package/dist/storage/repositories/workflow-runs-repository.js +52 -40
- package/dist/tasks/backends/cron.js +105 -15
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +85 -38
- package/dist/tasks/backends/schtasks.js +135 -15
- package/dist/tasks/embedded.js +56 -40
- package/dist/tasks/parser.js +7 -157
- package/dist/tasks/resolve-akm-bin.js +137 -59
- package/dist/tasks/runner.js +79 -42
- package/dist/tasks/scheduler-invocation.js +220 -10
- package/dist/tasks/schema.js +24 -1
- package/dist/tasks/task-id.js +1 -3
- package/dist/tasks/validator.js +20 -6
- package/dist/workflows/authoring/authoring.js +94 -143
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/exec/frozen-judge.js +28 -2
- package/dist/workflows/exec/native-executor.js +77 -57
- package/dist/workflows/exec/param-secrets.js +9 -9
- package/dist/workflows/exec/run-workflow.js +133 -79
- package/dist/workflows/exec/step-work.js +219 -346
- package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
- package/dist/workflows/ir/compile.js +141 -270
- package/dist/workflows/ir/freeze.js +40 -30
- package/dist/workflows/ir/params.js +135 -11
- package/dist/workflows/ir/plan-hash.js +1 -1
- package/dist/workflows/ir/schema.js +25 -26
- package/dist/workflows/parser.js +872 -307
- package/dist/workflows/program/expressions.js +20 -208
- package/dist/workflows/program/schema.js +7 -10
- package/dist/workflows/renderer.js +95 -68
- package/dist/workflows/resource-limits.js +2 -0
- package/dist/workflows/runtime/checkin.js +3 -3
- package/dist/workflows/runtime/plan-classifier.js +16 -75
- package/dist/workflows/runtime/runs.js +186 -127
- package/dist/workflows/runtime/unit-checkin.js +1 -1
- package/dist/workflows/runtime/unit-phases.js +2 -2
- package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +30 -36
- package/dist/workflows/validator.js +21 -62
- package/docs/README.md +68 -0
- package/docs/migration/README.md +8 -0
- package/docs/migration/release-notes/0.7.0.md +11 -11
- package/docs/migration/release-notes/0.9.0.md +208 -27
- package/docs/migration/v0.7-to-v0.8.md +46 -47
- package/docs/migration/v0.8-to-v0.9.md +564 -208
- package/docs/migration/v0.9.0-troubleshooting.md +561 -0
- package/docs/reference/README.md +12 -0
- package/docs/reference/cli.md +2253 -0
- package/docs/reference/configuration.md +358 -0
- package/docs/reference/data-and-telemetry.md +105 -42
- package/docs/reference/workflows.md +647 -0
- package/package.json +22 -11
- package/schemas/akm-asset-envelope.json +93 -0
- package/schemas/akm-config.json +81 -128
- package/schemas/akm-workflow.json +74 -73
- package/dist/assets/tasks/core/backup.yml +0 -5
- package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
- package/dist/cli/config-migrate.js +0 -1806
- package/dist/cli/config-validate.js +0 -41
- package/dist/commands/backup-cli.js +0 -56
- package/dist/commands/bundle/bundle-cli.js +0 -68
- package/dist/commands/bundle/bundle.js +0 -219
- package/dist/commands/graph/graph-cli.js +0 -124
- package/dist/commands/graph/graph.js +0 -489
- package/dist/commands/improve/extract-watch.js +0 -140
- package/dist/commands/mv-cli.js +0 -1221
- package/dist/commands/sources/history.js +0 -201
- package/dist/commands/tasks/default-tasks.js +0 -186
- package/dist/core/migration-backup.js +0 -1234
- package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
- package/dist/llm/memory-infer-impl.js +0 -138
- package/dist/migrate/legacy/config-source-migration.js +0 -223
- package/dist/migrate/legacy/content-migration.js +0 -305
- package/dist/migrate/legacy/legacy-layout.js +0 -779
- package/dist/migrate/legacy/legacy-paths.js +0 -25
- package/dist/migrate/legacy/legacy-stash-json.js +0 -72
- package/dist/migrate/legacy/proposal-fs-import.js +0 -168
- package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
- package/dist/migrate/legacy/three-db-cutover.js +0 -841
- package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
- package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
- package/dist/migrate/legacy-ref-grammar.js +0 -214
- 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/registry/build-index.js +0 -382
- package/dist/schemas/akm-config.json +0 -4704
- package/dist/schemas/akm-task.json +0 -87
- package/dist/schemas/akm-workflow.json +0 -372
- package/dist/scripts/migrate-storage.js +0 -3816
- package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
- package/dist/workflows/cli.js +0 -53
- package/dist/workflows/exec/brief.js +0 -481
- package/dist/workflows/exec/report.js +0 -1460
- package/dist/workflows/exec/watch.js +0 -116
- package/dist/workflows/program/parser.js +0 -813
- package/dist/workflows/program/project.js +0 -104
|
@@ -1,56 +1,28 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
|
|
5
|
-
import { primaryBundlePath } from "../../core/config/config.js";
|
|
6
|
-
// ── Durable improve-state keys (Chunk-8 WI-8.5c — collapsed to the item_ref) ──
|
|
4
|
+
// ── Durable improve-state keys ───────────────────────────────────────────────
|
|
7
5
|
//
|
|
8
|
-
// Every improve ref
|
|
6
|
+
// Every improve ref uses the current grammar (a short conceptId), and the durable
|
|
9
7
|
// state key is the resolved index entry's `item_ref` when the planner supplied
|
|
10
8
|
// one, else the conceptId `ref` itself (`preparation.ts`
|
|
11
|
-
// `salienceWriteKey`/`outcomeWriteKey` = `itemRef ?? ref`).
|
|
12
|
-
// source-qualified / legacy-bare dual-key machinery (and its dependency on the
|
|
13
|
-
// retired dual-grammar stored-ref parser) is gone.
|
|
9
|
+
// `salienceWriteKey`/`outcomeWriteKey` = `itemRef ?? ref`).
|
|
14
10
|
/**
|
|
15
11
|
* The durable improve-state key for a ref with no resolved `item_ref` — the
|
|
16
|
-
* conceptId `ref` itself.
|
|
17
|
-
* the pre-flip source-qualification it drove is gone.)
|
|
12
|
+
* conceptId `ref` itself.
|
|
18
13
|
*/
|
|
19
|
-
export function durableImproveRef(ref
|
|
14
|
+
export function durableImproveRef(ref) {
|
|
20
15
|
return ref;
|
|
21
16
|
}
|
|
22
|
-
/**
|
|
17
|
+
/** Return the conceptId portion of a durable improve-state key. */
|
|
23
18
|
export function bareImproveRef(ref) {
|
|
24
19
|
const boundary = ref.indexOf("//");
|
|
25
20
|
return boundary >= 0 ? ref.slice(boundary + 2) : ref;
|
|
26
21
|
}
|
|
27
22
|
/**
|
|
28
|
-
* The durable
|
|
29
|
-
*
|
|
30
|
-
* Because that write key is the `item_ref` for a provenance-bearing entry but
|
|
31
|
-
* the bare conceptId `ref` for a provenance-absent one, an asset's durable rows
|
|
32
|
-
* can carry EITHER spelling across runs — so the reader probes both, item_ref
|
|
33
|
-
* first, deduped. The `sourceName`/`includeLegacyBare` parameters are retained
|
|
34
|
-
* for call-site compatibility but no longer widen the set (the retired
|
|
35
|
-
* source-qualified / legacy-bare arms).
|
|
23
|
+
* The single durable improve-state key used by both readers and writers.
|
|
24
|
+
* Indexed entries use item_ref; direct or provenance-free refs use conceptId.
|
|
36
25
|
*/
|
|
37
|
-
export function improveStateReadRefs(ref,
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Bare improve state predates source-qualified refs and belongs only to the
|
|
42
|
-
* historical local stash. Named sources at any other root must never inherit it.
|
|
43
|
-
*/
|
|
44
|
-
export function shouldReadLegacyBareImproveState(sourceName, sourcePath, config) {
|
|
45
|
-
if (!sourceName || !sourcePath)
|
|
46
|
-
return false;
|
|
47
|
-
// 0.9.0 (spec §10.1 / Decision C): the historical local stash is the primary
|
|
48
|
-
// bundle (`defaultBundle`). A named source at any other root must never
|
|
49
|
-
// inherit the pre-source-qualified bare improve state. This defaultBundle-path
|
|
50
|
-
// equivalence preserves the pre-cutover behavior for a migrated workspace,
|
|
51
|
-
// whose `stashDir` became the defaultBundle's filesystem `path`.
|
|
52
|
-
const primaryPath = primaryBundlePath(config);
|
|
53
|
-
if (!primaryPath)
|
|
54
|
-
return false;
|
|
55
|
-
return path.resolve(sourcePath) === path.resolve(primaryPath);
|
|
26
|
+
export function improveStateReadRefs(ref, itemRef) {
|
|
27
|
+
return [itemRef ?? ref];
|
|
56
28
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// `<type>:<slug>` -> on-disk-asset question and MUST agree on the set of
|
|
11
11
|
// reachable refs for any given stash layout.
|
|
12
12
|
//
|
|
13
|
-
// The lock is enforced by `tests/contracts/ref-resolver-contract.test.ts`,
|
|
13
|
+
// The lock is enforced by `tests/integration/contracts/ref-resolver-contract.test.ts`,
|
|
14
14
|
// which drives this implementation through a canonical fixture set. The
|
|
15
15
|
// akm-plugins repo ships an equivalent test that drives its copy through the
|
|
16
16
|
// SAME inputs and asserts identical outcomes. Any change to the resolver
|
|
@@ -19,50 +19,28 @@
|
|
|
19
19
|
//
|
|
20
20
|
// Cases the contract covers (see fixture in the contract test):
|
|
21
21
|
// - existing memory / knowledge / agent / workflow / skill refs
|
|
22
|
-
// - knowledge
|
|
22
|
+
// - namespaced knowledge paths (knowledge/<category>/<slug>.md)
|
|
23
23
|
// - skill multi-file layout (skills/<slug>/SKILL.md)
|
|
24
|
-
// - memory `.derived.md` sibling
|
|
25
24
|
// - namespaced slugs containing `/`
|
|
26
25
|
// - env (`env/.env`, `env/<name>.env`) and secret (`secrets/<name>`) refs
|
|
27
26
|
// - non-existent refs
|
|
28
|
-
// - script
|
|
27
|
+
// - script paths with explicit extensions
|
|
29
28
|
//
|
|
30
29
|
// As of 0.9 the path mapping in `refToRelPath` is DERIVED FROM THE PLACEMENT
|
|
31
30
|
// SPECS (`assetPathForName` in `src/core/asset/asset-placement.ts`) rather than
|
|
32
31
|
// hand-encoded, so it can no longer drift from the placement layer. `env`/
|
|
33
|
-
// `secret` refs are path-resolved.
|
|
34
|
-
// keeps its legacy `.md` resolution (see refToRelPath for both).
|
|
32
|
+
// `secret`, `script`, and `task` refs are path-resolved.
|
|
35
33
|
// ----------------------------------------------------------------------------
|
|
36
34
|
import fs from "node:fs";
|
|
37
35
|
import path from "node:path";
|
|
38
36
|
import { assetPathForName, stashDirFor } from "../../core/asset/asset-placement.js";
|
|
39
37
|
import { BUNDLE_REF_RE } from "../../core/asset/asset-ref.js";
|
|
38
|
+
import { spliceFrontmatterLine } from "../../core/asset/frontmatter.js";
|
|
39
|
+
import { checkUnquotedDescriptionColon } from "../../core/asset/frontmatter-lint.js";
|
|
40
40
|
import { typeNameFromConceptId } from "../../core/asset/resolve-ref.js";
|
|
41
|
+
import { localDateStamp } from "../../core/common.js";
|
|
41
42
|
import { findFenceRegions } from "./markdown-insertion.js";
|
|
42
43
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
43
|
-
function formatDate(d) {
|
|
44
|
-
const y = d.getFullYear();
|
|
45
|
-
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
46
|
-
const day = String(d.getDate()).padStart(2, "0");
|
|
47
|
-
return `${y}-${m}-${day}`;
|
|
48
|
-
}
|
|
49
|
-
function checkUnquotedColon(frontmatterText) {
|
|
50
|
-
if (!frontmatterText)
|
|
51
|
-
return null;
|
|
52
|
-
for (const line of frontmatterText.split(/\r?\n/)) {
|
|
53
|
-
const match = line.match(/^description:\s*(.*)/);
|
|
54
|
-
if (!match)
|
|
55
|
-
continue;
|
|
56
|
-
const value = match[1].trim();
|
|
57
|
-
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
if (value.includes(":")) {
|
|
61
|
-
return `description value contains unquoted colon: ${value}`;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
44
|
function fixUnquotedColon(raw) {
|
|
67
45
|
const lines = raw.split(/\r?\n/);
|
|
68
46
|
if (lines[0]?.trim() !== "---")
|
|
@@ -88,15 +66,7 @@ function checkMissingUpdated(data, frontmatterText) {
|
|
|
88
66
|
return frontmatterText !== null && !("updated" in data);
|
|
89
67
|
}
|
|
90
68
|
function fixMissingUpdated(raw, mtime) {
|
|
91
|
-
|
|
92
|
-
const lines = raw.split(/\r?\n/);
|
|
93
|
-
if (lines[0]?.trim() !== "---")
|
|
94
|
-
return raw;
|
|
95
|
-
const closeIdx = lines.findIndex((l, i) => i > 0 && l.trim() === "---");
|
|
96
|
-
if (closeIdx === -1)
|
|
97
|
-
return raw;
|
|
98
|
-
lines.splice(closeIdx, 0, `updated: ${dateStr}`);
|
|
99
|
-
return lines.join("\n");
|
|
69
|
+
return spliceFrontmatterLine(raw, `updated: ${localDateStamp(mtime)}`) ?? raw;
|
|
100
70
|
}
|
|
101
71
|
// ── stale-path helpers ────────────────────────────────────────────────────────
|
|
102
72
|
function checkStalePath(body) {
|
|
@@ -129,50 +99,17 @@ function stripFencedBlocks(body) {
|
|
|
129
99
|
return lines.join("\n");
|
|
130
100
|
}
|
|
131
101
|
// ── missing-ref helpers ───────────────────────────────────────────────────────
|
|
132
|
-
/**
|
|
133
|
-
* Body-ref boundary grammar, shared with `akm mv`'s ref-rewrite pattern —
|
|
134
|
-
* `src/commands/mv-cli.ts` imports these constants so the two grammars cannot
|
|
135
|
-
* drift. Any character-class change here retargets both the lint missing-ref
|
|
136
|
-
* scan and mv's inbound-xref rewriting.
|
|
137
|
-
*
|
|
138
|
-
* `REF_BOUNDARY_PREFIX_CLASS_SRC` is the character class a ref may start
|
|
139
|
-
* after (a ref also matches at line start): whitespace, backtick, quote,
|
|
140
|
-
* `(`, `[`, or `,` — the `[` admits markdown-link-style refs like
|
|
141
|
-
* `see [memory:foo]`, which the legacy class silently skipped, and the `,`
|
|
142
|
-
* admits the ref AFTER a bare comma in a no-space flow list like
|
|
143
|
-
* `xrefs: [memory:a,memory:b]` (valid YAML). `,` is already a slug
|
|
144
|
-
* TERMINATOR (excluded from `REF_SLUG_CHAR_CLASS_SRC`), so `a,b` splits
|
|
145
|
-
* cleanly and adding it here cannot extend any existing match; false
|
|
146
|
-
* positives are fenced by the type alternation — a comma only starts a match
|
|
147
|
-
* when a literal `<type>:` follows it.
|
|
148
|
-
*
|
|
149
|
-
* `REF_SLUG_CHAR_CLASS_SRC` is the character class a ref's `<type>:<slug>`
|
|
150
|
-
* token is made of; the first excluded character ends the ref.
|
|
151
|
-
*/
|
|
152
|
-
export const REF_BOUNDARY_PREFIX_CLASS_SRC = "[\\s`\"'(,\\[]";
|
|
153
|
-
export const REF_SLUG_CHAR_CLASS_SRC = "[^\\s\"'`)\\]>,\\n]";
|
|
154
102
|
/**
|
|
155
103
|
* Map from ref type to relative path pattern within stashRoot. Returns null to
|
|
156
104
|
* skip (type is unresolvable by the slug walker).
|
|
157
105
|
*
|
|
158
106
|
* Path layout is owned by the placement layer: we resolve through
|
|
159
107
|
* `assetPathForName(type, stashDirFor(type), name)` so the linter and the
|
|
160
|
-
* rest of the CLI agree on where an asset lives.
|
|
161
|
-
* preserved to keep pre-0.9 behaviour byte-identical:
|
|
162
|
-
* - `script`: returns null (scripts live in nested dirs with arbitrary
|
|
163
|
-
* extensions — unresolvable by the slug-based walker, as the contract pins).
|
|
164
|
-
* - `task`: M1 fix — tasks are stored as `<id>.yml` on disk, so resolve
|
|
165
|
-
* `task:` refs against `tasks/<id>.yml` to match actual on-disk layout.
|
|
108
|
+
* rest of the CLI agree on where an asset lives.
|
|
166
109
|
*
|
|
167
110
|
* Exported for contract testing — see header CONTRACT block.
|
|
168
111
|
*/
|
|
169
112
|
export function refToRelPath(refType, refName) {
|
|
170
|
-
// script is intentionally unresolvable (contract-pinned).
|
|
171
|
-
if (refType === "script")
|
|
172
|
-
return null;
|
|
173
|
-
// M1: tasks are stored as .yml on disk; resolve task: refs against tasks/<id>.yml.
|
|
174
|
-
if (refType === "task")
|
|
175
|
-
return path.join(stashDirFor("task") ?? "tasks", `${refName}.yml`);
|
|
176
113
|
const typeDir = stashDirFor(refType);
|
|
177
114
|
if (!typeDir)
|
|
178
115
|
return null; // unknown type — skip
|
|
@@ -208,56 +145,16 @@ export function refExistsInAnyStash(relPath, refType, refName, stashRoots) {
|
|
|
208
145
|
* (the contract pins `refToRelPath` + `refExistsInAnyStash`; this is the
|
|
209
146
|
* shared internal both build on).
|
|
210
147
|
*/
|
|
211
|
-
export function resolveRefPathInStash(relPath,
|
|
148
|
+
export function resolveRefPathInStash(relPath, _refType, _refName, root) {
|
|
212
149
|
const absPath = path.join(root, relPath);
|
|
213
150
|
if (fs.existsSync(absPath))
|
|
214
151
|
return absPath;
|
|
215
|
-
// Multi-file skill layout: directory containing SKILL.md
|
|
216
|
-
const bareDir = absPath.replace(/\.md$/, "");
|
|
217
|
-
if (fs.existsSync(bareDir) && fs.existsSync(path.join(bareDir, "SKILL.md"))) {
|
|
218
|
-
return path.join(bareDir, "SKILL.md");
|
|
219
|
-
}
|
|
220
|
-
// .derived.md variant for memory refs
|
|
221
|
-
if (refType === "memory") {
|
|
222
|
-
const derivedPath = path.join(root, "memories", `${refName}.derived.md`);
|
|
223
|
-
if (fs.existsSync(derivedPath))
|
|
224
|
-
return derivedPath;
|
|
225
|
-
}
|
|
226
|
-
// Knowledge-specific: search subdirectories like knowledge/projects/, knowledge/tools/, etc.
|
|
227
|
-
if (refType === "knowledge") {
|
|
228
|
-
try {
|
|
229
|
-
const knowledgeDir = path.join(root, "knowledge");
|
|
230
|
-
if (fs.existsSync(knowledgeDir) && fs.statSync(knowledgeDir).isDirectory()) {
|
|
231
|
-
const entries = fs.readdirSync(knowledgeDir, { withFileTypes: true });
|
|
232
|
-
for (const entry of entries) {
|
|
233
|
-
if (!entry.isDirectory())
|
|
234
|
-
continue;
|
|
235
|
-
const subPath = path.join(knowledgeDir, entry.name, `${refName}.md`);
|
|
236
|
-
if (fs.existsSync(subPath))
|
|
237
|
-
return subPath;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
catch {
|
|
242
|
-
// Ignore errors reading directory
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
// Fallback: the refName may already encode the full stash-relative path
|
|
246
|
-
// (e.g. knowledge:skills/foo/references/bar where the file lives at
|
|
247
|
-
// <stash>/skills/foo/references/bar.md, not <stash>/knowledge/skills/...).
|
|
248
|
-
const directPath = path.join(root, `${refName}.md`);
|
|
249
|
-
if (fs.existsSync(directPath))
|
|
250
|
-
return directPath;
|
|
251
|
-
const directDir = path.join(root, refName);
|
|
252
|
-
if (fs.existsSync(directDir) && fs.existsSync(path.join(directDir, "SKILL.md"))) {
|
|
253
|
-
return path.join(directDir, "SKILL.md");
|
|
254
|
-
}
|
|
255
152
|
return null;
|
|
256
153
|
}
|
|
257
154
|
/**
|
|
258
155
|
* A `(refType, refName)` pair that is not a lint-checkable local asset ref —
|
|
259
|
-
* shared skip-guard for
|
|
260
|
-
*
|
|
156
|
+
* shared skip-guard for recognized `bundle//conceptId` refs. Filters the
|
|
157
|
+
* false-positive patterns:
|
|
261
158
|
* - Shell variables: memory:$(cmd) or knowledge:${VAR} (guarded by callers on
|
|
262
159
|
* the raw token, before it is split).
|
|
263
160
|
* - Empty names or names that look like absolute paths / home dirs / URLs.
|
|
@@ -322,10 +219,10 @@ function scanBundleRefs(scanBody, allRoots) {
|
|
|
322
219
|
*/
|
|
323
220
|
function classifyConceptRef(rawConceptId, allRoots) {
|
|
324
221
|
const conceptId = rawConceptId.split("#", 1)[0];
|
|
325
|
-
const
|
|
326
|
-
if (
|
|
222
|
+
const parts = typeNameFromConceptId(conceptId);
|
|
223
|
+
if (parts === undefined)
|
|
327
224
|
return null; // foreign type / not a local asset ref
|
|
328
|
-
return localRefMissingRelPath(
|
|
225
|
+
return localRefMissingRelPath(parts.type, parts.name, allRoots);
|
|
329
226
|
}
|
|
330
227
|
/**
|
|
331
228
|
* Returns an array of {ref, resolvedRelPath} for every local AKM ref in the
|
|
@@ -401,9 +298,8 @@ function dedupeMissing(rows) {
|
|
|
401
298
|
* would otherwise dangle them silently.
|
|
402
299
|
*
|
|
403
300
|
* `sources:` is deliberately excluded (non-wiki `sources:` was rejected as a
|
|
404
|
-
* typed channel; wiki `sources:` is checked by lintWiki). `
|
|
405
|
-
*
|
|
406
|
-
* merged-away or pruned assets (historical provenance).
|
|
301
|
+
* typed channel; wiki `sources:` is checked by lintWiki). `evidenceSources:` is
|
|
302
|
+
* excluded because it can point at merged-away or pruned assets.
|
|
407
303
|
*/
|
|
408
304
|
const XREF_FRONTMATTER_KEYS = ["xrefs", "supersededBy", "contradictedBy"];
|
|
409
305
|
/**
|
|
@@ -568,7 +464,7 @@ export function runBaseChecks(ctx) {
|
|
|
568
464
|
const shouldRun = (issueType) => !lintSkip.includes(issueType);
|
|
569
465
|
// ── 1. unquoted-colon ──────────────────────────────────────────────────
|
|
570
466
|
if (shouldRun("unquoted-colon")) {
|
|
571
|
-
const unquotedColonDetail =
|
|
467
|
+
const unquotedColonDetail = checkUnquotedDescriptionColon(ctx.frontmatter);
|
|
572
468
|
if (unquotedColonDetail) {
|
|
573
469
|
if (ctx.fix) {
|
|
574
470
|
currentRaw = fixUnquotedColon(currentRaw);
|
|
@@ -605,7 +501,7 @@ export function runBaseChecks(ctx) {
|
|
|
605
501
|
issues.push({
|
|
606
502
|
file: ctx.relPath,
|
|
607
503
|
issue: "missing-updated",
|
|
608
|
-
detail: `stamped updated: ${
|
|
504
|
+
detail: `stamped updated: ${localDateStamp(mtime)}`,
|
|
609
505
|
fixed: true,
|
|
610
506
|
});
|
|
611
507
|
}
|
|
@@ -632,7 +528,7 @@ export function runBaseChecks(ctx) {
|
|
|
632
528
|
for (const candidate of [...staleInBody, ...staleInFrontmatter]) {
|
|
633
529
|
// M4: Suggest portable replacement when path is under stashRoot.
|
|
634
530
|
const portableHint = candidate.startsWith(ctx.stashRoot)
|
|
635
|
-
? ` (portable form: $
|
|
531
|
+
? ` (portable form: $AKM_BUNDLE_DIR${candidate.slice(ctx.stashRoot.length)})`
|
|
636
532
|
: "";
|
|
637
533
|
issues.push({
|
|
638
534
|
file: ctx.relPath,
|
|
@@ -2,32 +2,32 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Environment security lint rules — flags known-dangerous variable names.
|
|
6
6
|
*
|
|
7
|
-
* These env var names, when present
|
|
7
|
+
* These env var names, when present in an environment file, indicate the file can be
|
|
8
8
|
* used to hijack process execution via loader injection, path override, or
|
|
9
9
|
* shell/runtime startup hooks. The lint pass emits a warning-level finding;
|
|
10
|
-
* it does NOT block
|
|
10
|
+
* it does NOT block local environment edits.
|
|
11
11
|
*
|
|
12
12
|
* Enforcement scope:
|
|
13
|
-
* - `akm lint` reports findings as `dangerous-
|
|
14
|
-
* - `akm add` BLOCKS install unless `--allow-insecure` is set (or, on TTY,
|
|
13
|
+
* - `akm lint` reports findings as `dangerous-env-key` (non-blocking warn).
|
|
14
|
+
* - `akm bundle add` BLOCKS install unless `--allow-insecure` is set (or, on TTY,
|
|
15
15
|
* the user explicitly confirms at the prompt).
|
|
16
|
-
* -
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* - Local env writes do NOT consult this list — by design, the operator may
|
|
17
|
+
* legitimately store any key locally. The gate exists only for third-party
|
|
18
|
+
* stash installation.
|
|
19
19
|
*
|
|
20
20
|
* False-positive tradeoff:
|
|
21
21
|
* A handful of keys (EDITOR, VISUAL, PAGER) are included because they are
|
|
22
22
|
* invoked by many interactive tools and are a documented RCE vector when
|
|
23
|
-
* sourced from untrusted
|
|
23
|
+
* sourced from untrusted environments. They will also flag on benign files
|
|
24
24
|
* where the operator legitimately wants to set their editor — accept the
|
|
25
25
|
* FP and bypass with `--allow-insecure` after review.
|
|
26
26
|
*/
|
|
27
27
|
import fs from "node:fs";
|
|
28
28
|
import { listKeys } from "../env/env.js";
|
|
29
29
|
// ── Dangerous key set ─────────────────────────────────────────────────────────
|
|
30
|
-
export const
|
|
30
|
+
export const DANGEROUS_ENV_KEYS = new Set([
|
|
31
31
|
// Dynamic linker hijacking (Linux glibc ld.so)
|
|
32
32
|
"LD_PRELOAD", // forces shared library injection
|
|
33
33
|
"LD_LIBRARY_PATH", // overrides library search path
|
|
@@ -89,7 +89,7 @@ export const DANGEROUS_VAULT_KEYS = new Set([
|
|
|
89
89
|
* prefixed with `BASH_FUNC_`. Listing every concrete name is impossible; we
|
|
90
90
|
* test against this pattern set in addition to the literal `Set`.
|
|
91
91
|
*/
|
|
92
|
-
export const
|
|
92
|
+
export const DANGEROUS_ENV_KEY_PATTERNS = [
|
|
93
93
|
{
|
|
94
94
|
// CVE-2014-6271 (Shellshock) — bash imports exported functions named
|
|
95
95
|
// `BASH_FUNC_<name>%%` and parses their bodies, enabling RCE.
|
|
@@ -103,13 +103,13 @@ export const DANGEROUS_VAULT_KEY_PATTERNS = [
|
|
|
103
103
|
];
|
|
104
104
|
/**
|
|
105
105
|
* Returns `true` if the given key name is dangerous — either by literal match
|
|
106
|
-
* against `
|
|
107
|
-
* `
|
|
106
|
+
* against `DANGEROUS_ENV_KEYS` or by matching any entry in
|
|
107
|
+
* `DANGEROUS_ENV_KEY_PATTERNS`.
|
|
108
108
|
*/
|
|
109
|
-
export function
|
|
110
|
-
if (
|
|
109
|
+
export function isDangerousEnvKey(key) {
|
|
110
|
+
if (DANGEROUS_ENV_KEYS.has(key))
|
|
111
111
|
return true;
|
|
112
|
-
for (const { pattern } of
|
|
112
|
+
for (const { pattern } of DANGEROUS_ENV_KEY_PATTERNS) {
|
|
113
113
|
if (pattern.test(key))
|
|
114
114
|
return true;
|
|
115
115
|
}
|
|
@@ -117,27 +117,26 @@ export function isDangerousVaultKey(key) {
|
|
|
117
117
|
}
|
|
118
118
|
// ── Checker ───────────────────────────────────────────────────────────────────
|
|
119
119
|
/**
|
|
120
|
-
* Inspect
|
|
121
|
-
*
|
|
122
|
-
* `DANGEROUS_VAULT_KEY_PATTERNS`.
|
|
120
|
+
* Inspect an `.env` file and return a lint finding for every key whose name
|
|
121
|
+
* appears in `DANGEROUS_ENV_KEYS` or matches `DANGEROUS_ENV_KEY_PATTERNS`.
|
|
123
122
|
*
|
|
124
|
-
* @param
|
|
123
|
+
* @param envPath Absolute path to the `.env` file.
|
|
125
124
|
* @param relPath Stash-relative path used as the `file` field in findings
|
|
126
|
-
* (e.g. `"
|
|
127
|
-
* @param
|
|
125
|
+
* (e.g. `"env/prod.env"`).
|
|
126
|
+
* @param envRef Human-readable env ref (e.g. `"env/prod"`) shown in
|
|
128
127
|
* the finding message.
|
|
129
128
|
*/
|
|
130
129
|
/** Suppression comment token checked case-insensitively on the preceding non-empty line. */
|
|
131
|
-
const SUPPRESSION_COMMENT = "# akm-lint-ok: dangerous-
|
|
130
|
+
const SUPPRESSION_COMMENT = "# akm-lint-ok: dangerous-env-key";
|
|
132
131
|
/**
|
|
133
|
-
* Returns the set of keys suppressed by an inline `# akm-lint-ok: dangerous-
|
|
132
|
+
* Returns the set of keys suppressed by an inline `# akm-lint-ok: dangerous-env-key`
|
|
134
133
|
* comment on the line immediately preceding the key assignment in the `.env` file.
|
|
135
134
|
*/
|
|
136
|
-
function collectSuppressedKeys(
|
|
135
|
+
function collectSuppressedKeys(envPath) {
|
|
137
136
|
const suppressed = new Set();
|
|
138
137
|
let raw;
|
|
139
138
|
try {
|
|
140
|
-
raw = fs.readFileSync(
|
|
139
|
+
raw = fs.readFileSync(envPath, "utf8");
|
|
141
140
|
}
|
|
142
141
|
catch {
|
|
143
142
|
return suppressed;
|
|
@@ -156,36 +155,21 @@ function collectSuppressedKeys(vaultPath) {
|
|
|
156
155
|
}
|
|
157
156
|
return suppressed;
|
|
158
157
|
}
|
|
159
|
-
export function
|
|
160
|
-
const { keys } = listKeys(
|
|
161
|
-
const suppressed = collectSuppressedKeys(
|
|
158
|
+
export function checkEnvForDangerousKeys(envPath, relPath, envRef) {
|
|
159
|
+
const { keys } = listKeys(envPath);
|
|
160
|
+
const suppressed = collectSuppressedKeys(envPath);
|
|
162
161
|
const issues = [];
|
|
163
162
|
for (const key of keys) {
|
|
164
|
-
if (!
|
|
163
|
+
if (!isDangerousEnvKey(key))
|
|
165
164
|
continue;
|
|
166
165
|
if (suppressed.has(key))
|
|
167
166
|
continue;
|
|
168
167
|
issues.push({
|
|
169
168
|
file: relPath,
|
|
170
|
-
issue: "dangerous-
|
|
171
|
-
detail: `Env key \`${key}\` can be used to hijack process execution when injected via \`akm env run\`. Ref: ${
|
|
169
|
+
issue: "dangerous-env-key",
|
|
170
|
+
detail: `Env key \`${key}\` can be used to hijack process execution when injected via \`akm env run\`. Ref: ${envRef}. Review this file before running \`akm env run\` commands against untrusted stashes. (suppress with: ${SUPPRESSION_COMMENT} on previous line)`,
|
|
172
171
|
fixed: false,
|
|
173
172
|
});
|
|
174
173
|
}
|
|
175
174
|
return issues;
|
|
176
175
|
}
|
|
177
|
-
// ── Env-neutral aliases ───────────────────────────────────────────────────────
|
|
178
|
-
//
|
|
179
|
-
// These primitives guard *environment variable injection*, which is shared by
|
|
180
|
-
// the `env` asset type, whole-file `secret` injection, and the `akm add`
|
|
181
|
-
// supply-chain gate. The original `*Vault*` names are retained above for
|
|
182
|
-
// backward compatibility (and stable lint output) through the 0.8.x
|
|
183
|
-
// deprecation window; new call sites should prefer the env-neutral names.
|
|
184
|
-
/** Env-neutral alias of {@link DANGEROUS_VAULT_KEYS}. */
|
|
185
|
-
export const DANGEROUS_ENV_KEYS = DANGEROUS_VAULT_KEYS;
|
|
186
|
-
/** Env-neutral alias of {@link DANGEROUS_VAULT_KEY_PATTERNS}. */
|
|
187
|
-
export const DANGEROUS_ENV_KEY_PATTERNS = DANGEROUS_VAULT_KEY_PATTERNS;
|
|
188
|
-
/** Env-neutral alias of {@link isDangerousVaultKey}. */
|
|
189
|
-
export const isDangerousEnvKey = isDangerousVaultKey;
|
|
190
|
-
/** Env-neutral alias of {@link checkVaultForDangerousKeys}. */
|
|
191
|
-
export const checkEnvForDangerousKeys = checkVaultForDangerousKeys;
|