akm-cli 0.9.0-rc.0 → 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 +1283 -22
- 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/prompts/workflow-unit-preamble.md +26 -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 +99 -0
- package/dist/commands/env/env-cli.js +84 -224
- 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/migration-help.js +7 -4
- 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 +232 -121
- 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 -834
- 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/json-schema.js +142 -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 -34
- 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 -56
- 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 +16 -2
- package/dist/integrations/agent/profiles.js +36 -62
- package/dist/integrations/agent/prompts.js +46 -18
- package/dist/integrations/agent/runner-dispatch.js +93 -4
- package/dist/integrations/agent/runner.js +76 -208
- package/dist/integrations/agent/spawn.js +88 -196
- package/dist/integrations/harnesses/aider/agent-builder.js +114 -0
- package/dist/integrations/harnesses/aider/index.js +48 -0
- package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
- package/dist/integrations/harnesses/amazonq/agent-builder.js +147 -0
- package/dist/integrations/harnesses/amazonq/index.js +45 -0
- package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
- package/dist/integrations/harnesses/claude/agent-builder.js +46 -8
- package/dist/integrations/harnesses/claude/config-import.js +1 -3
- package/dist/integrations/harnesses/claude/index.js +24 -35
- package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
- package/dist/integrations/harnesses/claude/session-log.js +27 -75
- package/dist/integrations/harnesses/codex/agent-builder.js +138 -0
- package/dist/integrations/harnesses/codex/index.js +52 -0
- package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
- package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
- package/dist/integrations/harnesses/copilot/index.js +48 -0
- package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
- package/dist/integrations/harnesses/gemini/agent-builder.js +120 -0
- package/dist/integrations/harnesses/gemini/index.js +48 -0
- package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
- package/dist/integrations/harnesses/ids.js +24 -0
- package/dist/integrations/harnesses/index.js +54 -34
- 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 +14 -32
- package/dist/integrations/harnesses/opencode/session-log.js +67 -125
- package/dist/integrations/harnesses/opencode-sdk/harness.js +51 -0
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +681 -108
- package/dist/integrations/harnesses/openhands/agent-builder.js +128 -0
- package/dist/integrations/harnesses/openhands/index.js +48 -0
- package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
- package/dist/integrations/harnesses/pi/agent-builder.js +97 -0
- package/dist/integrations/harnesses/pi/index.js +45 -0
- package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
- package/dist/integrations/harnesses/shared.js +17 -0
- package/dist/integrations/harnesses/types.js +43 -32
- package/dist/integrations/lockfile.js +211 -24
- package/dist/integrations/session-logs/index.js +36 -39
- 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 +14 -279
- 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 +11 -39
- 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 -1164
- 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 +3 -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 +240 -19
- 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/text-import-hook.mjs +1 -1
- package/dist/workflows/authoring/authoring.js +104 -43
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/cli.js +0 -16
- package/dist/workflows/concurrency-policy.js +15 -0
- package/dist/workflows/exec/brief.js +450 -0
- package/dist/workflows/exec/frozen-judge.js +47 -0
- package/dist/workflows/exec/native-executor.js +1038 -0
- package/dist/workflows/exec/param-secrets.js +115 -0
- package/dist/workflows/exec/report.js +1460 -0
- package/dist/workflows/exec/run-workflow.js +602 -0
- package/dist/workflows/exec/scheduler.js +71 -0
- package/dist/workflows/exec/step-work.js +1190 -0
- package/dist/workflows/exec/unit-writer.js +23 -0
- package/dist/workflows/exec/workflow-engine-gate.js +67 -0
- package/dist/workflows/exec/worktree.js +171 -0
- package/dist/workflows/ir/compile.js +246 -0
- package/dist/workflows/ir/freeze.js +233 -0
- package/dist/workflows/ir/params.js +54 -0
- package/dist/workflows/ir/plan-hash.js +68 -0
- package/dist/workflows/ir/schema.js +540 -0
- package/dist/workflows/parser.js +878 -304
- package/dist/workflows/program/expressions.js +181 -0
- package/dist/workflows/program/schema.js +51 -0
- package/dist/workflows/renderer.js +100 -45
- package/dist/workflows/resource-limits.js +22 -0
- package/dist/workflows/runtime/agent-identity.js +59 -14
- package/dist/workflows/runtime/checkin.js +1 -1
- package/dist/workflows/runtime/plan-classifier.js +131 -0
- package/dist/workflows/runtime/runs.js +376 -119
- package/dist/workflows/runtime/unit-checkin.js +45 -0
- package/dist/workflows/runtime/unit-phases.js +20 -0
- package/dist/workflows/runtime/workflow-asset-loader.js +241 -40
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +2 -3
- 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/schemas/akm-workflow.json +373 -0
- 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 -259
- 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 -1413
- 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 -49
- 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/scripts/migrate-storage.js +0 -19108
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -9411
- 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/db.js +0 -215
- package/docs/data-and-telemetry.md +0 -226
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
|
@@ -4,11 +4,20 @@
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { ConfigError } from "../errors.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { AkmConfigSchema } from "./config-schema.js";
|
|
7
|
+
import { assertNoPendingMigrationOperation } from "../migration-operation.js";
|
|
8
|
+
import { acquireConfigLock, backupExistingConfig, parseConfigText, readConfigText, withConfigLock, writeConfigAtomic, } from "./config-io.js";
|
|
9
|
+
import { AkmConfigSchema, CURRENT_CONFIG_VERSION } from "./config-schema.js";
|
|
10
|
+
import { bundlesToSourceEntries } from "./config-sources.js";
|
|
11
|
+
import { deepMergeConfig } from "./deep-merge.js";
|
|
10
12
|
export { stripJsonComments } from "./config-io.js";
|
|
11
|
-
|
|
13
|
+
// requireLlmConfig / getDefaultLlmConfig moved to
|
|
14
|
+
// integrations/agent/engine-resolution.ts (WI-9.8 KILL 3, D.3 edge A) — they
|
|
15
|
+
// called that module's materializeLlmConnection/resolveLlmEngineUse, and that
|
|
16
|
+
// module imported LlmConnectionConfig back from this file, closing a 2-file
|
|
17
|
+
// cycle that also fused config.ts into the harness/agent-runtime SCC. This
|
|
18
|
+
// file can no longer re-export them (a re-export is still a graph edge to
|
|
19
|
+
// engine-resolution.ts) — import them from there directly.
|
|
20
|
+
import { getConfigPath } from "../paths.js";
|
|
12
21
|
import { warn } from "../warn.js";
|
|
13
22
|
// Canonical harness-id source of truth (#565) — runtime value re-export.
|
|
14
23
|
export { VALID_HARNESS_IDS } from "./config-types.js";
|
|
@@ -48,7 +57,8 @@ export function resolveBatchSize(configured, contextLength) {
|
|
|
48
57
|
}
|
|
49
58
|
// ── Defaults ────────────────────────────────────────────────────────────────
|
|
50
59
|
export const DEFAULT_CONFIG = {
|
|
51
|
-
|
|
60
|
+
configVersion: "0.9.0",
|
|
61
|
+
semanticSearchMode: "off",
|
|
52
62
|
registries: [
|
|
53
63
|
{ url: "https://raw.githubusercontent.com/itlackey/akm-registry/main/index.json", name: "akm-registry" },
|
|
54
64
|
{ url: "https://skills.sh", name: "skills.sh", provider: "skills-sh", enabled: false },
|
|
@@ -59,20 +69,23 @@ export const DEFAULT_CONFIG = {
|
|
|
59
69
|
},
|
|
60
70
|
};
|
|
61
71
|
// ── Load / Save / Update ────────────────────────────────────────────────────
|
|
62
|
-
const PROJECT_CONFIG_RELATIVE_PATH = path.join(".akm", "config.json");
|
|
63
72
|
let cachedConfig;
|
|
64
73
|
export function resetConfigCache() {
|
|
65
74
|
cachedConfig = undefined;
|
|
66
75
|
}
|
|
67
76
|
export function loadUserConfig() {
|
|
77
|
+
assertNoPendingMigrationOperation();
|
|
68
78
|
const configPath = getConfigPath();
|
|
69
79
|
let stat;
|
|
70
80
|
try {
|
|
71
81
|
stat = fs.statSync(configPath);
|
|
72
82
|
}
|
|
73
|
-
catch {
|
|
83
|
+
catch (err) {
|
|
84
|
+
if (err.code !== "ENOENT") {
|
|
85
|
+
throw new ConfigError(`Unable to read config at ${configPath}: ${err instanceof Error ? err.message : String(err)}`, "INVALID_CONFIG_FILE");
|
|
86
|
+
}
|
|
74
87
|
cachedConfig = undefined;
|
|
75
|
-
return
|
|
88
|
+
return { ...DEFAULT_CONFIG };
|
|
76
89
|
}
|
|
77
90
|
// Cache key: mtimeMs + size. Tests that write rapidly back-to-back inside
|
|
78
91
|
// the mtime resolution window MUST call resetConfigCache() between writes —
|
|
@@ -85,17 +98,16 @@ export function loadUserConfig() {
|
|
|
85
98
|
}
|
|
86
99
|
let text;
|
|
87
100
|
try {
|
|
88
|
-
text =
|
|
101
|
+
text = readConfigText(configPath);
|
|
89
102
|
}
|
|
90
|
-
catch {
|
|
103
|
+
catch (err) {
|
|
104
|
+
throw new ConfigError(`Unable to read config at ${configPath}: ${err instanceof Error ? err.message : String(err)}`, "INVALID_CONFIG_FILE");
|
|
105
|
+
}
|
|
106
|
+
if (text === undefined) {
|
|
91
107
|
cachedConfig = undefined;
|
|
92
|
-
return
|
|
108
|
+
return { ...DEFAULT_CONFIG };
|
|
93
109
|
}
|
|
94
|
-
|
|
95
|
-
// sees canonical input. AKM_NO_AUTO_MIGRATE=1 skips the disk rewrite (still
|
|
96
|
-
// applies in-memory).
|
|
97
|
-
text = maybeAutoMigrateConfigFile(configPath, text);
|
|
98
|
-
const finalConfig = applyRuntimeEnvApiKeys(parseAndValidate(text, configPath));
|
|
110
|
+
const finalConfig = parseAndValidateConfigText(text, configPath);
|
|
99
111
|
// Re-stat after potential write-back so the cache key reflects the new mtime.
|
|
100
112
|
let finalStat = stat;
|
|
101
113
|
try {
|
|
@@ -113,222 +125,141 @@ export function loadUserConfig() {
|
|
|
113
125
|
return finalConfig;
|
|
114
126
|
}
|
|
115
127
|
/**
|
|
116
|
-
* Parse raw config text
|
|
117
|
-
* ({@link migrateConfigShape}), then validate via Zod
|
|
128
|
+
* Parse raw config text and validate via Zod.
|
|
118
129
|
* ({@link AkmConfigSchema}). Returns the merged-with-defaults AkmConfig.
|
|
119
130
|
*
|
|
120
|
-
* The
|
|
121
|
-
*
|
|
122
|
-
* the canonical shape and throws on anything it doesn't recognise.
|
|
131
|
+
* The schema accepts only the current config version and validates the
|
|
132
|
+
* canonical shape before defaults are merged.
|
|
123
133
|
*/
|
|
124
|
-
function
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const parsed = AkmConfigSchema.safeParse(
|
|
134
|
+
export function parseAndValidateConfigText(text, sourcePath) {
|
|
135
|
+
const raw = parseConfigText(text, sourcePath);
|
|
136
|
+
if (raw.configVersion !== CURRENT_CONFIG_VERSION) {
|
|
137
|
+
throw new ConfigError(`Unsupported configVersion${sourcePath ? ` at ${sourcePath}` : ""}: expected "${CURRENT_CONFIG_VERSION}".`, "UNSUPPORTED_CONFIG_VERSION", "Recreate engines and improve.strategies manually for AKM 0.9.0; profile-based configuration is not translated automatically.");
|
|
138
|
+
}
|
|
139
|
+
const parsed = AkmConfigSchema.safeParse(raw);
|
|
130
140
|
if (!parsed.success) {
|
|
131
141
|
const lines = parsed.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join("\n");
|
|
132
142
|
const where = sourcePath ? ` at ${sourcePath}` : "";
|
|
133
143
|
throw new ConfigError(`Invalid config${where}:\n${lines}`, "INVALID_CONFIG_FILE");
|
|
134
144
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
export function getEffectiveRegistries(config) {
|
|
141
|
-
return config.registries ?? DEFAULT_CONFIG.registries ?? [];
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Resolve the name of the default LLM profile.
|
|
145
|
-
*
|
|
146
|
-
* Resolution order:
|
|
147
|
-
* 1. `defaults.llm` — explicit pointer set by the user.
|
|
148
|
-
* 2. A profile literally named `default` under `profiles.llm` — implicit
|
|
149
|
-
* fallback. The convention "name your default profile `default`" is
|
|
150
|
-
* what `akm setup` produces, so an unset `defaults.llm` next to a
|
|
151
|
-
* `profiles.llm.default` block is overwhelmingly a config-rewrite
|
|
152
|
-
* casualty (see [[project_akm_config_clobber_trap]]) rather than
|
|
153
|
-
* intent. Treating that shape as configured avoids the silent
|
|
154
|
-
* `getDefaultLlmConfig → undefined → pass-returns-zero` failure mode
|
|
155
|
-
* that produced 18h of no-op memory-inference runs on 2026-05-23.
|
|
156
|
-
*
|
|
157
|
-
* Returns `undefined` when neither path resolves to a profile name.
|
|
158
|
-
*/
|
|
159
|
-
function resolveDefaultLlmProfileName(config) {
|
|
160
|
-
const explicit = config.defaults?.llm;
|
|
161
|
-
if (explicit)
|
|
162
|
-
return explicit;
|
|
163
|
-
if (config.profiles?.llm?.default)
|
|
164
|
-
return "default";
|
|
165
|
-
return undefined;
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Resolve the default LLM connection from `profiles.llm[defaults.llm]`.
|
|
169
|
-
*
|
|
170
|
-
* Throws {@link ConfigError} when no default profile can be resolved (neither
|
|
171
|
-
* `defaults.llm` nor an implicit `profiles.llm.default`) or when the named
|
|
172
|
-
* profile does not exist under `profiles.llm`. Use this in code paths that
|
|
173
|
-
* must have an LLM configured (per-pass index calls, distill, consolidate,
|
|
174
|
-
* etc).
|
|
175
|
-
*/
|
|
176
|
-
export function requireLlmConfig(config) {
|
|
177
|
-
const defaultName = resolveDefaultLlmProfileName(config);
|
|
178
|
-
if (!defaultName) {
|
|
179
|
-
throw new ConfigError("LLM is not configured. Run `akm setup` or set `defaults.llm` to a profile defined in `profiles.llm`.", "LLM_NOT_CONFIGURED");
|
|
180
|
-
}
|
|
181
|
-
const profile = config.profiles?.llm?.[defaultName];
|
|
182
|
-
if (!profile) {
|
|
183
|
-
throw new ConfigError(`LLM default profile "${defaultName}" not found in profiles.llm.`, "LLM_NOT_CONFIGURED", `Available profiles: ${Object.keys(config.profiles?.llm ?? {}).join(", ") || "none"}. Run \`akm setup\` to configure.`);
|
|
145
|
+
const merged = deepMergeConfig(DEFAULT_CONFIG, parsed.data);
|
|
146
|
+
const finalResult = AkmConfigSchema.safeParse(merged);
|
|
147
|
+
if (!finalResult.success) {
|
|
148
|
+
const lines = finalResult.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join("\n");
|
|
149
|
+
throw new ConfigError(`Invalid merged config${sourcePath ? ` at ${sourcePath}` : ""}:\n${lines}`, "INVALID_CONFIG_FILE");
|
|
184
150
|
}
|
|
185
|
-
return
|
|
151
|
+
return finalResult.data;
|
|
186
152
|
}
|
|
187
153
|
/**
|
|
188
|
-
*
|
|
189
|
-
* when no LLM is configured. Use in code paths where the LLM is optional.
|
|
190
|
-
*/
|
|
191
|
-
export function getDefaultLlmConfig(config) {
|
|
192
|
-
const defaultName = resolveDefaultLlmProfileName(config);
|
|
193
|
-
if (!defaultName)
|
|
194
|
-
return undefined;
|
|
195
|
-
return config.profiles?.llm?.[defaultName];
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Resolve the per-process config section for an improve process,
|
|
199
|
-
* centralizing the deeply-nested lookup
|
|
200
|
-
* `profile?.processes?.<name>` that was previously copy-pasted across the
|
|
201
|
-
* improve command family (20+ call sites).
|
|
154
|
+
* The configured stash sources as an ordered {@link SourceConfigEntry} list.
|
|
202
155
|
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* get the historical default-profile behavior unchanged.
|
|
156
|
+
* 0.9.0 (spec §10.1): the retired `stashDir`/`sources[]`/`installed[]` trio is
|
|
157
|
+
* gone — every source is a `bundles.<slug>` entry. This derives the unified
|
|
158
|
+
* source list from `bundles` (defaultBundle first, then map order), so callers
|
|
159
|
+
* that iterated `sources[]` keep working over the new shape. Returns `[]` when
|
|
160
|
+
* no bundles are configured.
|
|
209
161
|
*/
|
|
210
|
-
export function
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
return config.
|
|
162
|
+
export function getSources(config) {
|
|
163
|
+
return bundlesToSourceEntries(config) ?? [];
|
|
164
|
+
}
|
|
165
|
+
export function getEffectiveRegistries(config) {
|
|
166
|
+
return config.registries ?? DEFAULT_CONFIG.registries ?? [];
|
|
215
167
|
}
|
|
216
168
|
/**
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* for the caller to feed into `parseAndValidate`.
|
|
220
|
-
*
|
|
221
|
-
* If the on-disk config is newer than this binary's known version, the bytes
|
|
222
|
-
* are left untouched (we won't silently strip fields on downgrade).
|
|
169
|
+
* Transitional internal accessor. It deliberately never consults a configured
|
|
170
|
+
* default strategy; callers must pass their already selected strategy.
|
|
223
171
|
*/
|
|
224
|
-
function
|
|
225
|
-
|
|
226
|
-
try {
|
|
227
|
-
obj = parseConfigText(text);
|
|
228
|
-
}
|
|
229
|
-
catch {
|
|
230
|
-
return text; // Malformed JSON — let parseAndValidate surface the error.
|
|
231
|
-
}
|
|
232
|
-
// Downgrade protection. Skip migration when the on-disk config is NEWER than
|
|
233
|
-
// this binary (=== 1), OR when it carries a configVersion we cannot order
|
|
234
|
-
// against ours (compareConfigVersion returns undefined for an unparseable
|
|
235
|
-
// value — e.g. one written by a newer/foreign akm). Migrating such a config
|
|
236
|
-
// could strip fields a newer binary added, a cross-version data-loss path.
|
|
237
|
-
//
|
|
238
|
-
// A MISSING configVersion (absent → undefined) is a legacy pre-versioning
|
|
239
|
-
// config that MUST still migrate, so the unparseable-skip is gated on the
|
|
240
|
-
// field being PRESENT (`onDiskVersion !== undefined`).
|
|
241
|
-
const onDiskVersion = obj.configVersion;
|
|
242
|
-
const versionOrder = compareConfigVersion(onDiskVersion, CURRENT_CONFIG_VERSION);
|
|
243
|
-
if (versionOrder === 1 || (onDiskVersion !== undefined && versionOrder === undefined)) {
|
|
244
|
-
return text;
|
|
245
|
-
}
|
|
246
|
-
const { changed, result } = migrateConfigShape(obj);
|
|
247
|
-
if (!changed)
|
|
248
|
-
return text;
|
|
249
|
-
const migratedText = `${JSON.stringify(result, null, 2)}\n`;
|
|
250
|
-
if (process.env.AKM_NO_AUTO_MIGRATE === "1")
|
|
251
|
-
return migratedText;
|
|
252
|
-
try {
|
|
253
|
-
withConfigLock(() => {
|
|
254
|
-
backupExistingConfig(configPath);
|
|
255
|
-
writeConfigAtomic(configPath, result);
|
|
256
|
-
});
|
|
257
|
-
const newVersion = typeof result.configVersion === "string" ? result.configVersion : "0.8.0";
|
|
258
|
-
const backupDir = `${getCacheDir()}/config-backups`;
|
|
259
|
-
// WS-2: emit a loud banner to BOTH stderr and stdout so pipelines and
|
|
260
|
-
// interactive terminals both see it. Include the backup path (resolved,
|
|
261
|
-
// not ~/...), opt-out env var, and preview diff command.
|
|
262
|
-
const banner = [
|
|
263
|
-
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
|
|
264
|
-
` akm: auto-migrated config → ${newVersion} format`,
|
|
265
|
-
` file: ${configPath}`,
|
|
266
|
-
` backup: ${backupDir}/config-<timestamp>.json`,
|
|
267
|
-
" to opt out of future auto-migration: AKM_NO_AUTO_MIGRATE=1",
|
|
268
|
-
" to preview a dry-run diff: akm config migrate --dry-run --print-diff",
|
|
269
|
-
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
|
|
270
|
-
].join("\n");
|
|
271
|
-
process.stderr?.write?.(`${banner}\n`);
|
|
272
|
-
process.stdout?.write?.(`${banner}\n`);
|
|
273
|
-
}
|
|
274
|
-
catch (err) {
|
|
275
|
-
// #461: never return migrated bytes when disk write fails — that triggers
|
|
276
|
-
// an infinite re-migrate loop on every load. Hard-error so the user
|
|
277
|
-
// notices and either fixes the disk issue or sets AKM_NO_AUTO_MIGRATE=1.
|
|
278
|
-
throw new ConfigError(`Failed to write migrated config to ${configPath}: ${err instanceof Error ? err.message : String(err)}`, "INVALID_CONFIG_FILE", "Check filesystem permissions, free space, and disk health. To skip auto-migration, set AKM_NO_AUTO_MIGRATE=1.");
|
|
279
|
-
}
|
|
280
|
-
return migratedText;
|
|
172
|
+
export function getImproveProcessConfig(processName, selected) {
|
|
173
|
+
return selected?.processes?.[processName];
|
|
281
174
|
}
|
|
282
175
|
export function loadConfig() {
|
|
283
|
-
// Single-layer load: only the user-level config file is read. Project-level
|
|
284
|
-
// .akm/config.json files discovered under cwd-ancestors emit a one-time
|
|
285
|
-
// deprecation warning (#457) but are NOT merged.
|
|
286
|
-
warnIfProjectConfigPresent(process.cwd());
|
|
287
176
|
return loadUserConfig();
|
|
288
177
|
}
|
|
289
|
-
let saveConfigOverride;
|
|
290
|
-
/** TEST-ONLY. Swap the implementation of `saveConfig`; pass undefined to restore. */
|
|
291
|
-
export function _setSaveConfigForTests(fake) {
|
|
292
|
-
saveConfigOverride = fake;
|
|
293
|
-
}
|
|
294
178
|
export function saveConfig(config) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
saveConfigReal(config);
|
|
179
|
+
// Every lifecycle write produces the only config version this binary can load.
|
|
180
|
+
const currentConfig = { ...config, configVersion: CURRENT_CONFIG_VERSION };
|
|
181
|
+
saveConfigReal(currentConfig);
|
|
300
182
|
}
|
|
301
183
|
function saveConfigReal(config) {
|
|
184
|
+
assertNoPendingMigrationOperation();
|
|
302
185
|
cachedConfig = undefined;
|
|
303
186
|
const configPath = getConfigPath();
|
|
304
187
|
const dir = path.dirname(configPath);
|
|
305
188
|
fs.mkdirSync(dir, { recursive: true });
|
|
306
|
-
const sanitized = sanitizeConfigForWrite(config);
|
|
307
|
-
// Final validation gate before bytes hit disk. Runs the FULL schema —
|
|
308
|
-
// including the cross-field superRefine guards (removed `feedbackDistillation`
|
|
309
|
-
// process key, `defaultWriteTarget` resolution, writable npm/website sources)
|
|
310
|
-
// and all type/enum/range checks — so an `akm config set` (leaf OR object
|
|
311
|
-
// form) cannot persist a guard-violating or mistyped value. NOTE: unknown
|
|
312
|
-
// keys are intentionally NOT rejected here — object schemas are `.passthrough()`
|
|
313
|
-
// so cross-version skew round-trips (see config-schema.ts header); the lenient
|
|
314
|
-
// tolerance is by design, not an oversight.
|
|
315
|
-
const parseResult = AkmConfigSchema.safeParse(sanitized);
|
|
316
|
-
if (!parseResult.success) {
|
|
317
|
-
const lines = parseResult.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join("\n");
|
|
318
|
-
throw new ConfigError(`Refusing to save invalid config:\n${lines}`, "INVALID_CONFIG_FILE", "Fix the listed fields, or undo the offending `akm config set`. " +
|
|
319
|
-
"If this looks like an akm bug, re-run with --debug to attach the traceback.");
|
|
320
|
-
}
|
|
321
|
-
// WS-3: acquire the config write lock so concurrent `akm config set`
|
|
322
|
-
// invocations do not interleave their backup+atomic-write cycles.
|
|
323
189
|
withConfigLock(() => {
|
|
190
|
+
assertNoPendingMigrationOperation();
|
|
191
|
+
const validated = validateCompleteConfig(config);
|
|
324
192
|
backupExistingConfig(configPath);
|
|
325
|
-
writeConfigAtomic(configPath,
|
|
193
|
+
writeConfigAtomic(configPath, sanitizeConfigForWrite(validated));
|
|
326
194
|
});
|
|
327
195
|
}
|
|
196
|
+
export function validateCompleteConfig(config) {
|
|
197
|
+
const parseResult = AkmConfigSchema.safeParse(config);
|
|
198
|
+
if (parseResult.success)
|
|
199
|
+
return parseResult.data;
|
|
200
|
+
const lines = parseResult.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join("\n");
|
|
201
|
+
throw new ConfigError(`Refusing to save invalid config:\n${lines}`, "INVALID_CONFIG_FILE", "Fix the listed fields, or undo the offending `akm config set`. " +
|
|
202
|
+
"If this looks like an akm bug, re-run with --debug to attach the traceback.");
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Mutate config under one fail-closed lock spanning read, merge, validation,
|
|
206
|
+
* ordinary backup, and atomic write.
|
|
207
|
+
*/
|
|
208
|
+
export function mutateConfig(mutate, options) {
|
|
209
|
+
assertNoPendingMigrationOperation();
|
|
210
|
+
cachedConfig = undefined;
|
|
211
|
+
const configPath = getConfigPath();
|
|
212
|
+
return withConfigLock(() => {
|
|
213
|
+
assertNoPendingMigrationOperation();
|
|
214
|
+
const text = readConfigText(configPath);
|
|
215
|
+
if (text === undefined && options?.absentNoop) {
|
|
216
|
+
return { config: { ...DEFAULT_CONFIG }, written: false };
|
|
217
|
+
}
|
|
218
|
+
const current = text === undefined ? { ...DEFAULT_CONFIG } : parseAndValidateConfigText(text, configPath);
|
|
219
|
+
const mutated = mutate(current);
|
|
220
|
+
if (mutated === current)
|
|
221
|
+
return { config: current, written: false };
|
|
222
|
+
const next = validateCompleteConfig({ ...mutated, configVersion: CURRENT_CONFIG_VERSION });
|
|
223
|
+
if (text !== undefined)
|
|
224
|
+
backupExistingConfig(configPath);
|
|
225
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
226
|
+
writeConfigAtomic(configPath, sanitizeConfigForWrite(next));
|
|
227
|
+
return { config: next, written: true };
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Mutate config while holding the write lock across one validated pre-commit
|
|
232
|
+
* side effect. Setup uses this to reject a three-way conflict before creating
|
|
233
|
+
* its stash, while preventing another config writer from racing the final save.
|
|
234
|
+
*/
|
|
235
|
+
export async function mutateConfigWithPrecommit(mutate, precommit) {
|
|
236
|
+
assertNoPendingMigrationOperation();
|
|
237
|
+
cachedConfig = undefined;
|
|
238
|
+
const configPath = getConfigPath();
|
|
239
|
+
const release = acquireConfigLock();
|
|
240
|
+
try {
|
|
241
|
+
assertNoPendingMigrationOperation();
|
|
242
|
+
const text = readConfigText(configPath);
|
|
243
|
+
const current = text === undefined ? { ...DEFAULT_CONFIG } : parseAndValidateConfigText(text, configPath);
|
|
244
|
+
const mutated = mutate(current);
|
|
245
|
+
const next = validateCompleteConfig({ ...mutated, configVersion: CURRENT_CONFIG_VERSION });
|
|
246
|
+
if (text !== undefined)
|
|
247
|
+
backupExistingConfig(configPath);
|
|
248
|
+
const precommitResult = await precommit(next);
|
|
249
|
+
if (mutated === current)
|
|
250
|
+
return { config: current, written: false, precommit: precommitResult };
|
|
251
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
252
|
+
writeConfigAtomic(configPath, sanitizeConfigForWrite(next));
|
|
253
|
+
return { config: next, written: true, precommit: precommitResult };
|
|
254
|
+
}
|
|
255
|
+
finally {
|
|
256
|
+
release();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
328
259
|
/**
|
|
329
260
|
* Strip literal apiKey fields before writing config to disk.
|
|
330
261
|
* API keys are expected to come from environment variables
|
|
331
|
-
* (AKM_EMBED_API_KEY, AKM_LLM_API_KEY,
|
|
262
|
+
* (AKM_EMBED_API_KEY, AKM_LLM_API_KEY, AKM_ENGINE_<NAME>_API_KEY).
|
|
332
263
|
*
|
|
333
264
|
* `${VAR}` / `$VAR` references are preserved — they are not secrets, they
|
|
334
265
|
* are deferred lookups resolved at consumption by `resolveSecret`. Dropping
|
|
@@ -340,7 +271,7 @@ function saveConfigReal(config) {
|
|
|
340
271
|
* --yes` with an `apiKey` field expected persistence and got a wiped config
|
|
341
272
|
* with no feedback.
|
|
342
273
|
*/
|
|
343
|
-
function sanitizeConfigForWrite(config) {
|
|
274
|
+
export function sanitizeConfigForWrite(config) {
|
|
344
275
|
const sanitized = { ...config };
|
|
345
276
|
const stripped = [];
|
|
346
277
|
if (config.embedding?.apiKey !== undefined) {
|
|
@@ -359,50 +290,36 @@ function sanitizeConfigForWrite(config) {
|
|
|
359
290
|
else if (config.embedding) {
|
|
360
291
|
sanitized.embedding = { ...config.embedding };
|
|
361
292
|
}
|
|
362
|
-
if (config.
|
|
363
|
-
const
|
|
364
|
-
for (const [name,
|
|
365
|
-
if (
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
const { apiKey: _drop, ...rest } = profile;
|
|
371
|
-
llmProfiles[name] = rest;
|
|
372
|
-
if (profile.apiKey) {
|
|
373
|
-
const envVar = `AKM_PROFILE_${name.toUpperCase().replace(/-/g, "_")}_API_KEY`;
|
|
374
|
-
stripped.push(`profiles.llm.${name}.apiKey (set ${envVar} to provide at runtime)`);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
else {
|
|
379
|
-
llmProfiles[name] = { ...profile };
|
|
293
|
+
if (config.engines) {
|
|
294
|
+
const engines = {};
|
|
295
|
+
for (const [name, engine] of Object.entries(config.engines)) {
|
|
296
|
+
if (engine.kind !== "llm" || engine.apiKey === undefined || isEnvReference(engine.apiKey)) {
|
|
297
|
+
engines[name] = { ...engine };
|
|
298
|
+
continue;
|
|
380
299
|
}
|
|
300
|
+
const { apiKey: _drop, ...rest } = engine;
|
|
301
|
+
engines[name] = rest;
|
|
302
|
+
if (engine.apiKey)
|
|
303
|
+
stripped.push(`engines.${name}.apiKey`);
|
|
381
304
|
}
|
|
382
|
-
sanitized.
|
|
383
|
-
...(sanitized.profiles ?? {}),
|
|
384
|
-
llm: llmProfiles,
|
|
385
|
-
};
|
|
305
|
+
sanitized.engines = engines;
|
|
386
306
|
}
|
|
387
307
|
if (stripped.length > 0) {
|
|
388
|
-
warn(`Config sanitizer dropped API key(s) before writing to disk:\n - ${stripped.join("\n - ")}\n\nakm does not persist API keys to config.json. Set the listed environment variables to provide them at runtime, or use \`\${VAR}\` references in your config to defer lookup. See docs/data-and-telemetry.md.`);
|
|
308
|
+
warn(`Config sanitizer dropped API key(s) before writing to disk:\n - ${stripped.join("\n - ")}\n\nakm does not persist API keys to config.json. Set the listed environment variables to provide them at runtime, or use \`\${VAR}\` references in your config to defer lookup. See docs/reference/data-and-telemetry.md.`);
|
|
389
309
|
}
|
|
390
310
|
return sanitized;
|
|
391
311
|
}
|
|
392
|
-
/** Matches
|
|
312
|
+
/** Matches the only 0.9 symbolic secret forms: `${VAR}` or `$VAR`. */
|
|
393
313
|
function isEnvReference(value) {
|
|
394
|
-
return /^\$\{[
|
|
314
|
+
return /^\$\{[A-Za-z_][A-Za-z0-9_]*\}$|^\$[A-Za-z_][A-Za-z0-9_]*$/.test(value);
|
|
395
315
|
}
|
|
396
316
|
export function updateConfig(partial) {
|
|
397
|
-
|
|
398
|
-
const merged = mergeLoadedConfig(current, partial);
|
|
399
|
-
saveConfig(merged);
|
|
400
|
-
return merged;
|
|
317
|
+
return mutateConfig((current) => deepMergeConfig(current, partial)).config;
|
|
401
318
|
}
|
|
402
319
|
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
403
320
|
/**
|
|
404
|
-
* Resolve a single secret value by expanding `${VAR}` / `$VAR`
|
|
405
|
-
*
|
|
321
|
+
* Resolve a single secret value by expanding `${VAR}` / `$VAR` references
|
|
322
|
+
* against `process.env`. Use this at apiKey /
|
|
406
323
|
* authorization-header consumption sites (LLM client, embedder, agent SDK
|
|
407
324
|
* runner) — NOT on the load path. Non-string inputs pass through unchanged.
|
|
408
325
|
*
|
|
@@ -420,26 +337,21 @@ export function resolveSecret(value) {
|
|
|
420
337
|
return value;
|
|
421
338
|
if (!value.includes("$"))
|
|
422
339
|
return value;
|
|
423
|
-
return value.replace(/\$\{([
|
|
424
|
-
|
|
425
|
-
const [name, ...rest] = braced.split(":-");
|
|
426
|
-
const fallback = rest.join(":-");
|
|
427
|
-
return process.env[name] ?? fallback ?? "";
|
|
428
|
-
}
|
|
429
|
-
return process.env[bare] ?? "";
|
|
340
|
+
return value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g, (_match, braced, bare) => {
|
|
341
|
+
return process.env[(braced ?? bare)] ?? "";
|
|
430
342
|
});
|
|
431
343
|
}
|
|
432
344
|
/**
|
|
433
345
|
* Read a per-pass {@link IndexPassConfig} entry from {@link IndexConfig},
|
|
434
346
|
* filtering out the reserved feature-section keys so callers don't mistake
|
|
435
|
-
* `metadataEnhance`
|
|
347
|
+
* `metadataEnhance` for a pass.
|
|
436
348
|
*/
|
|
437
349
|
/**
|
|
438
350
|
* Reserved well-known keys on IndexConfig that are NOT per-pass entries.
|
|
439
|
-
* `
|
|
440
|
-
*
|
|
351
|
+
* `indexBodyOpening` (stash-conventions SPEC-8) is a boolean feature flag, not
|
|
352
|
+
* a pass section.
|
|
441
353
|
*/
|
|
442
|
-
const INDEX_RESERVED_KEYS = new Set(["metadataEnhance", "
|
|
354
|
+
const INDEX_RESERVED_KEYS = new Set(["metadataEnhance", "indexBodyOpening"]);
|
|
443
355
|
export function getIndexPassConfig(config, passName) {
|
|
444
356
|
if (!config)
|
|
445
357
|
return undefined;
|
|
@@ -451,99 +363,10 @@ export function getIndexPassConfig(config, passName) {
|
|
|
451
363
|
return entry;
|
|
452
364
|
}
|
|
453
365
|
// Re-export source runtime helpers — implementation lives in config-sources.ts.
|
|
454
|
-
export { parseSourceSpec, resolveConfiguredSources } from "./config-sources.js";
|
|
366
|
+
export { bundleComponentConfig, bundleEntryToSourceEntry, bundlesToSourceEntries, installedSourceDescriptor, parseSourceSpec, primaryBundlePath, resolveConfiguredSources, } from "./config-sources.js";
|
|
455
367
|
/**
|
|
456
368
|
* Merge a partial user-config override onto a base config. Used by
|
|
457
369
|
* {@link loadUserConfig} (DEFAULT_CONFIG + on-disk) and {@link updateConfig}
|
|
458
370
|
* (current config + partial patch). Sub-objects with named records (profiles,
|
|
459
371
|
* defaults, etc.) shallow-merge; arrays override wholesale.
|
|
460
372
|
*/
|
|
461
|
-
function mergeLoadedConfig(base, override) {
|
|
462
|
-
if (!override)
|
|
463
|
-
return { ...base };
|
|
464
|
-
const merged = { ...base, ...override };
|
|
465
|
-
// Shallow-merge sub-objects so a partial update to e.g. `output.format`
|
|
466
|
-
// doesn't drop the existing `output.detail`.
|
|
467
|
-
for (const key of ["output", "embedding", "index", "defaults"]) {
|
|
468
|
-
if (base[key] && override[key]) {
|
|
469
|
-
// biome-ignore lint/suspicious/noExplicitAny: heterogeneous structural merge
|
|
470
|
-
merged[key] = { ...base[key], ...override[key] };
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
if (base.profiles && override.profiles) {
|
|
474
|
-
const next = { ...base.profiles };
|
|
475
|
-
for (const k of ["llm", "agent", "improve"]) {
|
|
476
|
-
const ovr = override.profiles[k];
|
|
477
|
-
if (ovr)
|
|
478
|
-
next[k] = { ...(next[k] ?? {}), ...ovr };
|
|
479
|
-
}
|
|
480
|
-
merged.profiles = next;
|
|
481
|
-
}
|
|
482
|
-
return merged;
|
|
483
|
-
}
|
|
484
|
-
function applyRuntimeEnvApiKeys(config) {
|
|
485
|
-
const next = { ...config };
|
|
486
|
-
if (next.embedding && !next.embedding.apiKey) {
|
|
487
|
-
const envKey = process.env.AKM_EMBED_API_KEY?.trim();
|
|
488
|
-
if (envKey)
|
|
489
|
-
next.embedding = { ...next.embedding, apiKey: envKey };
|
|
490
|
-
}
|
|
491
|
-
// LLM profile keys: AKM_LLM_API_KEY for the default profile, then
|
|
492
|
-
// AKM_PROFILE_<UPPER>_API_KEY for any profile (per-profile wins).
|
|
493
|
-
// Resolve the default profile the SAME way the rest of the config layer does
|
|
494
|
-
// (resolveDefaultLlmProfileName), so the implicit `profiles.llm.default`
|
|
495
|
-
// fallback is honored. Keying off the raw `defaults.llm` field alone silently
|
|
496
|
-
// dropped AKM_LLM_API_KEY for configs that rely on the implicit default —
|
|
497
|
-
// the same no-op-run class as the 2026-05-23 incident.
|
|
498
|
-
const defaultProfile = resolveDefaultLlmProfileName(next);
|
|
499
|
-
if (next.profiles?.llm) {
|
|
500
|
-
const updated = { ...next.profiles.llm };
|
|
501
|
-
let changed = false;
|
|
502
|
-
for (const [name, profile] of Object.entries(updated)) {
|
|
503
|
-
if (profile.apiKey)
|
|
504
|
-
continue;
|
|
505
|
-
const perProfile = process.env[`AKM_PROFILE_${name.toUpperCase().replace(/-/g, "_")}_API_KEY`]?.trim();
|
|
506
|
-
const fallback = name === defaultProfile ? process.env.AKM_LLM_API_KEY?.trim() : undefined;
|
|
507
|
-
const envKey = perProfile || fallback;
|
|
508
|
-
if (envKey) {
|
|
509
|
-
updated[name] = { ...profile, apiKey: envKey };
|
|
510
|
-
changed = true;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
if (changed)
|
|
514
|
-
next.profiles = { ...next.profiles, llm: updated };
|
|
515
|
-
}
|
|
516
|
-
return next;
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Walk cwd-ancestors looking for `.akm/config.json`. If one is found, emit a
|
|
520
|
-
* one-time deprecation warning per path. The file's contents are NOT read —
|
|
521
|
-
* multi-layer project config was removed in this release; the warning stays
|
|
522
|
-
* for one cycle so users notice they have a now-dead file on disk and can
|
|
523
|
-
* migrate its settings to the user-level config.
|
|
524
|
-
*/
|
|
525
|
-
const PROJECT_CONFIG_DEPRECATION_WARNED = new Set();
|
|
526
|
-
function warnIfProjectConfigPresent(startDir) {
|
|
527
|
-
let currentDir = path.resolve(startDir);
|
|
528
|
-
while (true) {
|
|
529
|
-
const configPath = path.join(currentDir, PROJECT_CONFIG_RELATIVE_PATH);
|
|
530
|
-
if (isFile(configPath) && !PROJECT_CONFIG_DEPRECATION_WARNED.has(configPath)) {
|
|
531
|
-
PROJECT_CONFIG_DEPRECATION_WARNED.add(configPath);
|
|
532
|
-
warn(`[akm] DEPRECATED: project-level config file found at ${configPath}. ` +
|
|
533
|
-
"Project-level config files are no longer merged (removed after 0.8.x deprecation). " +
|
|
534
|
-
"Move any needed settings to ~/.config/akm/config.json; this file is ignored.");
|
|
535
|
-
}
|
|
536
|
-
const parentDir = path.dirname(currentDir);
|
|
537
|
-
if (parentDir === currentDir)
|
|
538
|
-
break;
|
|
539
|
-
currentDir = parentDir;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
function isFile(filePath) {
|
|
543
|
-
try {
|
|
544
|
-
return fs.statSync(filePath).isFile();
|
|
545
|
-
}
|
|
546
|
-
catch {
|
|
547
|
-
return false;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
const UNSAFE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
5
|
+
export function isPlainObject(value) {
|
|
6
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
7
|
+
return false;
|
|
8
|
+
const prototype = Object.getPrototypeOf(value);
|
|
9
|
+
return prototype === Object.prototype || prototype === null;
|
|
10
|
+
}
|
|
11
|
+
function copyConfigValue(value) {
|
|
12
|
+
if (Array.isArray(value))
|
|
13
|
+
return value.map(copyConfigValue);
|
|
14
|
+
if (!isPlainObject(value))
|
|
15
|
+
return value;
|
|
16
|
+
const copy = {};
|
|
17
|
+
for (const key of Object.keys(value)) {
|
|
18
|
+
if (UNSAFE_KEYS.has(key))
|
|
19
|
+
throw new TypeError(`Unsafe configuration key: ${key}`);
|
|
20
|
+
copy[key] = copyConfigValue(value[key]);
|
|
21
|
+
}
|
|
22
|
+
return copy;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Merge configuration values without mutating either input. Plain objects merge
|
|
26
|
+
* recursively; arrays and scalar values replace the less-specific value.
|
|
27
|
+
*/
|
|
28
|
+
export function deepMergeConfig(base, override) {
|
|
29
|
+
const result = copyConfigValue(base);
|
|
30
|
+
for (const key of Object.keys(override)) {
|
|
31
|
+
if (UNSAFE_KEYS.has(key))
|
|
32
|
+
throw new TypeError(`Unsafe configuration key: ${key}`);
|
|
33
|
+
const next = override[key];
|
|
34
|
+
if (next === undefined)
|
|
35
|
+
continue;
|
|
36
|
+
const current = result[key];
|
|
37
|
+
result[key] =
|
|
38
|
+
isPlainObject(current) && isPlainObject(next) ? deepMergeConfig(current, next) : copyConfigValue(next);
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|