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
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { defineJsonCommand, output } from "../cli/shared.js";
|
|
7
|
-
import { DEFAULT_CONFIG, loadUserConfig, saveConfig } from "../core/config/config.js";
|
|
4
|
+
import { defineGroupCommand, defineJsonCommand, output } from "../cli/shared.js";
|
|
5
|
+
import { getEffectiveRegistries, loadUserConfig, mutateConfig } from "../core/config/config.js";
|
|
8
6
|
import { UsageError } from "../core/errors.js";
|
|
9
7
|
import { warn } from "../core/warn.js";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export const registryCommand = defineCommand({
|
|
13
|
-
meta: { name: "registry", description: "Manage stash registries" },
|
|
8
|
+
export const registryCommand = defineGroupCommand({
|
|
9
|
+
meta: { name: "registry", description: "Manage bundle registries" },
|
|
14
10
|
subCommands: {
|
|
15
11
|
list: defineJsonCommand({
|
|
16
12
|
meta: { name: "list", description: "List configured registries" },
|
|
17
13
|
async run() {
|
|
18
14
|
const config = loadUserConfig();
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
// R-066 #5: mirror the shared config↔default-fallback helper instead
|
|
16
|
+
// of re-deriving it inline.
|
|
17
|
+
output("registry-list", { registries: getEffectiveRegistries(config) });
|
|
21
18
|
},
|
|
22
19
|
}),
|
|
23
20
|
add: defineJsonCommand({
|
|
@@ -45,13 +42,6 @@ export const registryCommand = defineCommand({
|
|
|
45
42
|
}
|
|
46
43
|
warn("Warning: registry URL uses plain HTTP (not HTTPS). --allow-insecure was set; an on-path attacker could substitute a malicious index.");
|
|
47
44
|
}
|
|
48
|
-
const config = loadUserConfig();
|
|
49
|
-
const registries = [...(config.registries ?? [])];
|
|
50
|
-
// Deduplicate by URL
|
|
51
|
-
if (registries.some((r) => r.url === args.url)) {
|
|
52
|
-
output("registry-add", { registries, added: false, message: "Registry URL already configured" });
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
45
|
const entry = { url: args.url };
|
|
56
46
|
if (args.name)
|
|
57
47
|
entry.name = args.name;
|
|
@@ -65,9 +55,20 @@ export const registryCommand = defineCommand({
|
|
|
65
55
|
throw new UsageError("--options must be valid JSON");
|
|
66
56
|
}
|
|
67
57
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
58
|
+
let added = false;
|
|
59
|
+
const updated = mutateConfig((config) => {
|
|
60
|
+
const registries = [...(config.registries ?? [])];
|
|
61
|
+
if (registries.some((registry) => registry.url === args.url))
|
|
62
|
+
return config;
|
|
63
|
+
registries.push(entry);
|
|
64
|
+
added = true;
|
|
65
|
+
return { ...config, registries };
|
|
66
|
+
}).config;
|
|
67
|
+
output("registry-add", {
|
|
68
|
+
registries: updated.registries ?? [],
|
|
69
|
+
added,
|
|
70
|
+
...(!added ? { message: "Registry URL already configured" } : {}),
|
|
71
|
+
});
|
|
71
72
|
},
|
|
72
73
|
}),
|
|
73
74
|
remove: defineJsonCommand({
|
|
@@ -92,46 +93,19 @@ export const registryCommand = defineCommand({
|
|
|
92
93
|
process.stderr.write("Aborted.\n");
|
|
93
94
|
return;
|
|
94
95
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const limitRaw = parsePositiveIntFlag(args.limit ?? undefined);
|
|
109
|
-
const result = await searchRegistry(args.query, { limit: limitRaw, includeAssets: args.assets });
|
|
110
|
-
output("registry-search", result);
|
|
111
|
-
},
|
|
112
|
-
}),
|
|
113
|
-
"build-index": defineJsonCommand({
|
|
114
|
-
meta: { name: "build-index", description: "Build a v2 registry index from discovery and manual entries" },
|
|
115
|
-
args: {
|
|
116
|
-
out: { type: "string", description: "Output path for the generated index" },
|
|
117
|
-
manual: { type: "string", description: "Manual entries JSON file" },
|
|
118
|
-
"npm-registry": { type: "string", description: "Override npm registry base URL" },
|
|
119
|
-
"github-api": { type: "string", description: "Override GitHub API base URL" },
|
|
120
|
-
},
|
|
121
|
-
async run({ args }) {
|
|
122
|
-
const result = await buildRegistryIndex({
|
|
123
|
-
manualEntriesPath: args.manual,
|
|
124
|
-
npmRegistryBase: args["npm-registry"],
|
|
125
|
-
githubApiBase: args["github-api"],
|
|
126
|
-
});
|
|
127
|
-
const outPath = writeRegistryIndex(result.index, args.out);
|
|
128
|
-
output("registry-build-index", {
|
|
129
|
-
outPath,
|
|
130
|
-
version: result.index.version,
|
|
131
|
-
updatedAt: result.index.updatedAt,
|
|
132
|
-
totalKits: result.counts.total,
|
|
133
|
-
counts: result.counts,
|
|
134
|
-
manualEntriesPath: result.paths.manualEntriesPath,
|
|
96
|
+
let removed;
|
|
97
|
+
const updated = mutateConfig((latest) => {
|
|
98
|
+
const current = [...(latest.registries ?? [])];
|
|
99
|
+
const currentIndex = current.findIndex((registry) => registry.url === args.target || registry.name === args.target);
|
|
100
|
+
if (currentIndex < 0)
|
|
101
|
+
return latest;
|
|
102
|
+
removed = current.splice(currentIndex, 1)[0];
|
|
103
|
+
return { ...latest, registries: current };
|
|
104
|
+
}).config;
|
|
105
|
+
output("registry-remove", {
|
|
106
|
+
registries: updated.registries ?? [],
|
|
107
|
+
removed: removed !== undefined,
|
|
108
|
+
...(removed ? { entry: removed } : { message: "No matching registry found" }),
|
|
135
109
|
});
|
|
136
110
|
},
|
|
137
111
|
}),
|
|
@@ -10,12 +10,13 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { serializeFrontmatter } from "../core/asset/asset-serialize.js";
|
|
12
12
|
import { toErrorMessage, tryReadStdinText } from "../core/common.js";
|
|
13
|
-
import {
|
|
13
|
+
import { loadConfig } from "../core/config/config.js";
|
|
14
14
|
import { UsageError } from "../core/errors.js";
|
|
15
|
+
import { parseEmbeddedJsonResponse } from "../core/parse.js";
|
|
15
16
|
import { DURATION_UNITS, parseDuration as parseDurationSpec } from "../core/time.js";
|
|
16
17
|
import { warn } from "../core/warn.js";
|
|
17
18
|
import { SCOPE_KEYS } from "../indexer/passes/metadata.js";
|
|
18
|
-
import {
|
|
19
|
+
import { getDefaultLlmConfig } from "../integrations/agent/engine-resolution.js";
|
|
19
20
|
/**
|
|
20
21
|
* Parse a shorthand duration string to a number of milliseconds.
|
|
21
22
|
* Supports the CLI-wide canonical grammar: `30d` (days), `12h` (hours),
|
|
@@ -50,6 +51,8 @@ export function buildMemoryFrontmatter(fields) {
|
|
|
50
51
|
obj.tags = fields.tags;
|
|
51
52
|
if (fields.source?.trim())
|
|
52
53
|
obj.source = fields.source;
|
|
54
|
+
if (fields.xrefs && fields.xrefs.length > 0)
|
|
55
|
+
obj.xrefs = fields.xrefs;
|
|
53
56
|
if (fields.observed_at?.trim())
|
|
54
57
|
obj.observed_at = fields.observed_at;
|
|
55
58
|
if (fields.expires?.trim())
|
|
@@ -147,7 +150,7 @@ export async function runLlmEnrich(body) {
|
|
|
147
150
|
warn("Warning: --enrich requires an LLM to be configured. Run `akm setup` to configure one.");
|
|
148
151
|
return { tags: [] };
|
|
149
152
|
}
|
|
150
|
-
const { chatCompletion
|
|
153
|
+
const { chatCompletion } = await import("../llm/client.js");
|
|
151
154
|
// #576: attribute this entry point's LLM call to the `remember` stage. The
|
|
152
155
|
// wrapper is ambient — if a usage sink is active it tags the record; if not,
|
|
153
156
|
// it is a no-op.
|
|
@@ -182,7 +185,7 @@ Return ONLY the JSON object, no prose, no markdown fences.`;
|
|
|
182
185
|
}
|
|
183
186
|
}
|
|
184
187
|
})();
|
|
185
|
-
const parsed =
|
|
188
|
+
const parsed = parseEmbeddedJsonResponse(result);
|
|
186
189
|
if (!parsed) {
|
|
187
190
|
warn("Warning: --enrich received invalid JSON from the LLM. Writing memory without enrichment.");
|
|
188
191
|
return { tags: [] };
|
|
@@ -201,56 +204,14 @@ Return ONLY the JSON object, no prose, no markdown fences.`;
|
|
|
201
204
|
return { tags: [] };
|
|
202
205
|
}
|
|
203
206
|
}
|
|
204
|
-
//
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
return undefined;
|
|
216
|
-
const parsedFormat = parseFlagValue(process.argv, "--format");
|
|
217
|
-
if (parsedFormat !== undefined &&
|
|
218
|
-
content === parsedFormat &&
|
|
219
|
-
wasRememberFlagValueConsumedAsContent(content, parsedFormat, "--format")) {
|
|
220
|
-
return undefined;
|
|
221
|
-
}
|
|
222
|
-
const parsedDetail = parseFlagValue(process.argv, "--detail");
|
|
223
|
-
if (parsedDetail !== undefined &&
|
|
224
|
-
content === parsedDetail &&
|
|
225
|
-
wasRememberFlagValueConsumedAsContent(content, parsedDetail, "--detail")) {
|
|
226
|
-
return undefined;
|
|
227
|
-
}
|
|
228
|
-
return content;
|
|
229
|
-
}
|
|
230
|
-
function wasRememberFlagValueConsumedAsContent(content, flagValue, flagName) {
|
|
231
|
-
const argv = process.argv.slice(2);
|
|
232
|
-
const rememberIndex = argv.indexOf("remember");
|
|
233
|
-
const tokens = rememberIndex >= 0 ? argv.slice(rememberIndex + 1) : argv;
|
|
234
|
-
let flagIndex = -1;
|
|
235
|
-
let flagConsumesNextToken = false;
|
|
236
|
-
for (let i = 0; i < tokens.length; i += 1) {
|
|
237
|
-
const token = tokens[i];
|
|
238
|
-
if (token === flagName) {
|
|
239
|
-
flagIndex = i;
|
|
240
|
-
flagConsumesNextToken = true;
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
if (token === `${flagName}=${flagValue}`) {
|
|
244
|
-
flagIndex = i;
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
if (flagIndex === -1)
|
|
249
|
-
return false;
|
|
250
|
-
if (tokens.slice(0, flagIndex).includes(content))
|
|
251
|
-
return false;
|
|
252
|
-
const firstTokenAfterFlag = flagIndex + (flagConsumesNextToken ? 2 : 1);
|
|
253
|
-
if (tokens.slice(firstTokenAfterFlag).includes(content))
|
|
254
|
-
return false;
|
|
255
|
-
return true;
|
|
256
|
-
}
|
|
207
|
+
// R-061(c): `resolveRememberContentArg` / `wasRememberFlagValueConsumedAsContent`
|
|
208
|
+
// used to live here — a heuristic guarding against citty consuming a global
|
|
209
|
+
// flag's value (`--format`/`--detail`) as the `content` positional. That guard
|
|
210
|
+
// predated `rememberCommand` declaring `GLOBAL_OUTPUT_ARGS` (via
|
|
211
|
+
// `defineJsonCommand`): once the leaf command itself declares `format`/
|
|
212
|
+
// `detail` args, citty's parser consumes their space-separated values as the
|
|
213
|
+
// flag's own value and never assigns them to `content` in the first place, so
|
|
214
|
+
// the heuristic no longer has anything to guard against. Verified: `akm
|
|
215
|
+
// remember "yaml" --format yaml` and `akm remember "brief" --detail brief`
|
|
216
|
+
// both write the literal content unchanged. Deleted rather than kept as
|
|
217
|
+
// defense-in-depth per the cleanup program's dead-code policy.
|
|
@@ -5,13 +5,14 @@ import fs from "node:fs";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import * as p from "../../cli/clack.js";
|
|
7
7
|
import { defineJsonCommand, output } from "../../cli/shared.js";
|
|
8
|
+
import { decideDangerousKeyInstall } from "../../core/activation-policy.js";
|
|
8
9
|
import { UsageError } from "../../core/errors.js";
|
|
9
10
|
import { appendEvent } from "../../core/events.js";
|
|
10
11
|
import { warn } from "../../core/warn.js";
|
|
11
12
|
import { akmRemove } from "./installed-stashes.js";
|
|
12
13
|
import { akmAdd } from "./source-add.js";
|
|
13
14
|
import { addStash } from "./source-manage.js";
|
|
14
|
-
// ── Shared website-options helper
|
|
15
|
+
// ── Shared website-options helper ──────────
|
|
15
16
|
export function buildWebsiteOptions(args) {
|
|
16
17
|
const websiteOptions = {};
|
|
17
18
|
if (typeof args["max-pages"] === "string" && args["max-pages"].length > 0)
|
|
@@ -37,24 +38,84 @@ export function shouldWarnOnPlainHttp(ref) {
|
|
|
37
38
|
return true;
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Recursively enumerate every real env FILE under `rootDir` (a stash's
|
|
43
|
+
* `env/` directory). "Real env file" is the SAME test used everywhere else
|
|
44
|
+
* in akm decides what `akm env run` / `akm env list` / the indexer will
|
|
45
|
+
* actually load as environment variables — `fileName === ".env" ||
|
|
46
|
+
* fileName.endsWith(".env")` — see `src/indexer/walk/matchers.ts` and
|
|
47
|
+
* `listEnvsRecursive` in `src/commands/env/env-cli.ts`. Reusing that exact
|
|
48
|
+
* rule here (rather than inventing a second, possibly-divergent one) is what
|
|
49
|
+
* closes the nested-directory bypass: `env/nested/inner.env` IS loaded by
|
|
50
|
+
* `akm env run` today via that same recursive walk, so it must be scanned
|
|
51
|
+
* too (previously only a flat, non-recursive `env/*.env` listing was
|
|
52
|
+
* scanned).
|
|
53
|
+
*
|
|
54
|
+
* Deliberately excludes files that do NOT end in `.env` (e.g.
|
|
55
|
+
* `env/notes.txt`). Such a file is never sourced as environment variables by
|
|
56
|
+
* any akm codepath, so a dangerous key sitting in its contents cannot hijack
|
|
57
|
+
* process execution via `akm env run` — there is no live attack through this
|
|
58
|
+
* gate for it. Residual gap: this scanner does not protect against an
|
|
59
|
+
* operator later renaming/copying that file to a `*.env` name, or feeding it
|
|
60
|
+
* into `akm env run` through some other mechanism outside akm; closing that
|
|
61
|
+
* would mean content-sniffing every byte of every file in the stash (README,
|
|
62
|
+
* lockfiles, binaries, …) for a vector that requires a subsequent human
|
|
63
|
+
* action to become live, which is a materially different and much more
|
|
64
|
+
* expensive check than "is this a file `akm` will actually source".
|
|
65
|
+
*/
|
|
66
|
+
function collectEnvFilePathsRecursive(rootDir) {
|
|
67
|
+
const results = [];
|
|
68
|
+
const walk = (dir) => {
|
|
69
|
+
let entries;
|
|
70
|
+
try {
|
|
71
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
for (const entry of entries) {
|
|
77
|
+
const full = path.join(dir, entry.name);
|
|
78
|
+
if (entry.isDirectory()) {
|
|
79
|
+
walk(full);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (!entry.isFile())
|
|
83
|
+
continue;
|
|
84
|
+
if (entry.name !== ".env" && !entry.name.endsWith(".env"))
|
|
85
|
+
continue;
|
|
86
|
+
results.push(full);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
walk(rootDir);
|
|
90
|
+
return results;
|
|
91
|
+
}
|
|
92
|
+
/** Scan every real env file (recursively, see {@link collectEnvFilePathsRecursive}) in the freshly-installed stash for dangerous env keys. */
|
|
41
93
|
function collectDangerousKeyFindings(installedStashRoot, checkEnvForDangerousKeys) {
|
|
42
94
|
const allFindings = [];
|
|
43
95
|
const subdir = "env";
|
|
44
96
|
const prefix = "env";
|
|
45
97
|
const dir = path.join(installedStashRoot, subdir);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
98
|
+
if (!fs.existsSync(dir))
|
|
99
|
+
return allFindings;
|
|
100
|
+
for (const envPath of collectEnvFilePathsRecursive(dir)) {
|
|
101
|
+
const relToEnvDir = path.relative(dir, envPath);
|
|
102
|
+
// Only the LAST path segment carries the ".env" suffix / dotfile-default
|
|
103
|
+
// naming rule; intermediate directory segments pass through unchanged.
|
|
104
|
+
// e.g. "nested/inner.env" -> "nested/inner", "nested/.env" ->
|
|
105
|
+
// "nested/default" (not "nested/", which is what naively stripping the
|
|
106
|
+
// suffix from the whole relative path would produce).
|
|
107
|
+
const segments = relToEnvDir.split(path.sep);
|
|
108
|
+
const lastSegment = segments[segments.length - 1] ?? "";
|
|
109
|
+
const lastSegmentBase = lastSegment.endsWith(".env") ? lastSegment.slice(0, -".env".length) : lastSegment;
|
|
110
|
+
const refSegments = [...segments.slice(0, -1), lastSegmentBase === "" ? "default" : lastSegmentBase];
|
|
111
|
+
const envRef = `${prefix}/${refSegments.join("/")}`;
|
|
112
|
+
const relPath = path.join(subdir, relToEnvDir);
|
|
113
|
+
const findings = checkEnvForDangerousKeys(envPath, relPath, envRef);
|
|
53
114
|
for (const finding of findings) {
|
|
54
115
|
// Extract the key name from the detail string for the summary line.
|
|
55
116
|
const keyMatch = finding.detail.match(/Env key `([^`]+)`/);
|
|
56
117
|
const keyName = keyMatch ? keyMatch[1] : finding.file;
|
|
57
|
-
allFindings.push({
|
|
118
|
+
allFindings.push({ envRef, keyName, relPath });
|
|
58
119
|
}
|
|
59
120
|
}
|
|
60
121
|
return allFindings;
|
|
@@ -79,12 +140,18 @@ export async function auditInstalledStashForDangerousKeys(opts) {
|
|
|
79
140
|
catch {
|
|
80
141
|
return { blocked: false };
|
|
81
142
|
}
|
|
82
|
-
|
|
143
|
+
// The workspace activation policy fixes the baseline stance; the interactive
|
|
144
|
+
// confirm / rollback below is layered on top of the `"gate"` stance only.
|
|
145
|
+
const stance = decideDangerousKeyInstall({
|
|
146
|
+
findingsPresent: allFindings.length > 0,
|
|
147
|
+
allowInsecure: allowDangerousKeys,
|
|
148
|
+
});
|
|
149
|
+
if (stance === "allow")
|
|
83
150
|
return { blocked: false };
|
|
84
|
-
if (
|
|
151
|
+
if (stance === "warn-allow") {
|
|
85
152
|
// Operator has explicitly accepted the risk — warn and continue.
|
|
86
153
|
for (const f of allFindings) {
|
|
87
|
-
warn(`[dangerous-
|
|
154
|
+
warn(`[dangerous-env-key] ${f.relPath}: key \`${f.keyName}\` in ${f.envRef} can hijack process execution via \`akm env run\`. Proceeding because --allow-insecure was set.`);
|
|
88
155
|
}
|
|
89
156
|
return { blocked: false };
|
|
90
157
|
}
|
|
@@ -98,7 +165,7 @@ export async function auditInstalledStashForDangerousKeys(opts) {
|
|
|
98
165
|
}
|
|
99
166
|
catch (_rollbackErr) {
|
|
100
167
|
return (`Rollback failed — stash may still be installed at ${installedStashRoot}. ` +
|
|
101
|
-
`Remove it manually with: akm remove ${rollbackTarget}`);
|
|
168
|
+
`Remove it manually with: akm bundle remove ${rollbackTarget}`);
|
|
102
169
|
}
|
|
103
170
|
}
|
|
104
171
|
if (isTTY) {
|
|
@@ -106,14 +173,14 @@ export async function auditInstalledStashForDangerousKeys(opts) {
|
|
|
106
173
|
// Guard on stdin (not stdout) because p.confirm() reads from stdin;
|
|
107
174
|
// stdout may be a TTY while stdin is piped, which would cause a hang.
|
|
108
175
|
const stashLabel = ref;
|
|
109
|
-
const
|
|
176
|
+
const groupedByEnv = new Map();
|
|
110
177
|
for (const f of allFindings) {
|
|
111
|
-
const existing =
|
|
178
|
+
const existing = groupedByEnv.get(f.envRef) ?? [];
|
|
112
179
|
existing.push(f.keyName);
|
|
113
|
-
|
|
180
|
+
groupedByEnv.set(f.envRef, existing);
|
|
114
181
|
}
|
|
115
|
-
for (const [
|
|
116
|
-
warn(`[warn] Env "${
|
|
182
|
+
for (const [envRef, keys] of groupedByEnv) {
|
|
183
|
+
warn(`[warn] Env "${envRef}" in stash "${stashLabel}" contains potentially dangerous keys:`);
|
|
117
184
|
for (const key of keys) {
|
|
118
185
|
warn(` - ${key}: can hijack process execution via \`akm env run\``);
|
|
119
186
|
}
|
|
@@ -127,7 +194,7 @@ export async function auditInstalledStashForDangerousKeys(opts) {
|
|
|
127
194
|
console.error(JSON.stringify({
|
|
128
195
|
ok: false,
|
|
129
196
|
error: "Install aborted: stash contains dangerous env keys. Remove the keys or re-run with --allow-insecure to bypass.",
|
|
130
|
-
code: "
|
|
197
|
+
code: "DANGEROUS_ENV_KEY",
|
|
131
198
|
...(rollbackWarning ? { rollbackWarning } : {}),
|
|
132
199
|
}, null, 2));
|
|
133
200
|
return { blocked: true, exitCode: 1 };
|
|
@@ -137,11 +204,11 @@ export async function auditInstalledStashForDangerousKeys(opts) {
|
|
|
137
204
|
}
|
|
138
205
|
// Non-interactive path without bypass flag: fail hard.
|
|
139
206
|
const rollbackWarning = await rollback();
|
|
140
|
-
const keyList = allFindings.map((f) => ` - ${f.keyName} (${f.
|
|
207
|
+
const keyList = allFindings.map((f) => ` - ${f.keyName} (${f.envRef})`).join("\n");
|
|
141
208
|
console.error(JSON.stringify({
|
|
142
209
|
ok: false,
|
|
143
210
|
error: `Install blocked: stash "${ref}" contains dangerous env keys that can hijack process execution via \`akm env run\`:\n${keyList}\nRe-run with --allow-insecure to bypass this check after reviewing the env file.`,
|
|
144
|
-
code: "
|
|
211
|
+
code: "DANGEROUS_ENV_KEY",
|
|
145
212
|
...(rollbackWarning ? { rollbackWarning } : {}),
|
|
146
213
|
}, null, 2));
|
|
147
214
|
return { blocked: true, exitCode: 1 };
|
|
@@ -163,18 +230,14 @@ export const addCommand = defineJsonCommand({
|
|
|
163
230
|
name: { type: "string", description: "Human-friendly name for the source" },
|
|
164
231
|
writable: {
|
|
165
232
|
type: "boolean",
|
|
166
|
-
description: "Mark a git
|
|
233
|
+
description: "Mark a git bundle as writable so changes can be pushed back",
|
|
167
234
|
default: false,
|
|
168
235
|
},
|
|
169
|
-
type: {
|
|
170
|
-
type: "string",
|
|
171
|
-
description: "Override asset type for all files in this stash (currently supports: wiki)",
|
|
172
|
-
},
|
|
173
236
|
"max-pages": { type: "string", description: "Maximum pages to crawl for website sources (default: 50)" },
|
|
174
237
|
"max-depth": { type: "string", description: "Maximum crawl depth for website sources (default: 3)" },
|
|
175
238
|
"allow-insecure": {
|
|
176
239
|
type: "boolean",
|
|
177
|
-
description: "Allow a plain HTTP source URL and skip confirmation for dangerous env keys (e.g. LD_PRELOAD, PATH). Use only after explicitly reviewing the
|
|
240
|
+
description: "Allow a plain HTTP source URL and skip confirmation for dangerous env keys (e.g. LD_PRELOAD, PATH). Use only after explicitly reviewing the bundle.",
|
|
178
241
|
default: false,
|
|
179
242
|
},
|
|
180
243
|
},
|
|
@@ -182,7 +245,9 @@ export const addCommand = defineJsonCommand({
|
|
|
182
245
|
const ref = args.ref.trim();
|
|
183
246
|
const allowInsecure = args["allow-insecure"];
|
|
184
247
|
const allowDangerousKeys = allowInsecure;
|
|
185
|
-
//
|
|
248
|
+
// --provider → declarative bundle source (URL for git/website; bare
|
|
249
|
+
// package spec for npm — R-013). Config-only write; content is not
|
|
250
|
+
// synced until a later `akm update`.
|
|
186
251
|
if (args.provider) {
|
|
187
252
|
if (shouldWarnOnPlainHttp(ref)) {
|
|
188
253
|
if (!allowInsecure) {
|
|
@@ -228,25 +293,9 @@ export const addCommand = defineJsonCommand({
|
|
|
228
293
|
warn("Warning: source URL uses plain HTTP (not HTTPS). --allow-insecure was set; an on-path attacker could substitute a malicious payload.");
|
|
229
294
|
}
|
|
230
295
|
const websiteOptions = buildWebsiteOptions(args);
|
|
231
|
-
if (args.type === "wiki") {
|
|
232
|
-
const { registerWikiSource } = await import("./source-add.js");
|
|
233
|
-
const result = await registerWikiSource({
|
|
234
|
-
ref,
|
|
235
|
-
name: args.name,
|
|
236
|
-
options: Object.keys(websiteOptions).length > 0 ? websiteOptions : undefined,
|
|
237
|
-
writable: args.writable,
|
|
238
|
-
});
|
|
239
|
-
appendEvent({
|
|
240
|
-
eventType: "add",
|
|
241
|
-
metadata: { target: ref, type: "wiki", name: args.name ?? null, writable: args.writable === true },
|
|
242
|
-
});
|
|
243
|
-
output("add", result);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
296
|
const result = await akmAdd({
|
|
247
297
|
ref,
|
|
248
298
|
name: args.name,
|
|
249
|
-
overrideType: args.type,
|
|
250
299
|
options: Object.keys(websiteOptions).length > 0 ? websiteOptions : undefined,
|
|
251
300
|
writable: args.writable,
|
|
252
301
|
});
|
|
@@ -255,7 +304,6 @@ export const addCommand = defineJsonCommand({
|
|
|
255
304
|
metadata: {
|
|
256
305
|
target: ref,
|
|
257
306
|
name: args.name ?? null,
|
|
258
|
-
overrideType: args.type ?? null,
|
|
259
307
|
writable: args.writable === true,
|
|
260
308
|
},
|
|
261
309
|
});
|
|
@@ -271,8 +319,14 @@ export const addCommand = defineJsonCommand({
|
|
|
271
319
|
// Use the canonical installed id (most reliably resolved by akmRemove) rather
|
|
272
320
|
// than the raw user-supplied ref which may not match after URL normalisation.
|
|
273
321
|
const rollbackTarget = result.installed?.id ?? result.sourceAdded?.stashRoot ?? ref;
|
|
274
|
-
// The audit RETURNS its decision; we decide
|
|
275
|
-
// any catch, so the abort cannot be lost to a swallowed
|
|
322
|
+
// The audit RETURNS its decision; we decide the exit outcome here,
|
|
323
|
+
// OUTSIDE any catch, so the abort cannot be lost to a swallowed
|
|
324
|
+
// exception (C3). F4: `process.exitCode = …; return;` instead of
|
|
325
|
+
// `process.exit(...)` — the DANGEROUS_ENV_KEY error envelope has
|
|
326
|
+
// already been written to stderr by the audit itself (or is about to
|
|
327
|
+
// be), so an explicit `return` here (skipping the success `output("add",
|
|
328
|
+
// …)` below) is load-bearing, not merely cosmetic: it is what stops a
|
|
329
|
+
// blocked install from ALSO printing a success envelope.
|
|
276
330
|
const decision = await auditInstalledStashForDangerousKeys({
|
|
277
331
|
installedStashRoot,
|
|
278
332
|
ref,
|
|
@@ -281,7 +335,8 @@ export const addCommand = defineJsonCommand({
|
|
|
281
335
|
isTTY: process.stdin.isTTY === true,
|
|
282
336
|
});
|
|
283
337
|
if (decision.blocked) {
|
|
284
|
-
process.
|
|
338
|
+
process.exitCode = decision.exitCode;
|
|
339
|
+
return;
|
|
285
340
|
}
|
|
286
341
|
}
|
|
287
342
|
output("add", result);
|