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,91 +4,199 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* Source operations: list, remove, update.
|
|
6
6
|
*
|
|
7
|
-
* Provides unified operations across all
|
|
8
|
-
* The CLI's `akm list`, `akm remove`, and `akm update` commands are wired here.
|
|
7
|
+
* Provides unified operations across all configured bundle source providers.
|
|
8
|
+
* The CLI's `akm bundle list`, `akm bundle remove`, and `akm bundle update` commands are wired here.
|
|
9
|
+
*
|
|
10
|
+
* 0.9.0 (spec §10.1/§10.2): the retired `installed[]` array is gone — a
|
|
11
|
+
* registry-managed source is now a `bundles.<slug>` entry (the desired locator)
|
|
12
|
+
* paired with a lock entry (the resolved `localRoot`/version). A bundle that has
|
|
13
|
+
* a lock entry is "managed" (installed from a registry and overwritten on
|
|
14
|
+
* `akm bundle update`); a bundle with no lock is a plain filesystem/git/website source.
|
|
9
15
|
*/
|
|
10
16
|
import fs from "node:fs";
|
|
11
17
|
import path from "node:path";
|
|
12
18
|
import { isWithin, resolveStashDir } from "../../core/common.js";
|
|
13
19
|
import { getSources, loadConfig } from "../../core/config/config.js";
|
|
14
|
-
import { NotFoundError, UsageError } from "../../core/errors.js";
|
|
20
|
+
import { ConfigError, NotFoundError, UsageError } from "../../core/errors.js";
|
|
21
|
+
import { getDbPath } from "../../core/paths.js";
|
|
22
|
+
import { warn } from "../../core/warn.js";
|
|
23
|
+
import { withAssetMutationLease } from "../../indexer/index-writer-lock.js";
|
|
15
24
|
import { akmIndex } from "../../indexer/indexer.js";
|
|
16
|
-
import {
|
|
25
|
+
import { compareAndSwapLockfile, readLockfile } from "../../integrations/lockfile.js";
|
|
17
26
|
import { parseRegistryRef } from "../../registry/resolve.js";
|
|
27
|
+
import { sha256Hex } from "../../runtime.js";
|
|
18
28
|
import { parseGitRepoUrl, syncMirroredRepo } from "../../sources/providers/git.js";
|
|
19
29
|
import { syncFromRef } from "../../sources/providers/sync-from-ref.js";
|
|
20
|
-
import { ensureWebsiteMirror, shouldAllowPrivateWebsiteUrlForTests } from "../../sources/website-ingest.js";
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
30
|
+
import { ensureWebsiteMirror, shouldAllowPrivateWebsiteUrlForTests, } from "../../sources/snapshot-fetchers/website-ingest.js";
|
|
31
|
+
import { closeDatabase, openReadonlyExistingDatabase } from "../../storage/repositories/index-connection.js";
|
|
32
|
+
import { getAllEntries } from "../../storage/repositories/index-entries-repository.js";
|
|
33
|
+
import { removeInstalledRegistryEntry } from "./source-add.js";
|
|
23
34
|
import { removeStash } from "./source-manage.js";
|
|
35
|
+
/** Enumerate the registry-managed installs (lock-backed bundles) in a config. */
|
|
36
|
+
function listManagedInstalls(config) {
|
|
37
|
+
const bundles = config.bundles ?? {};
|
|
38
|
+
const locks = new Map(readLockfile().map((entry) => [entry.id, entry]));
|
|
39
|
+
const out = [];
|
|
40
|
+
for (const [key, bundle] of Object.entries(bundles)) {
|
|
41
|
+
const lock = locks.get(key);
|
|
42
|
+
if (!lock)
|
|
43
|
+
continue; // only lock-backed bundles are registry-managed
|
|
44
|
+
const componentWritable = Object.values(bundle.components ?? {})[0]?.writable;
|
|
45
|
+
out.push({
|
|
46
|
+
bundleKey: key,
|
|
47
|
+
installId: bundle.registryId ?? key,
|
|
48
|
+
source: lock.source,
|
|
49
|
+
ref: lock.ref,
|
|
50
|
+
localRoot: lock.localRoot ?? "",
|
|
51
|
+
resolvedVersion: lock.resolvedVersion,
|
|
52
|
+
resolvedRevision: lock.resolvedRevision,
|
|
53
|
+
writable: componentWritable ?? bundle.writable === true,
|
|
54
|
+
requiredRoots: lock.localRoot
|
|
55
|
+
? Object.values(bundle.components ?? {}).map((component) => path.resolve(lock.localRoot, component.root ?? "."))
|
|
56
|
+
: [],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/** Resolve an `akm bundle remove`/`akm bundle update` target to a managed install, if any. */
|
|
62
|
+
function resolveManagedTarget(config, target) {
|
|
63
|
+
const installs = listManagedInstalls(config);
|
|
64
|
+
const byId = installs.find((m) => m.installId === target || m.bundleKey === target);
|
|
65
|
+
if (byId)
|
|
66
|
+
return byId;
|
|
67
|
+
const byRef = installs.find((m) => m.ref === target);
|
|
68
|
+
if (byRef)
|
|
69
|
+
return byRef;
|
|
70
|
+
const isUrl = target.startsWith("http://") || target.startsWith("https://");
|
|
71
|
+
if (!isUrl) {
|
|
72
|
+
const resolved = path.resolve(target);
|
|
73
|
+
const byPath = installs.find((m) => m.localRoot && path.resolve(m.localRoot) === resolved);
|
|
74
|
+
if (byPath)
|
|
75
|
+
return byPath;
|
|
76
|
+
}
|
|
77
|
+
let parsedId;
|
|
78
|
+
try {
|
|
79
|
+
parsedId = parseRegistryRef(target).id;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
parsedId = undefined;
|
|
83
|
+
}
|
|
84
|
+
if (parsedId)
|
|
85
|
+
return installs.find((m) => m.installId === parsedId);
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
function describeBundleSource(entry) {
|
|
89
|
+
if (entry.path)
|
|
90
|
+
return { kind: "path", locator: entry.path };
|
|
91
|
+
if (entry.git)
|
|
92
|
+
return { kind: "git", locator: entry.git };
|
|
93
|
+
if (entry.website) {
|
|
94
|
+
return {
|
|
95
|
+
kind: "website",
|
|
96
|
+
locator: entry.website.url,
|
|
97
|
+
...(entry.website.maxPages !== undefined ? { maxPages: entry.website.maxPages } : {}),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return { kind: "npm", locator: entry.npm ?? "" };
|
|
101
|
+
}
|
|
102
|
+
function describeComponents(entry) {
|
|
103
|
+
return Object.entries(entry.components ?? {}).map(([name, component]) => ({
|
|
104
|
+
name,
|
|
105
|
+
...(component.root !== undefined ? { root: component.root } : {}),
|
|
106
|
+
...(component.adapter !== undefined ? { adapter: component.adapter } : {}),
|
|
107
|
+
...(component.writable !== undefined ? { writable: component.writable } : {}),
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
function describeLock(entry) {
|
|
111
|
+
if (!entry)
|
|
112
|
+
return null;
|
|
113
|
+
return {
|
|
114
|
+
source: entry.source,
|
|
115
|
+
ref: entry.ref,
|
|
116
|
+
...(entry.resolvedVersion !== undefined ? { resolvedVersion: entry.resolvedVersion } : {}),
|
|
117
|
+
...(entry.resolvedRevision !== undefined ? { resolvedRevision: entry.resolvedRevision } : {}),
|
|
118
|
+
...(entry.integrity !== undefined ? { integrity: entry.integrity } : {}),
|
|
119
|
+
...(entry.localRoot !== undefined ? { localRoot: entry.localRoot } : {}),
|
|
120
|
+
...(entry.manifestDigest !== undefined ? { manifestDigest: entry.manifestDigest } : {}),
|
|
121
|
+
...(entry.adapterIds !== undefined ? { adapterIds: entry.adapterIds } : {}),
|
|
122
|
+
...(entry.installedAt !== undefined ? { installedAt: entry.installedAt } : {}),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function readBundleCounts() {
|
|
126
|
+
const counts = new Map();
|
|
127
|
+
const dbPath = getDbPath();
|
|
128
|
+
if (!fs.existsSync(dbPath))
|
|
129
|
+
return counts;
|
|
130
|
+
let db;
|
|
131
|
+
try {
|
|
132
|
+
db = openReadonlyExistingDatabase(dbPath);
|
|
133
|
+
if (!db)
|
|
134
|
+
return counts;
|
|
135
|
+
for (const row of getAllEntries(db)) {
|
|
136
|
+
if (!row.bundleId)
|
|
137
|
+
continue;
|
|
138
|
+
const count = counts.get(row.bundleId) ?? { itemCount: 0, byType: {} };
|
|
139
|
+
count.itemCount += 1;
|
|
140
|
+
count.byType[row.entry.type] = (count.byType[row.entry.type] ?? 0) + 1;
|
|
141
|
+
counts.set(row.bundleId, count);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
warn(`[akm bundle list] failed to read bundle counts from ${dbPath}: ${String(error)}`);
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
if (db) {
|
|
149
|
+
try {
|
|
150
|
+
closeDatabase(db);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// The inventory read is already complete; a close failure is non-fatal.
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return counts;
|
|
158
|
+
}
|
|
24
159
|
export async function akmListSources(input) {
|
|
25
160
|
const stashDir = input?.stashDir ?? resolveStashDir();
|
|
26
161
|
const config = loadConfig();
|
|
27
162
|
const kindFilter = input?.kind;
|
|
163
|
+
const locks = new Map(readLockfile().map((entry) => [entry.id, entry]));
|
|
164
|
+
const counts = readBundleCounts();
|
|
28
165
|
const sources = [];
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (kindFilter && !kindFilter.includes(kind))
|
|
166
|
+
for (const bundle of getSources(config)) {
|
|
167
|
+
const key = bundle.name ?? bundle.path ?? bundle.url ?? "unknown";
|
|
168
|
+
const configured = config.bundles?.[key];
|
|
169
|
+
if (!configured)
|
|
34
170
|
continue;
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
const name = stash.name ?? stash.path ?? stash.url ?? "unknown";
|
|
38
|
-
sources.push({
|
|
39
|
-
name,
|
|
40
|
-
kind,
|
|
41
|
-
wiki: stash.wikiName,
|
|
42
|
-
path: stash.path,
|
|
43
|
-
provider: stash.url != null ? stash.type : undefined,
|
|
44
|
-
writable: stash.writable !== undefined ? stash.writable : writableDefault,
|
|
45
|
-
status: { exists: stash.path ? directoryExists(stash.path) : true },
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
// Installed entries → managed sources
|
|
49
|
-
for (const entry of config.installed ?? []) {
|
|
50
|
-
const kind = "managed";
|
|
171
|
+
const lock = locks.get(key);
|
|
172
|
+
const kind = bundle.type;
|
|
51
173
|
if (kindFilter && !kindFilter.includes(kind))
|
|
52
174
|
continue;
|
|
175
|
+
const root = lock?.localRoot ?? bundle.path ?? "";
|
|
176
|
+
const componentWritable = Object.values(configured.components ?? {})[0]?.writable;
|
|
177
|
+
const bundleCounts = counts.get(key) ?? { itemCount: 0, byType: {} };
|
|
53
178
|
sources.push({
|
|
54
|
-
name:
|
|
179
|
+
name: key,
|
|
55
180
|
kind,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
181
|
+
default: key === config.defaultBundle,
|
|
182
|
+
source: describeBundleSource(configured),
|
|
183
|
+
...(root ? { path: root } : {}),
|
|
184
|
+
...(lock ? { ref: lock.ref } : {}),
|
|
185
|
+
provider: bundle.url != null ? bundle.type : undefined,
|
|
186
|
+
...(lock?.resolvedVersion !== undefined ? { version: lock.resolvedVersion } : {}),
|
|
187
|
+
writable: componentWritable ?? bundle.writable ?? kind === "filesystem",
|
|
188
|
+
...(configured.registryId !== undefined ? { registryId: configured.registryId } : {}),
|
|
189
|
+
components: describeComponents(configured),
|
|
190
|
+
lock: describeLock(lock),
|
|
191
|
+
itemCount: bundleCounts.itemCount,
|
|
192
|
+
byType: bundleCounts.byType,
|
|
193
|
+
status: { exists: root ? directoryExists(root) : true },
|
|
62
194
|
});
|
|
63
195
|
}
|
|
64
|
-
if (!kindFilter || kindFilter.includes("filesystem")) {
|
|
65
|
-
const wikisRoot = resolveWikisRoot(stashDir);
|
|
66
|
-
const seenPaths = new Set(sources
|
|
67
|
-
.map((source) => source.path)
|
|
68
|
-
.filter((sourcePath) => typeof sourcePath === "string")
|
|
69
|
-
.map((sourcePath) => path.resolve(sourcePath)));
|
|
70
|
-
for (const wiki of listWikis(stashDir)) {
|
|
71
|
-
// `listWikis()` also includes externally-registered wikis. `akm list`
|
|
72
|
-
// should synthesize source entries here only for stash-owned wiki dirs.
|
|
73
|
-
if (!isWithin(wiki.path, wikisRoot))
|
|
74
|
-
continue;
|
|
75
|
-
const resolvedPath = path.resolve(wiki.path);
|
|
76
|
-
if (seenPaths.has(resolvedPath))
|
|
77
|
-
continue;
|
|
78
|
-
seenPaths.add(resolvedPath);
|
|
79
|
-
sources.push({
|
|
80
|
-
name: wiki.name,
|
|
81
|
-
kind: "filesystem",
|
|
82
|
-
wiki: wiki.name,
|
|
83
|
-
path: wiki.path,
|
|
84
|
-
writable: true,
|
|
85
|
-
status: { exists: directoryExists(wiki.path) },
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
196
|
return {
|
|
90
197
|
schemaVersion: 1,
|
|
91
|
-
stashDir,
|
|
198
|
+
bundleDir: stashDir,
|
|
199
|
+
defaultBundle: config.defaultBundle ?? null,
|
|
92
200
|
sources,
|
|
93
201
|
totalSources: sources.length,
|
|
94
202
|
};
|
|
@@ -96,33 +204,30 @@ export async function akmListSources(input) {
|
|
|
96
204
|
export async function akmRemove(input) {
|
|
97
205
|
const target = input.target.trim();
|
|
98
206
|
if (!target)
|
|
99
|
-
throw new UsageError("Target is required. Provide the source id, ref, path, URL, or name (e.g. `akm remove npm:@scope/stash` or `akm remove ~/my-stash`).");
|
|
207
|
+
throw new UsageError("Target is required. Provide the source id, ref, path, URL, or name (e.g. `akm bundle remove npm:@scope/stash` or `akm bundle remove ~/my-stash`).");
|
|
100
208
|
const stashDir = input.stashDir ?? resolveStashDir();
|
|
101
209
|
const config = loadConfig();
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (entry.source !== "local") {
|
|
109
|
-
cleanupDirectoryBestEffort(entry.cacheDir);
|
|
210
|
+
// Registry-managed installs (lock-backed bundles) first.
|
|
211
|
+
const managed = resolveManagedTarget(config, target);
|
|
212
|
+
if (managed) {
|
|
213
|
+
const updatedConfig = await removeInstalledRegistryEntry(managed.installId);
|
|
214
|
+
if (managed.source !== "local" && managed.localRoot) {
|
|
215
|
+
cleanupDirectoryBestEffort(managed.localRoot, "remove");
|
|
110
216
|
}
|
|
111
217
|
const index = await akmIndex({ stashDir });
|
|
112
218
|
return {
|
|
113
219
|
schemaVersion: 1,
|
|
114
|
-
stashDir,
|
|
220
|
+
bundleDir: stashDir,
|
|
115
221
|
target,
|
|
116
222
|
removed: {
|
|
117
|
-
id:
|
|
118
|
-
source:
|
|
119
|
-
ref:
|
|
120
|
-
cacheDir:
|
|
121
|
-
stashRoot:
|
|
223
|
+
id: managed.installId,
|
|
224
|
+
source: managed.source,
|
|
225
|
+
ref: managed.ref,
|
|
226
|
+
cacheDir: managed.localRoot,
|
|
227
|
+
stashRoot: managed.localRoot,
|
|
122
228
|
},
|
|
123
229
|
config: {
|
|
124
230
|
sourceCount: getSources(updatedConfig).length,
|
|
125
|
-
installedKitCount: updatedConfig.installed?.length ?? 0,
|
|
126
231
|
},
|
|
127
232
|
index: {
|
|
128
233
|
mode: index.mode,
|
|
@@ -132,7 +237,7 @@ export async function akmRemove(input) {
|
|
|
132
237
|
},
|
|
133
238
|
};
|
|
134
239
|
}
|
|
135
|
-
//
|
|
240
|
+
// Plain sources (filesystem/git/website bundles) via the bundle-map remover.
|
|
136
241
|
const stashResult = removeStash(target);
|
|
137
242
|
if (!stashResult.removed || !stashResult.entry) {
|
|
138
243
|
throw new NotFoundError(`No matching source for target: ${target}`, "SOURCE_NOT_FOUND");
|
|
@@ -142,7 +247,7 @@ export async function akmRemove(input) {
|
|
|
142
247
|
const updatedConfig = loadConfig();
|
|
143
248
|
return {
|
|
144
249
|
schemaVersion: 1,
|
|
145
|
-
stashDir,
|
|
250
|
+
bundleDir: stashDir,
|
|
146
251
|
target,
|
|
147
252
|
removed: {
|
|
148
253
|
id: removedEntry.name ?? removedEntry.path ?? removedEntry.url ?? target,
|
|
@@ -153,7 +258,6 @@ export async function akmRemove(input) {
|
|
|
153
258
|
},
|
|
154
259
|
config: {
|
|
155
260
|
sourceCount: getSources(updatedConfig).length,
|
|
156
|
-
installedKitCount: updatedConfig.installed?.length ?? 0,
|
|
157
261
|
},
|
|
158
262
|
index: {
|
|
159
263
|
mode: index.mode,
|
|
@@ -165,18 +269,19 @@ export async function akmRemove(input) {
|
|
|
165
269
|
}
|
|
166
270
|
// ── akmUpdate helpers ────────────────────────────────────────────────────────
|
|
167
271
|
/** Build a standard UpdateResponse summary block from the current config and index run. */
|
|
168
|
-
async function buildUpdateResponse(stashDir, target, all, processed,
|
|
169
|
-
const index = await akmIndex({ stashDir, ...(full ? { full: true } : {}) });
|
|
272
|
+
async function buildUpdateResponse(stashDir, target, all, processed, opts) {
|
|
273
|
+
const index = opts?.index ?? (await akmIndex({ stashDir, ...(opts?.full ? { full: true } : {}) }));
|
|
170
274
|
const finalConfig = loadConfig();
|
|
171
275
|
return {
|
|
172
276
|
schemaVersion: 1,
|
|
173
|
-
stashDir,
|
|
277
|
+
bundleDir: stashDir,
|
|
174
278
|
target,
|
|
175
279
|
all,
|
|
176
280
|
processed,
|
|
281
|
+
...(opts?.plainSynced?.length ? { plainSynced: opts.plainSynced } : {}),
|
|
282
|
+
...(opts?.skipped?.length ? { skipped: opts.skipped } : {}),
|
|
177
283
|
config: {
|
|
178
284
|
sourceCount: getSources(finalConfig).length,
|
|
179
|
-
installedKitCount: finalConfig.installed?.length ?? 0,
|
|
180
285
|
},
|
|
181
286
|
index: {
|
|
182
287
|
mode: index.mode,
|
|
@@ -186,34 +291,93 @@ async function buildUpdateResponse(stashDir, target, all, processed, full = fals
|
|
|
186
291
|
},
|
|
187
292
|
};
|
|
188
293
|
}
|
|
189
|
-
/**
|
|
190
|
-
|
|
294
|
+
/**
|
|
295
|
+
* Sync a git-mirrored (plain) source in place. Returns the {@link UpdatePlainSyncedItem}
|
|
296
|
+
* record instead of building the full response, so `--all` can batch several of
|
|
297
|
+
* these into one response alongside managed installs (R-015).
|
|
298
|
+
*/
|
|
299
|
+
async function syncGitPlainSource(gitSource) {
|
|
191
300
|
await syncMirroredRepo(gitSource, { force: true, writable: gitSource.writable === true });
|
|
192
|
-
return
|
|
301
|
+
return { id: gitSource.name ?? gitSource.url ?? "", kind: "git", ref: gitSource.url ?? "" };
|
|
193
302
|
}
|
|
194
|
-
/** Re-crawl a website source
|
|
195
|
-
async function
|
|
303
|
+
/** Re-crawl a website (plain) source in place. See {@link syncGitPlainSource}. */
|
|
304
|
+
async function syncWebsitePlainSource(websiteSource) {
|
|
196
305
|
// TODO: full incremental re-crawl with delta tracking (#19)
|
|
197
306
|
await ensureWebsiteMirror(websiteSource, {
|
|
198
307
|
requireStashDir: true,
|
|
199
308
|
force: true,
|
|
200
309
|
...(shouldAllowPrivateWebsiteUrlForTests(websiteSource.url ?? "") ? { allowPrivateHosts: true } : {}),
|
|
201
310
|
});
|
|
202
|
-
return
|
|
311
|
+
return { id: websiteSource.name ?? websiteSource.url ?? "", kind: "website", ref: websiteSource.url ?? "" };
|
|
203
312
|
}
|
|
204
|
-
/** Sync a
|
|
205
|
-
async function
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
313
|
+
/** Sync a git-mirrored (plain) source and return an UpdateResponse (single-target path). */
|
|
314
|
+
async function updateGitSource(stashDir, target, all, gitSource) {
|
|
315
|
+
const synced = await syncGitPlainSource(gitSource);
|
|
316
|
+
return buildUpdateResponse(stashDir, target, all, [], { full: true, plainSynced: [synced] });
|
|
317
|
+
}
|
|
318
|
+
/** Re-crawl a website (plain) source and return an UpdateResponse (single-target path). */
|
|
319
|
+
async function updateWebsiteSource(stashDir, target, all, websiteSource) {
|
|
320
|
+
const synced = await syncWebsitePlainSource(websiteSource);
|
|
321
|
+
return buildUpdateResponse(stashDir, target, all, [], { plainSynced: [synced] });
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* A plain (lockless) npm bundle has no deterministic content path — unlike
|
|
325
|
+
* git/website, resolving an npm package requires a registry round-trip to
|
|
326
|
+
* pick a concrete version/tarball, which is exactly what the lock records.
|
|
327
|
+
* So a plain npm source is synced via the same registry-install pipeline as
|
|
328
|
+
* `akm bundle add <package>` and PROMOTED to a registry-managed (lock-backed)
|
|
329
|
+
* install as a side effect of its first successful sync; it is reported via
|
|
330
|
+
* `processed` like any other managed install from then on. Building a
|
|
331
|
+
* {@link ManagedInstall} view onto the plain entry lets this reuse
|
|
332
|
+
* {@link updateManagedInstall} verbatim rather than duplicating its lock/config
|
|
333
|
+
* bookkeeping.
|
|
334
|
+
*/
|
|
335
|
+
function managedInstallViewOfPlainNpm(npmSource) {
|
|
336
|
+
const spec = npmSource.path ?? "";
|
|
337
|
+
const ref = spec.startsWith("npm:") ? spec : `npm:${spec}`;
|
|
338
|
+
const id = npmSource.name ?? ref;
|
|
339
|
+
return {
|
|
340
|
+
bundleKey: id,
|
|
341
|
+
installId: id,
|
|
342
|
+
source: "npm",
|
|
343
|
+
ref,
|
|
344
|
+
localRoot: "",
|
|
345
|
+
resolvedVersion: undefined,
|
|
346
|
+
resolvedRevision: undefined,
|
|
347
|
+
writable: false,
|
|
348
|
+
requiredRoots: [],
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Sync a single registry-managed install and return the processed record.
|
|
353
|
+
*
|
|
354
|
+
* `yes` gates ONLY the destructive branch below (deleting a previous
|
|
355
|
+
* `localRoot` whose content moved) — it has no effect on the sync itself. A
|
|
356
|
+
* normal refresh that resolves the SAME content directory (the overwhelming
|
|
357
|
+
* majority of updates) never reaches that branch, so it never prompts and
|
|
358
|
+
* never requires `--yes` (F1/R-058: `update` must stay usable bare in
|
|
359
|
+
* scripts; only the branch that can `rm -rf` needs a gate, not the whole
|
|
360
|
+
* command).
|
|
361
|
+
*/
|
|
362
|
+
async function updateManagedInstall(managed, force, yes, stashDir) {
|
|
363
|
+
// No pre-cleanup of the old root, even under --force: the providers already
|
|
364
|
+
// re-materialize staging-first (git clones into a `.tmp-*` sibling and swaps
|
|
365
|
+
// only on success), so destroying `managed.localRoot` BEFORE `syncFromRef`
|
|
366
|
+
// succeeds would turn any sync failure (network down, bad ref) into losing a
|
|
367
|
+
// previously-working install. The old root is cleaned up below only after
|
|
368
|
+
// config/lock publication and reindexing both succeed.
|
|
369
|
+
const synced = await syncFromRef(managed.ref, {
|
|
370
|
+
force,
|
|
371
|
+
writable: managed.writable,
|
|
372
|
+
...(managed.writable && managed.localRoot ? { writableRoot: managed.localRoot } : {}),
|
|
373
|
+
...(managed.writable && managed.requiredRoots.length > 0 ? { writableRequiredRoots: managed.requiredRoots } : {}),
|
|
374
|
+
});
|
|
210
375
|
const installedEntry = {
|
|
211
|
-
id:
|
|
376
|
+
id: managed.installId,
|
|
212
377
|
// Preserve the original source classification. syncFromRef() re-derives the
|
|
213
378
|
// source type from the ref scheme (e.g. "github:" → source: "github"), but
|
|
214
|
-
// an update should not reclassify an existing entry.
|
|
215
|
-
|
|
216
|
-
source: entry.source,
|
|
379
|
+
// an update should not reclassify an existing entry.
|
|
380
|
+
source: managed.source,
|
|
217
381
|
ref: synced.ref,
|
|
218
382
|
artifactUrl: synced.artifactUrl,
|
|
219
383
|
resolvedVersion: synced.resolvedVersion,
|
|
@@ -221,39 +385,102 @@ async function updateRegistryEntry(entry, force) {
|
|
|
221
385
|
stashRoot: synced.contentDir,
|
|
222
386
|
cacheDir: synced.cacheDir,
|
|
223
387
|
installedAt: synced.syncedAt,
|
|
224
|
-
writable: synced.writable ??
|
|
225
|
-
...(entry.wikiName ? { wikiName: entry.wikiName } : {}),
|
|
388
|
+
writable: synced.writable ?? managed.writable,
|
|
226
389
|
};
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
390
|
+
const movedRoot = managed.localRoot !== "" &&
|
|
391
|
+
path.resolve(managed.localRoot) !== path.resolve(synced.contentDir) &&
|
|
392
|
+
managed.source !== "local" &&
|
|
393
|
+
!managed.writable;
|
|
394
|
+
if (movedRoot) {
|
|
395
|
+
const { confirmDestructive } = await import("../../cli/confirm.js");
|
|
396
|
+
const confirmed = await confirmDestructive(`Update resolved a new content directory for "${managed.installId}" (${synced.contentDir}) and would delete the previous install directory at ${managed.localRoot}. This cannot be undone.`, { yes });
|
|
397
|
+
if (!confirmed)
|
|
398
|
+
throw new UsageError(`Update cancelled for "${managed.installId}"; no configuration was changed.`);
|
|
399
|
+
}
|
|
400
|
+
return withAssetMutationLease("source-update", async () => {
|
|
401
|
+
const config = loadConfig();
|
|
402
|
+
const oldLocks = readLockfile();
|
|
403
|
+
if (!config.bundles?.[managed.bundleKey]) {
|
|
404
|
+
throw new ConfigError(`Managed source "${managed.installId}" disappeared before update publication.`);
|
|
405
|
+
}
|
|
406
|
+
const desiredLock = {
|
|
407
|
+
id: managed.bundleKey,
|
|
408
|
+
// Preserve the STORED install kind: a `github:`-ref entry recorded as
|
|
409
|
+
// source "git" must not be reclassified by the sync flow's re-derivation.
|
|
410
|
+
source: managed.source,
|
|
411
|
+
ref: synced.ref,
|
|
412
|
+
resolvedVersion: synced.resolvedVersion,
|
|
413
|
+
resolvedRevision: synced.resolvedRevision,
|
|
414
|
+
integrity: synced.integrity ?? (synced.source === "local" ? "local" : undefined),
|
|
415
|
+
localRoot: synced.contentDir,
|
|
416
|
+
installedAt: synced.syncedAt,
|
|
417
|
+
};
|
|
418
|
+
const desiredLocks = [...oldLocks.filter((entry) => entry.id !== desiredLock.id), desiredLock];
|
|
419
|
+
const desiredLockGeneration = generationHash(desiredLocks);
|
|
420
|
+
if (!(await compareAndSwapLockfile(oldLocks, desiredLocks)))
|
|
421
|
+
throw concurrentGenerationError(managed);
|
|
422
|
+
const index = await akmIndex({ stashDir });
|
|
423
|
+
if (generationHash(readLockfile()) !== desiredLockGeneration)
|
|
424
|
+
throw concurrentGenerationError(managed);
|
|
425
|
+
if (movedRoot) {
|
|
426
|
+
const currentConfig = loadConfig();
|
|
427
|
+
const currentLocks = readLockfile();
|
|
428
|
+
if (referencesRoot(managed.localRoot, currentConfig, currentLocks)) {
|
|
429
|
+
warn(`[akm bundle update] kept previous install directory at ${managed.localRoot} because another configured or locked bundle still references it.`);
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
cleanupDirectoryBestEffort(managed.localRoot, "update");
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const versionChanged = (managed.resolvedVersion ?? "") !== (synced.resolvedVersion ?? "");
|
|
436
|
+
const revisionChanged = (managed.resolvedRevision ?? "") !== (synced.resolvedRevision ?? "");
|
|
437
|
+
return {
|
|
438
|
+
index,
|
|
439
|
+
item: {
|
|
440
|
+
id: managed.installId,
|
|
441
|
+
source: managed.source,
|
|
442
|
+
ref: managed.ref,
|
|
443
|
+
previous: {
|
|
444
|
+
resolvedVersion: managed.resolvedVersion,
|
|
445
|
+
resolvedRevision: managed.resolvedRevision,
|
|
446
|
+
cacheDir: managed.localRoot,
|
|
447
|
+
},
|
|
448
|
+
installed: { ...installedEntry, extractedDir: synced.extractedDir },
|
|
449
|
+
changed: {
|
|
450
|
+
version: versionChanged,
|
|
451
|
+
revision: revisionChanged,
|
|
452
|
+
any: versionChanged || revisionChanged,
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
};
|
|
235
456
|
});
|
|
236
|
-
|
|
237
|
-
|
|
457
|
+
}
|
|
458
|
+
function generationHash(value) {
|
|
459
|
+
return sha256Hex(JSON.stringify(value));
|
|
460
|
+
}
|
|
461
|
+
function referencesRoot(target, config, locks) {
|
|
462
|
+
const resolvedTarget = path.resolve(target);
|
|
463
|
+
const locksById = new Map(locks.map((entry) => [entry.id, entry]));
|
|
464
|
+
for (const [bundleId, bundle] of Object.entries(config.bundles ?? {})) {
|
|
465
|
+
const root = bundle.path ?? locksById.get(bundleId)?.localRoot;
|
|
466
|
+
if (!root)
|
|
467
|
+
continue;
|
|
468
|
+
if (isRootAtOrBelow(root, resolvedTarget))
|
|
469
|
+
return true;
|
|
470
|
+
for (const component of Object.values(bundle.components ?? {})) {
|
|
471
|
+
if (isRootAtOrBelow(path.resolve(root, component.root ?? "."), resolvedTarget))
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
238
474
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
cacheDir: entry.cacheDir,
|
|
249
|
-
},
|
|
250
|
-
installed: { ...installedEntry, extractedDir: synced.extractedDir },
|
|
251
|
-
changed: {
|
|
252
|
-
version: versionChanged,
|
|
253
|
-
revision: revisionChanged,
|
|
254
|
-
any: versionChanged || revisionChanged,
|
|
255
|
-
},
|
|
256
|
-
};
|
|
475
|
+
return locks.some((entry) => entry.localRoot && isRootAtOrBelow(entry.localRoot, resolvedTarget));
|
|
476
|
+
}
|
|
477
|
+
function isRootAtOrBelow(candidate, root) {
|
|
478
|
+
const relative = path.relative(path.resolve(root), path.resolve(candidate));
|
|
479
|
+
const lexicallyWithin = relative === "" || (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
|
|
480
|
+
return lexicallyWithin || isWithin(candidate, root);
|
|
481
|
+
}
|
|
482
|
+
function concurrentGenerationError(managed) {
|
|
483
|
+
return new ConfigError(`Managed source "${managed.installId}" changed concurrently; retained both materialized roots and deleted nothing.`, "INVALID_CONFIG_FILE", "Inspect `akm bundle list` and retry the update after the concurrent source operation completes.");
|
|
257
484
|
}
|
|
258
485
|
// ── akmUpdate dispatcher ─────────────────────────────────────────────────────
|
|
259
486
|
export async function akmUpdate(input) {
|
|
@@ -261,11 +488,17 @@ export async function akmUpdate(input) {
|
|
|
261
488
|
const target = input?.target?.trim();
|
|
262
489
|
const all = input?.all === true;
|
|
263
490
|
const force = input?.force === true;
|
|
491
|
+
const yes = input?.yes === true;
|
|
264
492
|
const config = loadConfig();
|
|
265
|
-
const
|
|
266
|
-
// Check if the target refers to a git or website source — those are stored
|
|
267
|
-
// in sources[] not installed[] and need a different update path.
|
|
493
|
+
const managedInstalls = listManagedInstalls(config);
|
|
268
494
|
if (target && !all) {
|
|
495
|
+
// Registry-managed install (lock-backed) — re-download from its locator.
|
|
496
|
+
const managed = resolveManagedTarget(config, target);
|
|
497
|
+
if (managed) {
|
|
498
|
+
const updated = await updateManagedInstall(managed, force, yes, stashDir);
|
|
499
|
+
return buildUpdateResponse(stashDir, target, all, [updated.item], { index: updated.index });
|
|
500
|
+
}
|
|
501
|
+
// Plain git / website source (bundles without a lock) — provider re-sync.
|
|
269
502
|
const stashes = getSources(config);
|
|
270
503
|
const isUrl = target.startsWith("http://") || target.startsWith("https://");
|
|
271
504
|
const resolvedPath = !isUrl ? path.resolve(target) : undefined;
|
|
@@ -305,28 +538,107 @@ export async function akmUpdate(input) {
|
|
|
305
538
|
});
|
|
306
539
|
if (websiteMatch)
|
|
307
540
|
return updateWebsiteSource(stashDir, target, all, websiteMatch);
|
|
541
|
+
// Plain npm source (bundle without a lock) — sync via the registry
|
|
542
|
+
// pipeline and promote to a managed install (see
|
|
543
|
+
// managedInstallViewOfPlainNpm's doc comment for why npm can't stay
|
|
544
|
+
// plain the way git/website do).
|
|
545
|
+
const npmMatch = stashes.find((s) => {
|
|
546
|
+
if (s.type !== "npm")
|
|
547
|
+
return false;
|
|
548
|
+
if (s.name === target)
|
|
549
|
+
return true;
|
|
550
|
+
if (s.path === target)
|
|
551
|
+
return true;
|
|
552
|
+
return false;
|
|
553
|
+
});
|
|
554
|
+
if (npmMatch) {
|
|
555
|
+
const updated = await updateManagedInstall(managedInstallViewOfPlainNpm(npmMatch), force, yes, stashDir);
|
|
556
|
+
return buildUpdateResponse(stashDir, target, all, [updated.item], { index: updated.index });
|
|
557
|
+
}
|
|
308
558
|
}
|
|
309
|
-
const
|
|
559
|
+
const enabledManagedInstalls = all
|
|
560
|
+
? managedInstalls.filter((managed) => config.bundles?.[managed.bundleKey]?.enabled !== false)
|
|
561
|
+
: managedInstalls;
|
|
562
|
+
const selected = selectManagedTargets(config, enabledManagedInstalls, target, all);
|
|
310
563
|
const processed = [];
|
|
311
|
-
|
|
312
|
-
|
|
564
|
+
let latestManagedIndex;
|
|
565
|
+
for (const managed of selected) {
|
|
566
|
+
const updated = await updateManagedInstall(managed, force, yes, stashDir);
|
|
567
|
+
processed.push(updated.item);
|
|
568
|
+
latestManagedIndex = updated.index;
|
|
569
|
+
}
|
|
570
|
+
// `--all` must account for EVERY configured source, not only the
|
|
571
|
+
// registry-managed (lock-backed) ones (R-015) — `selectManagedTargets`
|
|
572
|
+
// above returns only `installs` for `all`, so plain sources were
|
|
573
|
+
// previously never even looked at. Git/npm plain sources are synced here
|
|
574
|
+
// too (git in place; npm promoted to managed, same as the single-target
|
|
575
|
+
// path above); website/filesystem sources have no `--all` sync path, so
|
|
576
|
+
// they are reported as skipped with the same explanatory wording
|
|
577
|
+
// `selectManagedTargets` already uses for a single unmatched target.
|
|
578
|
+
let plainSynced;
|
|
579
|
+
let skipped;
|
|
580
|
+
let sawGitSync = false;
|
|
581
|
+
if (all) {
|
|
582
|
+
const managedKeys = new Set(managedInstalls.map((m) => m.bundleKey));
|
|
583
|
+
const plainSources = getSources(config).filter((source) => source.enabled !== false && !managedKeys.has(source.name ?? ""));
|
|
584
|
+
plainSynced = [];
|
|
585
|
+
skipped = [];
|
|
586
|
+
for (const plain of plainSources) {
|
|
587
|
+
const id = plain.name ?? plain.path ?? plain.url ?? "";
|
|
588
|
+
try {
|
|
589
|
+
if (plain.type === "git") {
|
|
590
|
+
plainSynced.push(await syncGitPlainSource(plain));
|
|
591
|
+
sawGitSync = true;
|
|
592
|
+
}
|
|
593
|
+
else if (plain.type === "npm") {
|
|
594
|
+
const updated = await updateManagedInstall(managedInstallViewOfPlainNpm(plain), force, yes, stashDir);
|
|
595
|
+
processed.push(updated.item);
|
|
596
|
+
latestManagedIndex = updated.index;
|
|
597
|
+
}
|
|
598
|
+
else if (plain.type === "website") {
|
|
599
|
+
skipped.push({
|
|
600
|
+
id,
|
|
601
|
+
kind: "website",
|
|
602
|
+
reason: `website caching not yet implemented for --all; run \`akm bundle update ${id}\` to re-mirror this source individually.`,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
skipped.push({
|
|
607
|
+
id,
|
|
608
|
+
kind: plain.type,
|
|
609
|
+
reason: "reflects your files in place and has no remote to sync; run `akm index` to refresh the search index.",
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
catch (err) {
|
|
614
|
+
skipped.push({
|
|
615
|
+
id,
|
|
616
|
+
kind: plain.type,
|
|
617
|
+
reason: `sync failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
}
|
|
313
621
|
}
|
|
314
|
-
return buildUpdateResponse(stashDir, target, all, processed
|
|
622
|
+
return buildUpdateResponse(stashDir, target, all, processed, {
|
|
623
|
+
full: sawGitSync,
|
|
624
|
+
plainSynced,
|
|
625
|
+
skipped,
|
|
626
|
+
...(!sawGitSync && latestManagedIndex ? { index: latestManagedIndex } : {}),
|
|
627
|
+
});
|
|
315
628
|
}
|
|
316
|
-
function
|
|
629
|
+
function selectManagedTargets(config, installs, target, all) {
|
|
317
630
|
if (all && target) {
|
|
318
631
|
throw new UsageError("Specify either <target> or --all, not both.", "MISSING_OR_AMBIGUOUS_TARGET");
|
|
319
632
|
}
|
|
320
633
|
if (all)
|
|
321
|
-
return
|
|
634
|
+
return installs;
|
|
322
635
|
if (!target) {
|
|
323
636
|
throw new UsageError("Either <target> or --all is required.", "MISSING_OR_AMBIGUOUS_TARGET");
|
|
324
637
|
}
|
|
325
|
-
const found =
|
|
638
|
+
const found = resolveManagedTarget(config, target);
|
|
326
639
|
if (found)
|
|
327
640
|
return [found];
|
|
328
|
-
//
|
|
329
|
-
const config = loadConfig();
|
|
641
|
+
// Give a helpful message when the target names a plain (non-managed) source.
|
|
330
642
|
const stashes = getSources(config);
|
|
331
643
|
const isUrl = target.startsWith("http://") || target.startsWith("https://");
|
|
332
644
|
const resolvedPath = !isUrl ? path.resolve(target) : undefined;
|
|
@@ -341,47 +653,32 @@ function selectTargets(installed, target, all) {
|
|
|
341
653
|
});
|
|
342
654
|
if (stashMatch) {
|
|
343
655
|
if (stashMatch.type === "website") {
|
|
344
|
-
// Website sources should be handled before reaching selectTargets.
|
|
345
|
-
// This path should not be reached; surface a clear message if it is.
|
|
346
656
|
throw new UsageError(`"${target}" is a website source — website caching not yet implemented for --all. ` +
|
|
347
|
-
`Run \`akm update ${target}\` to re-mirror this source individually.`, "TARGET_NOT_UPDATABLE");
|
|
657
|
+
`Run \`akm bundle update ${target}\` to re-mirror this source individually.`, "TARGET_NOT_UPDATABLE");
|
|
348
658
|
}
|
|
349
659
|
throw new UsageError(`"${target}" is a local directory — it reflects your files in place. To refresh the search index, run: akm index`, "TARGET_NOT_UPDATABLE");
|
|
350
660
|
}
|
|
351
661
|
throw new NotFoundError(`No matching source for target: ${target}`, "SOURCE_NOT_FOUND");
|
|
352
662
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
catch {
|
|
365
|
-
parsedId = undefined;
|
|
366
|
-
}
|
|
367
|
-
if (parsedId) {
|
|
368
|
-
const byParsedId = installed.find((entry) => entry.id === parsedId);
|
|
369
|
-
if (byParsedId)
|
|
370
|
-
return byParsedId;
|
|
371
|
-
}
|
|
372
|
-
return undefined;
|
|
373
|
-
}
|
|
374
|
-
function cleanupDirectoryBestEffort(target) {
|
|
663
|
+
/**
|
|
664
|
+
* Best-effort removal of a directory that is no longer referenced by config
|
|
665
|
+
* or the lockfile. `context` labels the call site (e.g. "remove", "update")
|
|
666
|
+
* in the warning so an operator can tell which command left the directory
|
|
667
|
+
* behind. Failure does not throw — callers already committed the config/lock
|
|
668
|
+
* change that made `target` orphaned — but it must not be silent either
|
|
669
|
+
* (F1/R-058): a swallowed `rmSync` error used to leave no trace anywhere the
|
|
670
|
+
* caller could inspect, so a confirmed deletion that then failed (permission
|
|
671
|
+
* error, file in use, …) looked identical to a successful one.
|
|
672
|
+
*/
|
|
673
|
+
function cleanupDirectoryBestEffort(target, context) {
|
|
375
674
|
try {
|
|
376
675
|
fs.rmSync(target, { recursive: true, force: true });
|
|
377
676
|
}
|
|
378
|
-
catch {
|
|
379
|
-
|
|
677
|
+
catch (err) {
|
|
678
|
+
warn(`[akm ${context}] failed to remove directory ${target}: ${err instanceof Error ? err.message : String(err)}. ` +
|
|
679
|
+
"Remove it manually if it is no longer needed.");
|
|
380
680
|
}
|
|
381
681
|
}
|
|
382
|
-
function shouldCleanupCache(entry) {
|
|
383
|
-
return entry.source !== "local";
|
|
384
|
-
}
|
|
385
682
|
function directoryExists(target) {
|
|
386
683
|
try {
|
|
387
684
|
return fs.statSync(target).isDirectory();
|