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
|
@@ -19,23 +19,22 @@
|
|
|
19
19
|
import { spawnSync } from "node:child_process";
|
|
20
20
|
import fs from "node:fs";
|
|
21
21
|
import path from "node:path";
|
|
22
|
+
import { getParsedInvocation } from "../../cli/invocation.js";
|
|
22
23
|
import { getStringArg } from "../../cli/parse-args.js";
|
|
23
24
|
import { defineGroupCommand, defineJsonCommand, output } from "../../cli/shared.js";
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import { isWithin, writeFileAtomic } from "../../core/common.js";
|
|
25
|
+
import { deriveCanonicalAssetName } from "../../core/asset/asset-placement.js";
|
|
26
|
+
import { writeFileAtomic } from "../../core/common.js";
|
|
27
27
|
import { loadConfig } from "../../core/config/config.js";
|
|
28
|
-
import {
|
|
28
|
+
import { makeEnvRef, resolveEnvPath, resolveEnvWriteTarget, withEnvSecretWrite } from "../../core/env-secret-ref.js";
|
|
29
29
|
import { ConfigError, NotFoundError, UsageError } from "../../core/errors.js";
|
|
30
|
-
import { isQuiet } from "../../core/warn.js";
|
|
31
30
|
import { resolveSourceEntries } from "../../indexer/search/search-source.js";
|
|
32
|
-
import { parseFlagValue } from "../../output/context.js";
|
|
33
31
|
import { readStdin } from "../../runtime.js";
|
|
34
32
|
import { buildChildEnv } from "./child-env.js";
|
|
33
|
+
import { sensitiveMarkerPath } from "./marker-path.js";
|
|
35
34
|
/**
|
|
36
35
|
* Walk each stash's env files and return one entry per `.env` file, using the
|
|
37
36
|
* env asset spec's canonical-name logic (e.g. `env/team/prod.env` →
|
|
38
|
-
* `env
|
|
37
|
+
* `env/team/prod`, `env/team/.env` → `env/team/default`).
|
|
39
38
|
*/
|
|
40
39
|
function listEnvsRecursive(listKeysFn) {
|
|
41
40
|
const result = [];
|
|
@@ -58,7 +57,7 @@ function listEnvsRecursive(listKeysFn) {
|
|
|
58
57
|
if (!canonical)
|
|
59
58
|
continue;
|
|
60
59
|
// Skip sensitive envs: a sibling .sensitive marker file suppresses listing.
|
|
61
|
-
const markerPath = full
|
|
60
|
+
const markerPath = sensitiveMarkerPath(full, "env");
|
|
62
61
|
if (fs.existsSync(markerPath))
|
|
63
62
|
continue;
|
|
64
63
|
const { keys } = listKeysFn(full);
|
|
@@ -70,7 +69,7 @@ function listEnvsRecursive(listKeysFn) {
|
|
|
70
69
|
return result;
|
|
71
70
|
}
|
|
72
71
|
const envListCommand = defineJsonCommand({
|
|
73
|
-
meta: { name: "list", description: "List all env files across all
|
|
72
|
+
meta: { name: "list", description: "List all env files across all bundles with their key names (no values)" },
|
|
74
73
|
async run() {
|
|
75
74
|
const { listKeys } = await import("./env.js");
|
|
76
75
|
output("env-list", { envs: listEnvsRecursive(listKeys) });
|
|
@@ -98,31 +97,29 @@ const envCreateCommand = defineJsonCommand({
|
|
|
98
97
|
description: "Exclude this env file from env list output and the search index",
|
|
99
98
|
default: false,
|
|
100
99
|
},
|
|
100
|
+
target: {
|
|
101
|
+
type: "string",
|
|
102
|
+
description: "Override the write destination. Accepts a source name from your config; falls back to defaultWriteTarget then the working bundle.",
|
|
103
|
+
},
|
|
101
104
|
},
|
|
102
105
|
async run({ args }) {
|
|
103
106
|
const { createEnv, writeEnv } = await import("./env.js");
|
|
104
|
-
// `create` always targets env/, never the frozen vaults/ copy.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const source = findEnvSource(parsed.origin);
|
|
110
|
-
const envRoot = path.join(source.path, "env");
|
|
111
|
-
const absPath = resolveAssetPathFromName("env", envRoot, parsed.name);
|
|
112
|
-
if (!isWithin(absPath, envRoot)) {
|
|
113
|
-
throw new UsageError(`Env name "${parsed.name}" escapes the env directory.`);
|
|
114
|
-
}
|
|
107
|
+
// `create` always targets env/, never the frozen vaults/ copy. `--path` is
|
|
108
|
+
// the subdirectory; `--target` selects the writable destination source.
|
|
109
|
+
const { name, absPath, target, ref } = resolveEnvWriteTarget(args.name, args.target, {
|
|
110
|
+
subPath: getStringArg(args, "path"),
|
|
111
|
+
});
|
|
115
112
|
const fromFile = args["from-file"];
|
|
116
113
|
const fromStdin = args["from-stdin"] === true;
|
|
117
114
|
if (fromFile !== undefined && fromStdin) {
|
|
118
115
|
throw new UsageError("Pass only one of --from-file or --from-stdin.", "INVALID_FLAG_VALUE");
|
|
119
116
|
}
|
|
117
|
+
let content;
|
|
120
118
|
if (fromFile !== undefined || fromStdin) {
|
|
121
119
|
// Ingest path: never silently clobber an existing env file.
|
|
122
120
|
if (fs.existsSync(absPath)) {
|
|
123
|
-
throw new UsageError(`Env "${
|
|
121
|
+
throw new UsageError(`Env "${ref}" already exists. Remove it first (\`akm env remove\`) or edit the file directly.`, "RESOURCE_ALREADY_EXISTS");
|
|
124
122
|
}
|
|
125
|
-
let content;
|
|
126
123
|
if (fromFile !== undefined) {
|
|
127
124
|
if (!fs.existsSync(fromFile)) {
|
|
128
125
|
throw new NotFoundError(`Source file not found: ${fromFile}`, "FILE_NOT_FOUND");
|
|
@@ -134,18 +131,24 @@ const envCreateCommand = defineJsonCommand({
|
|
|
134
131
|
const buf = await readStdin(MAX_ENV_BYTES, () => new UsageError("Env file exceeds 1 MB limit.", "INVALID_FLAG_VALUE"));
|
|
135
132
|
content = buf.toString("utf8");
|
|
136
133
|
}
|
|
137
|
-
writeEnv(absPath, content);
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
createEnv(absPath);
|
|
141
134
|
}
|
|
135
|
+
const written = [absPath];
|
|
136
|
+
const markerPath = sensitiveMarkerPath(absPath, "env");
|
|
142
137
|
if (args.sensitive) {
|
|
143
|
-
|
|
144
|
-
if (!fs.existsSync(markerPath)) {
|
|
145
|
-
fs.writeFileSync(markerPath, "", { mode: 0o600 });
|
|
146
|
-
}
|
|
138
|
+
written.push(markerPath);
|
|
147
139
|
}
|
|
148
|
-
|
|
140
|
+
withEnvSecretWrite(target, { type: "env", name }, "Update", written, () => {
|
|
141
|
+
if (content !== undefined)
|
|
142
|
+
writeEnv(absPath, content);
|
|
143
|
+
else
|
|
144
|
+
createEnv(absPath);
|
|
145
|
+
if (args.sensitive) {
|
|
146
|
+
if (!fs.existsSync(markerPath)) {
|
|
147
|
+
writeFileAtomic(markerPath, "", 0o600);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
output("env-create", { ref });
|
|
149
152
|
},
|
|
150
153
|
});
|
|
151
154
|
const envPathCommand = defineJsonCommand({
|
|
@@ -169,6 +172,22 @@ const envPathCommand = defineJsonCommand({
|
|
|
169
172
|
process.stderr.write(`warning: this is the raw file path. Do NOT \`source\` it (shell substitutions in the file would execute).\n` +
|
|
170
173
|
` To inject values run: akm env run ${args.ref} -- <command>\n`);
|
|
171
174
|
}
|
|
175
|
+
// F3/B3: this stdout write IS the payload — a bare absolute path for
|
|
176
|
+
// shell substitution (`$(akm env path <ref>)`, Docker `_FILE` /
|
|
177
|
+
// `--env-file`) — not a field inside a result envelope. `env path` is
|
|
178
|
+
// now declared format-exempt (src/output/format-exempt.ts, same
|
|
179
|
+
// classification as `env run`/`secret run`/`help`), so `--format`
|
|
180
|
+
// WARNS rather than doing anything to this write (src/cli.ts's startup
|
|
181
|
+
// `isFormatExemptCommand` check). An earlier version of this fix routed
|
|
182
|
+
// this through `output()` with a `{ path }` envelope so `--format`
|
|
183
|
+
// "worked" — but the CLI's process-wide default format is `json`, so a
|
|
184
|
+
// bare `akm env path <ref>` (exactly how `$(akm env path foo)` is
|
|
185
|
+
// written, with no explicit `--format`) started emitting
|
|
186
|
+
// `{"path":"..."}` instead of the raw path, breaking every existing
|
|
187
|
+
// shell substitution silently. Declaring the exemption is the correct
|
|
188
|
+
// fix: it keeps this byte-identical to history and makes the
|
|
189
|
+
// already-broken combination (`--format` + this command) loud instead
|
|
190
|
+
// of silent, per STABILITY.md's promise for exempt commands.
|
|
172
191
|
process.stdout.write(`${absPath}\n`);
|
|
173
192
|
},
|
|
174
193
|
});
|
|
@@ -204,11 +223,10 @@ const envExportCommand = defineJsonCommand({
|
|
|
204
223
|
* for process-hijacking variables.
|
|
205
224
|
*/
|
|
206
225
|
async function runEnvInjected(target, opts) {
|
|
207
|
-
const
|
|
208
|
-
if (
|
|
226
|
+
const command = getParsedInvocation().passthroughArgs();
|
|
227
|
+
if (command.length === 0) {
|
|
209
228
|
throw new UsageError("Missing command. Usage: akm env run <ref> -- <command>");
|
|
210
229
|
}
|
|
211
|
-
const command = process.argv.slice(dashIndex + 1);
|
|
212
230
|
const { name, absPath, source } = resolveEnvPath(target);
|
|
213
231
|
if (!fs.existsSync(absPath)) {
|
|
214
232
|
// Help users who reach for the removed single-key `ref/KEY` form.
|
|
@@ -225,7 +243,7 @@ async function runEnvInjected(target, opts) {
|
|
|
225
243
|
}
|
|
226
244
|
if (baseExists) {
|
|
227
245
|
throw new UsageError(`'akm env run' injects the whole file; the single-key '<ref>/${maybeKey}' form was removed.\n` +
|
|
228
|
-
` For one value use a secret: \`akm secret run
|
|
246
|
+
` For one value use a secret: \`akm secret run secrets/${maybeKey} ${maybeKey} -- <command>\`.`, "INVALID_FLAG_VALUE");
|
|
229
247
|
}
|
|
230
248
|
}
|
|
231
249
|
}
|
|
@@ -263,7 +281,15 @@ async function runEnvInjected(target, opts) {
|
|
|
263
281
|
}
|
|
264
282
|
throw err;
|
|
265
283
|
}
|
|
266
|
-
process.exit(result.status ?? 0)
|
|
284
|
+
// R-067: was `process.exit(result.status ?? 0)`, which terminates the
|
|
285
|
+
// process synchronously and skips the `finally { await
|
|
286
|
+
// disposeDispatchResources(); }` block in src/cli.ts's `runCommand` — even
|
|
287
|
+
// on the success path, since this call was unconditional. Setting
|
|
288
|
+
// `process.exitCode` and returning lets cleanup run while still exiting
|
|
289
|
+
// with the child's exact status once the event loop drains, matching the
|
|
290
|
+
// pattern `emitJsonError` (src/cli/shared.ts) already established.
|
|
291
|
+
process.exitCode = result.status ?? 0;
|
|
292
|
+
return;
|
|
267
293
|
}
|
|
268
294
|
/** Parse a comma/space-separated key list flag into a trimmed, non-empty array. */
|
|
269
295
|
function parseKeyListFlag(raw) {
|
|
@@ -280,7 +306,7 @@ const envRunCommand = defineJsonCommand({
|
|
|
280
306
|
name: "run",
|
|
281
307
|
description:
|
|
282
308
|
// biome-ignore lint/suspicious/noTemplateCurlyInString: literal `${secret:NAME}` token syntax documented for users, not interpolation
|
|
283
|
-
"Run a command with the env file injected into its environment: `akm env run <ref> -- <command>`. Use `-- $SHELL` for an interactive session. Restrict which variables are injected with --only / --except. Values may embed `${secret:NAME}` tokens, replaced at run time with the sibling
|
|
309
|
+
"Run a command with the env file injected into its environment: `akm env run <ref> -- <command>`. Use `-- $SHELL` for an interactive session. Restrict which variables are injected with --only / --except. Values may embed `${secret:NAME}` tokens, replaced at run time with the sibling `${secret:NAME}` value from the same bundle. Pass --clean to start the child with a minimal inherited environment instead of the full parent environment.",
|
|
284
310
|
},
|
|
285
311
|
args: {
|
|
286
312
|
target: { type: "positional", description: "Env ref", required: true },
|
|
@@ -313,15 +339,13 @@ const envRemoveCommand = defineJsonCommand({
|
|
|
313
339
|
args: {
|
|
314
340
|
ref: { type: "positional", description: "Env ref", required: true },
|
|
315
341
|
yes: { type: "boolean", alias: "y", description: "Skip confirmation prompt", default: false },
|
|
342
|
+
target: {
|
|
343
|
+
type: "string",
|
|
344
|
+
description: "Override the write destination. Accepts a source name from your config; falls back to defaultWriteTarget then the working bundle.",
|
|
345
|
+
},
|
|
316
346
|
},
|
|
317
347
|
async run({ args }) {
|
|
318
|
-
const
|
|
319
|
-
const source = findEnvSource(parsed.origin);
|
|
320
|
-
const envRoot = path.join(source.path, "env");
|
|
321
|
-
const absPath = resolveAssetPathFromName("env", envRoot, parsed.name);
|
|
322
|
-
if (!isWithin(absPath, envRoot)) {
|
|
323
|
-
throw new UsageError(`Env name "${parsed.name}" escapes the env directory.`);
|
|
324
|
-
}
|
|
348
|
+
const { name, absPath, target, ref } = resolveEnvWriteTarget(args.ref, args.target);
|
|
325
349
|
const { confirmDestructive } = await import("../../cli/confirm.js");
|
|
326
350
|
const confirmed = await confirmDestructive(`Remove env "${args.ref}"? This cannot be undone.`, {
|
|
327
351
|
yes: args.yes === true,
|
|
@@ -331,122 +355,18 @@ const envRemoveCommand = defineJsonCommand({
|
|
|
331
355
|
return;
|
|
332
356
|
}
|
|
333
357
|
if (!fs.existsSync(absPath)) {
|
|
334
|
-
throw new NotFoundError(`Env not found: ${
|
|
358
|
+
throw new NotFoundError(`Env not found: ${ref}`);
|
|
335
359
|
}
|
|
336
360
|
const { removeEnv } = await import("./env.js");
|
|
337
|
-
const removed = removeEnv(absPath);
|
|
338
|
-
output("env-remove", { ref
|
|
339
|
-
},
|
|
340
|
-
});
|
|
341
|
-
const envSetCommand = defineJsonCommand({
|
|
342
|
-
meta: {
|
|
343
|
-
name: "set",
|
|
344
|
-
description: "Set (create or update) a single KEY in an env file: `akm env set <ref> <KEY>`. The value is read from stdin by default (never via argv); use --from-env <VAR> or --from-file <path>. Preserves existing comments and key order; the value is never printed. Creates the env file if it does not exist.",
|
|
345
|
-
},
|
|
346
|
-
args: {
|
|
347
|
-
ref: { type: "positional", description: "Env ref (e.g. env:prod or just prod)", required: true },
|
|
348
|
-
key: { type: "positional", description: "Key name to set (e.g. API_URL)", required: true },
|
|
349
|
-
"from-env": { type: "string", description: "Read the value from the named environment variable" },
|
|
350
|
-
"from-file": { type: "string", description: "Read the value from this file" },
|
|
351
|
-
},
|
|
352
|
-
async run({ args }) {
|
|
353
|
-
const parsed = parseEnvRef(args.ref);
|
|
354
|
-
const source = findEnvSource(parsed.origin);
|
|
355
|
-
const envRoot = path.join(source.path, "env");
|
|
356
|
-
const absPath = resolveAssetPathFromName("env", envRoot, parsed.name);
|
|
357
|
-
if (!isWithin(absPath, envRoot)) {
|
|
358
|
-
throw new UsageError(`Env name "${parsed.name}" escapes the env directory.`);
|
|
359
|
-
}
|
|
360
|
-
const key = String(args.key);
|
|
361
|
-
const { ENV_KEY_RE, setEnvKey } = await import("./env.js");
|
|
362
|
-
if (!ENV_KEY_RE.test(key)) {
|
|
363
|
-
throw new UsageError(`Invalid env key "${key}". Keys match [A-Za-z_][A-Za-z0-9_]*.`, "INVALID_FLAG_VALUE");
|
|
364
|
-
}
|
|
365
|
-
const fromEnv = args["from-env"];
|
|
366
|
-
const fromFile = args["from-file"];
|
|
367
|
-
if (fromEnv !== undefined && fromFile !== undefined) {
|
|
368
|
-
throw new UsageError("Pass only one of --from-file or --from-env (or use stdin).", "INVALID_FLAG_VALUE");
|
|
369
|
-
}
|
|
370
|
-
const MAX_ENV_VALUE_BYTES = 1024 * 1024; // 1 MB
|
|
371
|
-
let value;
|
|
372
|
-
if (fromFile !== undefined) {
|
|
373
|
-
if (!fs.existsSync(fromFile)) {
|
|
374
|
-
throw new NotFoundError(`File not found: ${fromFile}`, "FILE_NOT_FOUND");
|
|
375
|
-
}
|
|
376
|
-
const buf = fs.readFileSync(fromFile);
|
|
377
|
-
if (buf.byteLength > MAX_ENV_VALUE_BYTES)
|
|
378
|
-
throw new UsageError("Value exceeds the 1 MB limit.");
|
|
379
|
-
value = buf.toString("utf8");
|
|
380
|
-
}
|
|
381
|
-
else if (fromEnv !== undefined) {
|
|
382
|
-
const v = process.env[fromEnv];
|
|
383
|
-
if (v === undefined) {
|
|
384
|
-
throw new UsageError(`Environment variable "${fromEnv}" is not set.`, "INVALID_FLAG_VALUE");
|
|
385
|
-
}
|
|
386
|
-
value = v;
|
|
387
|
-
}
|
|
388
|
-
else {
|
|
389
|
-
const buf = await readStdin(MAX_ENV_VALUE_BYTES, () => new UsageError("Value exceeds the 1 MB limit."));
|
|
390
|
-
// Strip a single trailing newline so `echo "$VAL" | akm env set` is exact.
|
|
391
|
-
value = buf.toString("utf8").replace(/\n$/, "");
|
|
392
|
-
}
|
|
393
|
-
setEnvKey(absPath, key, value);
|
|
394
|
-
// Warn (never block) on process-hijacking key names, matching the env-run audit.
|
|
395
|
-
const { isDangerousEnvKey } = await import("../lint/env-key-rules.js");
|
|
396
|
-
if (isDangerousEnvKey(key) && !isQuiet()) {
|
|
397
|
-
process.stderr.write(`warning: "${key}" can influence process execution when this env is loaded via 'akm env run'.\n`);
|
|
398
|
-
}
|
|
399
|
-
output("env-set", { ref: makeEnvRef(parsed.name, source), key });
|
|
400
|
-
},
|
|
401
|
-
});
|
|
402
|
-
const envUnsetCommand = defineJsonCommand({
|
|
403
|
-
meta: {
|
|
404
|
-
name: "unset",
|
|
405
|
-
description: "Remove one or more KEYs from an env file: `akm env unset <ref> <KEY...>`. Preserves other keys and comments. To remove the whole file, use `akm env remove`.",
|
|
406
|
-
},
|
|
407
|
-
args: {
|
|
408
|
-
ref: { type: "positional", description: "Env ref (e.g. env:prod or just prod)", required: true },
|
|
409
|
-
// `key` is read from the raw positionals (one or more) in run(); declared
|
|
410
|
-
// non-required so citty doesn't block before we emit a structured error.
|
|
411
|
-
key: { type: "positional", description: "Key name(s) to remove (one or more)", required: false },
|
|
412
|
-
},
|
|
413
|
-
async run({ args }) {
|
|
414
|
-
const parsed = parseEnvRef(args.ref);
|
|
415
|
-
const source = findEnvSource(parsed.origin);
|
|
416
|
-
const envRoot = path.join(source.path, "env");
|
|
417
|
-
const absPath = resolveAssetPathFromName("env", envRoot, parsed.name);
|
|
418
|
-
if (!isWithin(absPath, envRoot)) {
|
|
419
|
-
throw new UsageError(`Env name "${parsed.name}" escapes the env directory.`);
|
|
420
|
-
}
|
|
421
|
-
if (!fs.existsSync(absPath)) {
|
|
422
|
-
throw new NotFoundError(`Env not found: ${makeEnvRef(parsed.name, source)}`);
|
|
423
|
-
}
|
|
424
|
-
// citty puts every positional in `args._` (incl. the ref at [0]); the keys
|
|
425
|
-
// are the remaining positionals. citty also mis-captures the space-separated
|
|
426
|
-
// value of a global flag (`--format json`) as a positional, so drop any
|
|
427
|
-
// token that is actually a global flag's value (cli.ts:1335 documents this).
|
|
428
|
-
const globalFlagValues = new Set(["--format", "--shape", "--detail", "--scope", "--filter", "--target"]
|
|
429
|
-
.map((flag) => parseFlagValue(process.argv, flag))
|
|
430
|
-
.filter((v) => typeof v === "string"));
|
|
431
|
-
const keys = (Array.isArray(args._) ? args._.map(String) : [])
|
|
432
|
-
.slice(1)
|
|
433
|
-
.filter((k) => !globalFlagValues.has(k));
|
|
434
|
-
if (keys.length === 0) {
|
|
435
|
-
throw new UsageError("Usage: akm env unset <ref> <KEY...> (one or more keys).", "MISSING_REQUIRED_ARGUMENT");
|
|
436
|
-
}
|
|
437
|
-
const { ENV_KEY_RE, unsetEnvKeys } = await import("./env.js");
|
|
438
|
-
const invalid = keys.filter((k) => !ENV_KEY_RE.test(k));
|
|
439
|
-
if (invalid.length > 0) {
|
|
440
|
-
throw new UsageError(`Invalid env key(s): ${invalid.join(", ")}.`, "INVALID_FLAG_VALUE");
|
|
441
|
-
}
|
|
442
|
-
const { removed, missing } = unsetEnvKeys(absPath, keys);
|
|
443
|
-
output("env-unset", { ref: makeEnvRef(parsed.name, source), removed, missing });
|
|
361
|
+
const removed = withEnvSecretWrite(target, { type: "env", name }, "Remove", [absPath, sensitiveMarkerPath(absPath, "env")], () => removeEnv(absPath));
|
|
362
|
+
output("env-remove", { ref, removed });
|
|
444
363
|
},
|
|
445
364
|
});
|
|
446
365
|
export const envCommand = defineGroupCommand({
|
|
447
366
|
meta: {
|
|
448
367
|
name: "env",
|
|
449
|
-
description: "Manage `.env` files —
|
|
368
|
+
description: "Manage `.env` files — configuration values an app loads together (URLs, flags, and any credentials it needs).\n\n" +
|
|
369
|
+
"Values may or may not be sensitive; akm protects them all the same way — key names are visible, values never appear in structured output. For a single sensitive value used on its own (an auth token, key, or cert), use `akm secret`.",
|
|
450
370
|
},
|
|
451
371
|
subCommands: {
|
|
452
372
|
list: envListCommand,
|
|
@@ -454,12 +374,9 @@ export const envCommand = defineGroupCommand({
|
|
|
454
374
|
export: envExportCommand,
|
|
455
375
|
run: envRunCommand,
|
|
456
376
|
create: envCreateCommand,
|
|
457
|
-
set: envSetCommand,
|
|
458
|
-
unset: envUnsetCommand,
|
|
459
377
|
remove: envRemoveCommand,
|
|
460
378
|
},
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
},
|
|
379
|
+
// No `defaultRun`: bare `akm env` is a usage error (exit 2), the canonical
|
|
380
|
+
// bare-group behavior — owner ruling 12. Run `akm env list` for what the
|
|
381
|
+
// bare form used to print.
|
|
465
382
|
});
|
package/dist/commands/env/env.js
CHANGED
|
@@ -10,13 +10,10 @@
|
|
|
10
10
|
* them all the same. For a single sensitive value used on its own for
|
|
11
11
|
* authentication (a token, key, or cert), use the `secret` type instead.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* file with your own editor. Values are quoted/escaped only when necessary and
|
|
18
|
-
* round-trip through `dotenv`; the shell-load safety guarantee still lives on
|
|
19
|
-
* the READ path (see `buildShellExportScript` + `akm env export`).
|
|
13
|
+
* akm does not manage individual keys — edit the `.env` file with your own
|
|
14
|
+
* editor. Values are quoted/escaped only when necessary and round-trip
|
|
15
|
+
* through `dotenv`; the shell-load safety guarantee lives on the READ path
|
|
16
|
+
* (see `buildShellExportScript` + `akm env export`).
|
|
20
17
|
*
|
|
21
18
|
* Invariant: nothing from an env file except key NAMES may be written to
|
|
22
19
|
* stdout, returned through the indexer, the `akm show` renderer, or any
|
|
@@ -27,20 +24,18 @@
|
|
|
27
24
|
* are:
|
|
28
25
|
*
|
|
29
26
|
* - `akm env run <ref> -- <command>` — values injected into the child
|
|
30
|
-
* process env (never via a shell), see `
|
|
31
|
-
*
|
|
32
|
-
*
|
|
27
|
+
* process env (never via a shell), see `loadEnv` (loaded by
|
|
28
|
+
* `env-binding.ts#resolveEnvBinding`, then merged into the child env by
|
|
29
|
+
* `env-cli.ts`). This is the primary path and the only one safe for AI
|
|
30
|
+
* agents (no values ever reach stdout). For an interactive shell, `akm
|
|
31
|
+
* env run <ref> -- $SHELL`.
|
|
33
32
|
* - `akm env export <ref> --out <file>` — write parse-then-reserialized safe
|
|
34
33
|
* `export KEY='value'` lines to a file (mode 0600) for `source`-ing. Values
|
|
35
34
|
* are re-emitted single-quoted so a raw `.env` containing `X=$(cmd)` cannot
|
|
36
35
|
* execute on load. `export` never prints values to stdout (would leak into
|
|
37
36
|
* an agent's context); `path` prints only the file path.
|
|
38
37
|
*
|
|
39
|
-
* Value parsing is delegated to the `dotenv` package
|
|
40
|
-
* serialisation oracle for `env set` (`setEnvKey`): a written value is only
|
|
41
|
-
* committed if `dotenv.parse` reads it back exactly, and the whole edit is
|
|
42
|
-
* re-parsed to confirm no other key was disturbed. We never hand-roll a
|
|
43
|
-
* quoting representation we cannot read back.
|
|
38
|
+
* Value parsing is delegated to the `dotenv` package.
|
|
44
39
|
*
|
|
45
40
|
* Secret-token substitution: env VALUES may embed `${secret:NAME}` tokens, which
|
|
46
41
|
* are replaced at `env run` time with the value of the sibling `secret:NAME`
|
|
@@ -54,7 +49,7 @@ import fs from "node:fs";
|
|
|
54
49
|
import path from "node:path";
|
|
55
50
|
import dotenv from "dotenv";
|
|
56
51
|
import { writeFileAtomic } from "../../core/common.js";
|
|
57
|
-
import {
|
|
52
|
+
import { sensitiveMarkerPath } from "./marker-path.js";
|
|
58
53
|
/** Matches a KEY=value assignment line, capturing only the key. */
|
|
59
54
|
const ASSIGN_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
|
|
60
55
|
/** Scan lines and return KEY names in file order, without duplicates. */
|
|
@@ -101,21 +96,6 @@ export function loadEnv(envPath) {
|
|
|
101
96
|
const buf = fs.readFileSync(envPath);
|
|
102
97
|
return dotenv.parse(buf);
|
|
103
98
|
}
|
|
104
|
-
/**
|
|
105
|
-
* Load an env file and assign its values into `target` (defaults to
|
|
106
|
-
* `process.env`). Returns the list of keys that were set so the caller can
|
|
107
|
-
* log/observe without touching values.
|
|
108
|
-
*
|
|
109
|
-
* Existing keys in `target` are overwritten — callers who want to preserve
|
|
110
|
-
* pre-existing environment variables should filter before calling.
|
|
111
|
-
*/
|
|
112
|
-
export function injectIntoEnv(envPath, target = process.env) {
|
|
113
|
-
const env = loadEnv(envPath);
|
|
114
|
-
for (const [key, value] of Object.entries(env)) {
|
|
115
|
-
target[key] = value;
|
|
116
|
-
}
|
|
117
|
-
return Object.keys(env);
|
|
118
|
-
}
|
|
119
99
|
/**
|
|
120
100
|
* Serialise an env file's values as a POSIX shell script of `export KEY='value'`
|
|
121
101
|
* lines, with single-quote escaping (`'\''`). Every line is an assignment of a
|
|
@@ -214,142 +194,11 @@ export function removeEnv(envPath) {
|
|
|
214
194
|
if (!fs.existsSync(envPath))
|
|
215
195
|
return false;
|
|
216
196
|
fs.rmSync(envPath);
|
|
217
|
-
const marker =
|
|
197
|
+
const marker = sensitiveMarkerPath(envPath, "env");
|
|
218
198
|
if (fs.existsSync(marker))
|
|
219
199
|
fs.rmSync(marker);
|
|
220
200
|
return true;
|
|
221
201
|
}
|
|
222
|
-
/** A valid env KEY name (same grammar as the assignment scanner). */
|
|
223
|
-
export const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
224
|
-
/**
|
|
225
|
-
* Build a `KEY=value` assignment line whose value is GUARANTEED to round-trip
|
|
226
|
-
* through `dotenv.parse` — dotenv is the serialisation oracle, so we never
|
|
227
|
-
* write a representation we cannot read back. Candidate representations are
|
|
228
|
-
* tried in order of readability (bare → double-quoted → single-quoted) and the
|
|
229
|
-
* first one `dotenv.parse` recovers exactly is used. If a value contains
|
|
230
|
-
* characters no inline representation can round-trip (e.g. both quote styles),
|
|
231
|
-
* we throw rather than silently corrupt the file.
|
|
232
|
-
*/
|
|
233
|
-
function serializeEnvAssignment(key, value) {
|
|
234
|
-
const candidates = [];
|
|
235
|
-
// Bare — only for simple values (no whitespace/quotes/#/$/control chars).
|
|
236
|
-
if (/^[A-Za-z0-9_@%+=:,./-]*$/.test(value))
|
|
237
|
-
candidates.push(`${key}=${value}`);
|
|
238
|
-
// Double-quoted — dotenv expands \n \r \t inside double quotes.
|
|
239
|
-
const dq = value
|
|
240
|
-
.replace(/\\/g, "\\\\")
|
|
241
|
-
.replace(/"/g, '\\"')
|
|
242
|
-
.replace(/\n/g, "\\n")
|
|
243
|
-
.replace(/\r/g, "\\r")
|
|
244
|
-
.replace(/\t/g, "\\t");
|
|
245
|
-
candidates.push(`${key}="${dq}"`);
|
|
246
|
-
// Single-quoted — dotenv takes the content literally (no escapes/expansion).
|
|
247
|
-
candidates.push(`${key}='${value}'`);
|
|
248
|
-
for (const line of candidates) {
|
|
249
|
-
try {
|
|
250
|
-
if (dotenv.parse(line)[key] === value)
|
|
251
|
-
return line;
|
|
252
|
-
}
|
|
253
|
-
catch {
|
|
254
|
-
// Not parseable as written; try the next representation.
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
throw new UsageError(`Value for "${key}" cannot be stored inline in a .env file (it contains characters dotenv cannot round-trip). ` +
|
|
258
|
-
"Edit the .env file directly, or choose a different value.");
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Assert (using `dotenv.parse` as the oracle) that `after` set `key` to
|
|
262
|
-
* `expected` and left every other key from `before` byte-identical. This
|
|
263
|
-
* catches a line-level edit accidentally disturbing a quoted/multiline value.
|
|
264
|
-
*/
|
|
265
|
-
function assertEnvEditSafe(before, after, key) {
|
|
266
|
-
for (const [k, v] of Object.entries(before)) {
|
|
267
|
-
if (k !== key && after[k] !== v) {
|
|
268
|
-
throw new UsageError(`Editing "${key}" would disturb "${k}" (the .env file has a value layout dotenv could not safely round-trip). ` +
|
|
269
|
-
"Edit the .env file directly.");
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Set (create or update) a single `KEY=value` entry in an env file, preserving
|
|
275
|
-
* the file's existing lines, comments, and key order. The first existing
|
|
276
|
-
* assignment of `key` is replaced in place; otherwise the entry is appended.
|
|
277
|
-
* Creates the file (and parent dirs) if absent. The value is never logged.
|
|
278
|
-
*
|
|
279
|
-
* The serialised value and the whole resulting file are verified with
|
|
280
|
-
* `dotenv.parse` before the write commits.
|
|
281
|
-
*/
|
|
282
|
-
export function setEnvKey(envPath, key, value) {
|
|
283
|
-
ensureParentDir(envPath);
|
|
284
|
-
const existing = fs.existsSync(envPath) ? fs.readFileSync(envPath, "utf8") : "";
|
|
285
|
-
const assignment = serializeEnvAssignment(key, value);
|
|
286
|
-
const keyLineRe = new RegExp(`^\\s*(?:export\\s+)?${key}\\s*=`);
|
|
287
|
-
const lines = existing.split(/\r?\n/);
|
|
288
|
-
let replaced = false;
|
|
289
|
-
const out = lines.map((line) => {
|
|
290
|
-
if (!replaced && keyLineRe.test(line)) {
|
|
291
|
-
replaced = true;
|
|
292
|
-
return assignment;
|
|
293
|
-
}
|
|
294
|
-
return line;
|
|
295
|
-
});
|
|
296
|
-
if (!replaced) {
|
|
297
|
-
while (out.length > 0 && out[out.length - 1] === "")
|
|
298
|
-
out.pop();
|
|
299
|
-
out.push(assignment);
|
|
300
|
-
}
|
|
301
|
-
let content = out.join("\n");
|
|
302
|
-
if (!content.endsWith("\n"))
|
|
303
|
-
content += "\n";
|
|
304
|
-
// Verify the edit with dotenv before committing it.
|
|
305
|
-
const after = dotenv.parse(content);
|
|
306
|
-
if (after[key] !== value) {
|
|
307
|
-
throw new UsageError(`Could not set "${key}" reliably (the .env file has a value layout dotenv could not round-trip). ` +
|
|
308
|
-
"Edit the .env file directly.");
|
|
309
|
-
}
|
|
310
|
-
assertEnvEditSafe(dotenv.parse(existing), after, key);
|
|
311
|
-
writeFileAtomic(envPath, content, 0o600);
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Remove one or more `KEY=value` entries from an env file, preserving all other
|
|
315
|
-
* lines and comments. Returns which keys were present (removed) vs. absent.
|
|
316
|
-
*
|
|
317
|
-
* The result is verified with `dotenv.parse`: the removed keys are gone and
|
|
318
|
-
* every surviving key is byte-identical to before.
|
|
319
|
-
*/
|
|
320
|
-
export function unsetEnvKeys(envPath, keys) {
|
|
321
|
-
if (!fs.existsSync(envPath))
|
|
322
|
-
return { removed: [], missing: keys };
|
|
323
|
-
const text = fs.readFileSync(envPath, "utf8");
|
|
324
|
-
const before = dotenv.parse(text);
|
|
325
|
-
const present = new Set(Object.keys(before));
|
|
326
|
-
const toRemove = new Set(keys);
|
|
327
|
-
const out = text.split(/\r?\n/).filter((line) => {
|
|
328
|
-
const m = line.match(ASSIGN_RE);
|
|
329
|
-
return !(m && toRemove.has(m[1]));
|
|
330
|
-
});
|
|
331
|
-
let content = out.join("\n");
|
|
332
|
-
if (content.length > 0 && !content.endsWith("\n"))
|
|
333
|
-
content += "\n";
|
|
334
|
-
// Verify with dotenv: removed keys gone, survivors unchanged.
|
|
335
|
-
const after = dotenv.parse(content);
|
|
336
|
-
for (const k of toRemove) {
|
|
337
|
-
if (k in after) {
|
|
338
|
-
throw new UsageError(`Could not remove "${k}" reliably (the .env file has a value layout dotenv could not round-trip). ` +
|
|
339
|
-
"Edit the .env file directly.");
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
for (const [k, v] of Object.entries(before)) {
|
|
343
|
-
if (!toRemove.has(k) && after[k] !== v) {
|
|
344
|
-
throw new UsageError(`Removing those keys would disturb "${k}" (multiline/quoted value). Edit the .env file directly.`);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
writeFileAtomic(envPath, content, 0o600);
|
|
348
|
-
return {
|
|
349
|
-
removed: keys.filter((k) => present.has(k)),
|
|
350
|
-
missing: keys.filter((k) => !present.has(k)),
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
202
|
function ensureParentDir(filePath) {
|
|
354
203
|
const dir = path.dirname(filePath);
|
|
355
204
|
if (!fs.existsSync(dir))
|
|
@@ -0,0 +1,6 @@
|
|
|
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
|
+
export function sensitiveMarkerPath(assetPath, type) {
|
|
5
|
+
return type === "env" ? assetPath.replace(/\.env$/, ".sensitive") : `${assetPath}.sensitive`;
|
|
6
|
+
}
|