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
|
@@ -10,14 +10,26 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import fs from "node:fs";
|
|
12
12
|
import path from "node:path";
|
|
13
|
+
import { parse as yamlParse } from "yaml";
|
|
14
|
+
import { detectAdapterId } from "../../core/adapter/detect-adapter.js";
|
|
13
15
|
import { assertFlatAssetName, combineCreatePath, normalizeCreateSubPath } from "../../core/asset/asset-create.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
+
import { assetPathForName, stashDirFor } from "../../core/asset/asset-placement.js";
|
|
17
|
+
import { assembleAsset } from "../../core/asset/asset-serialize.js";
|
|
18
|
+
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
19
|
+
import { conceptIdFromTypeName, parseRefInput } from "../../core/asset/resolve-ref.js";
|
|
20
|
+
import { isHttpUrl, isWithin, resolveStashDir, tryReadStdinText } from "../../core/common.js";
|
|
16
21
|
import { loadConfig } from "../../core/config/config.js";
|
|
17
22
|
import { UsageError } from "../../core/errors.js";
|
|
18
|
-
import {
|
|
23
|
+
import { resolveBundleWriteTarget, resolveMutationTarget } from "../../core/mutation-target.js";
|
|
24
|
+
import { resolveStashStandards } from "../../core/standards/resolve-stash-standards.js";
|
|
25
|
+
import { warn } from "../../core/warn.js";
|
|
26
|
+
import { commitWriteTargetBoundary, formatRefForMessage, recordWriteTargetPath, resolveWriteTarget, writeAssetToSource, } from "../../core/write-source.js";
|
|
19
27
|
import { indexWrittenAssets } from "../../indexer/index-written-assets.js";
|
|
20
|
-
import {
|
|
28
|
+
import { deriveInstallations, slugForPath } from "../../indexer/installations.js";
|
|
29
|
+
import { resolveSourceEntries } from "../../indexer/search/search-source.js";
|
|
30
|
+
import { fetchWebsiteMarkdownSnapshot, shouldAllowPrivateWebsiteUrlForTests, } from "../../sources/snapshot-fetchers/website-ingest.js";
|
|
31
|
+
import { writeSupersededEdge } from "../improve/memory/memory-belief.js";
|
|
32
|
+
import { refToRelPath, resolveRefPathInStash } from "../lint/base-linter.js";
|
|
21
33
|
const MAX_CAPTURED_ASSET_SLUG_LENGTH = 64;
|
|
22
34
|
// ── Asset-name normalisation ─────────────────────────────────────────────────
|
|
23
35
|
/**
|
|
@@ -111,6 +123,383 @@ export async function readKnowledgeInput(source, options) {
|
|
|
111
123
|
});
|
|
112
124
|
return { content: snapshot.content, preferredName: snapshot.preferredName };
|
|
113
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Parse a `--xref` / `--supersedes` value through the new-grammar input parser
|
|
128
|
+
* (`parseRefInput`, the `[bundle//]conceptId` grammar) so malformed values get a
|
|
129
|
+
* structured error instead of a misleading "did not resolve". Bundle qualifiers
|
|
130
|
+
* are retained for exact source membership checks.
|
|
131
|
+
*/
|
|
132
|
+
function parseWriteRef(raw, flag) {
|
|
133
|
+
let parsed;
|
|
134
|
+
try {
|
|
135
|
+
parsed = parseRefInput(raw);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
139
|
+
throw new UsageError(`${flag} "${raw}" is not a valid asset ref: ${message}`, "INVALID_FLAG_VALUE", `Refs use the conceptId form, e.g. ${flag} knowledge/auth-flow.`);
|
|
140
|
+
}
|
|
141
|
+
// Bundle qualifiers remain explicit so duplicate names resolve in the named
|
|
142
|
+
// source.
|
|
143
|
+
const conceptId = conceptIdFromTypeName(parsed.type, parsed.name);
|
|
144
|
+
const origin = parsed.origin;
|
|
145
|
+
return {
|
|
146
|
+
ref: origin ? `${origin}//${conceptId}` : conceptId,
|
|
147
|
+
type: parsed.type,
|
|
148
|
+
name: parsed.name,
|
|
149
|
+
...(origin ? { origin } : {}),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Trim, parse, and dedupe `--xref` / `--supersedes` flag values, in argv
|
|
154
|
+
* order. Parsing comes before deduplication so normalized spellings collapse
|
|
155
|
+
* into one canonical entry.
|
|
156
|
+
*/
|
|
157
|
+
function parseWriteRefs(rawRefs, flag) {
|
|
158
|
+
const parsedRefs = [];
|
|
159
|
+
for (const raw of rawRefs) {
|
|
160
|
+
const trimmed = raw.trim();
|
|
161
|
+
if (!trimmed)
|
|
162
|
+
continue;
|
|
163
|
+
const parsed = parseWriteRef(trimmed, flag);
|
|
164
|
+
if (!parsedRefs.some((p) => p.ref === parsed.ref))
|
|
165
|
+
parsedRefs.push(parsed);
|
|
166
|
+
}
|
|
167
|
+
return parsedRefs;
|
|
168
|
+
}
|
|
169
|
+
function resolveWriteRefRoots(target) {
|
|
170
|
+
const cfg = loadConfig();
|
|
171
|
+
let writeTarget;
|
|
172
|
+
try {
|
|
173
|
+
writeTarget = resolveWriteTarget(cfg, target);
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
if (!target)
|
|
177
|
+
throw error;
|
|
178
|
+
try {
|
|
179
|
+
writeTarget = resolveBundleWriteTarget(cfg, target);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const stashRoot = writeTarget.source.path;
|
|
186
|
+
let workingStash;
|
|
187
|
+
try {
|
|
188
|
+
workingStash = resolveStashDir();
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// No working stash configured — the write target alone.
|
|
192
|
+
}
|
|
193
|
+
const mutableRoots = [stashRoot];
|
|
194
|
+
if (workingStash && path.resolve(workingStash) !== path.resolve(stashRoot))
|
|
195
|
+
mutableRoots.push(workingStash);
|
|
196
|
+
const namedSources = resolveSourceEntries(undefined, cfg);
|
|
197
|
+
const installations = deriveInstallations(namedSources);
|
|
198
|
+
const bundleByPath = new Map(namedSources.flatMap((source, index) => {
|
|
199
|
+
const bundleId = installations[index]?.id;
|
|
200
|
+
return bundleId ? [[path.resolve(source.path), bundleId]] : [];
|
|
201
|
+
}));
|
|
202
|
+
const otherSources = namedSources.filter((s) => !mutableRoots.some((m) => path.resolve(m) === path.resolve(s.path)) && fs.existsSync(s.path));
|
|
203
|
+
const roots = [
|
|
204
|
+
...mutableRoots
|
|
205
|
+
.filter((p) => fs.existsSync(p))
|
|
206
|
+
.map((p) => {
|
|
207
|
+
const source = namedSources.find((candidate) => path.resolve(candidate.path) === path.resolve(p));
|
|
208
|
+
const mutable = path.resolve(p) === path.resolve(stashRoot)
|
|
209
|
+
? writeTarget.source.adapterId === "akm"
|
|
210
|
+
: source?.writable === true && (source.adapterId ?? detectAdapterId(p)) === "akm";
|
|
211
|
+
return {
|
|
212
|
+
path: p,
|
|
213
|
+
source,
|
|
214
|
+
bundleId: bundleByPath.get(path.resolve(p)) ?? slugForPath(p),
|
|
215
|
+
mutable,
|
|
216
|
+
};
|
|
217
|
+
}),
|
|
218
|
+
...otherSources.map((source) => ({
|
|
219
|
+
path: source.path,
|
|
220
|
+
source,
|
|
221
|
+
bundleId: bundleByPath.get(path.resolve(source.path)) ?? slugForPath(source.path),
|
|
222
|
+
mutable: false,
|
|
223
|
+
})),
|
|
224
|
+
];
|
|
225
|
+
return { roots };
|
|
226
|
+
}
|
|
227
|
+
function rootsForWriteRef(parsed, roots) {
|
|
228
|
+
if (!parsed.origin)
|
|
229
|
+
return roots;
|
|
230
|
+
return roots.filter((root) => root.bundleId === parsed.origin);
|
|
231
|
+
}
|
|
232
|
+
function canonicalWriteRef(parsed, bundleId) {
|
|
233
|
+
return `${bundleId}//${conceptIdFromTypeName(parsed.type, parsed.name)}`;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* True when write-time validation must FAIL OPEN for this ref type — exactly
|
|
237
|
+
* lint's `checkMissingRefs` policy (`if (relPath === null) continue`,
|
|
238
|
+
* base-linter.ts): a type the slug resolver cannot map to a path (script refs
|
|
239
|
+
* are contract-pinned to return null) is accepted without an existence check
|
|
240
|
+
* rather than being unwinnable. Workflow refs never fail open — they resolve
|
|
241
|
+
* stash-rooted via {@link locateWriteRefInRoot}.
|
|
242
|
+
*/
|
|
243
|
+
function isFailOpenRefType(type, name) {
|
|
244
|
+
return type !== "workflow" && refToRelPath(type, name) === null;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Resolve a write-time ref to its primary on-disk file within a single stash
|
|
248
|
+
* root. Wraps lint's `resolveRefPathInStash` with one addition: workflow
|
|
249
|
+
* refs are probed against the ROOT's workflows/ dir first (every recognized
|
|
250
|
+
* workflow extension), because `workflowSpec.toAssetPath` inside
|
|
251
|
+
* `refToRelPath` probes the CWD — and write validation must not depend on the
|
|
252
|
+
* caller's cwd.
|
|
253
|
+
*/
|
|
254
|
+
function locateWriteRefInRoot(type, name, root) {
|
|
255
|
+
if (type === "workflow") {
|
|
256
|
+
const typeRoot = path.join(root, stashDirFor("workflow") ?? "workflows");
|
|
257
|
+
const candidate = assetPathForName("workflow", typeRoot, name);
|
|
258
|
+
if (fs.existsSync(candidate))
|
|
259
|
+
return candidate;
|
|
260
|
+
}
|
|
261
|
+
const relPath = refToRelPath(type, name);
|
|
262
|
+
if (relPath === null)
|
|
263
|
+
return null;
|
|
264
|
+
return resolveRefPathInStash(relPath, type, name, root);
|
|
265
|
+
}
|
|
266
|
+
/** Build the shared exit-2 error for refs that resolved in no root. */
|
|
267
|
+
function unresolvedRefsError(flag, unresolved) {
|
|
268
|
+
const firstName = unresolved[0]?.name ?? "asset";
|
|
269
|
+
const firstType = unresolved[0]?.type ?? "knowledge";
|
|
270
|
+
return new UsageError(`${flag} ref${unresolved.length > 1 ? "s" : ""} did not resolve in the write target or any configured source: ${unresolved.map((u) => u.ref).join(", ")}`, "INVALID_FLAG_VALUE", `Find the intended asset with \`akm search "${firstName}" --type ${firstType}\`. Refs use the form [bundle//]conceptId (e.g. knowledge/guide.md).`);
|
|
271
|
+
}
|
|
272
|
+
// ── Cross-references (--xref) ────────────────────────────────────────────────
|
|
273
|
+
/**
|
|
274
|
+
* Soft cap on xrefs per asset, from the back-linking conventions' "~5" rule.
|
|
275
|
+
* Exceeding it warns on stderr but never blocks the write (the cap is a
|
|
276
|
+
* heuristic, not a validator bound).
|
|
277
|
+
*/
|
|
278
|
+
export const XREF_SOFT_CAP = 5;
|
|
279
|
+
/**
|
|
280
|
+
* Validate `--xref` flag values before ANY write happens.
|
|
281
|
+
*
|
|
282
|
+
* Each `[bundle//]conceptId` must resolve to a real asset in the write-ref root
|
|
283
|
+
* set (write target + working stash + configured sources — see
|
|
284
|
+
* {@link resolveWriteRefRoots}; cross-stash provenance refs into read-only
|
|
285
|
+
* sources are accepted). An unresolvable ref is input validation of an
|
|
286
|
+
* explicitly passed flag — it throws {@link UsageError} (exit 2) naming every
|
|
287
|
+
* bad ref, and the caller must invoke this before writing so a failed
|
|
288
|
+
* validation leaves the stash untouched. Resolution reuses the lint
|
|
289
|
+
* ref-resolver helpers (`refToRelPath` / `resolveRefPathInStash`) — do not
|
|
290
|
+
* fork a second resolver — and mirrors lint's fail-open policy: a type the
|
|
291
|
+
* resolver cannot map to a path (for example a script concept) is accepted
|
|
292
|
+
* without an existence check.
|
|
293
|
+
*
|
|
294
|
+
* Returns fully-qualified durable refs, deduplicated in argv order. More than
|
|
295
|
+
* {@link XREF_SOFT_CAP} refs emits a stderr warning (soft cap) but still
|
|
296
|
+
* returns them all.
|
|
297
|
+
*/
|
|
298
|
+
export function resolveXrefsForWrite(rawXrefs, target) {
|
|
299
|
+
const parsedRefs = parseWriteRefs(rawXrefs, "--xref");
|
|
300
|
+
if (parsedRefs.length === 0)
|
|
301
|
+
return [];
|
|
302
|
+
const { roots } = resolveWriteRefRoots(target);
|
|
303
|
+
const unresolved = [];
|
|
304
|
+
const xrefs = [];
|
|
305
|
+
for (const parsed of parsedRefs) {
|
|
306
|
+
const candidates = rootsForWriteRef(parsed, roots);
|
|
307
|
+
const resolvedRoot = isFailOpenRefType(parsed.type, parsed.name)
|
|
308
|
+
? candidates[0]
|
|
309
|
+
: candidates.find((root) => locateWriteRefInRoot(parsed.type, parsed.name, root.path) !== null);
|
|
310
|
+
if (!resolvedRoot) {
|
|
311
|
+
unresolved.push(parsed);
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
const ref = canonicalWriteRef(parsed, resolvedRoot.bundleId);
|
|
315
|
+
if (!xrefs.includes(ref))
|
|
316
|
+
xrefs.push(ref);
|
|
317
|
+
}
|
|
318
|
+
if (unresolved.length > 0) {
|
|
319
|
+
throw unresolvedRefsError("--xref", unresolved);
|
|
320
|
+
}
|
|
321
|
+
if (xrefs.length > XREF_SOFT_CAP) {
|
|
322
|
+
warn(`Warning: ${xrefs.length} xrefs exceeds the ~${XREF_SOFT_CAP} soft cap from the back-linking conventions. ` +
|
|
323
|
+
"Each xref folds into this asset's search hints, so extras blur its ranking signal. Writing anyway.");
|
|
324
|
+
}
|
|
325
|
+
return xrefs;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Merge validated xrefs into a markdown document's frontmatter `xrefs:` list.
|
|
329
|
+
*
|
|
330
|
+
* A document without frontmatter gains a single block; a document WITH
|
|
331
|
+
* frontmatter keeps every existing key and gets the refs dedupe-appended to
|
|
332
|
+
* its `xrefs:` list — never a nested second block. Runs BEFORE the asset is
|
|
333
|
+
* written so write-path indexing sees the final content. Returns `content`
|
|
334
|
+
* unchanged when `xrefs` is empty.
|
|
335
|
+
*
|
|
336
|
+
* The merge round-trips the frontmatter through the YAML parser, so it is
|
|
337
|
+
* only safe when the existing block parses as a YAML mapping. Malformed YAML
|
|
338
|
+
* would silently fall back to `parseFrontmatter`'s lenient scalar-only
|
|
339
|
+
* scanner and re-serializing that lossy result would destroy list/nested
|
|
340
|
+
* values (`tags: [a, b]` → `tags: ""`). Rather than corrupt data the caller
|
|
341
|
+
* asked to preserve, a block that is not a parseable YAML mapping throws
|
|
342
|
+
* {@link UsageError} (exit 2, before any write). The AKM write boundary also
|
|
343
|
+
* rejects malformed frontmatter without `--xref` because it cannot safely add
|
|
344
|
+
* required type metadata. Known
|
|
345
|
+
* cosmetic limitation: YAML comments and anchors in a VALID block do not
|
|
346
|
+
* survive the round-trip (values are preserved).
|
|
347
|
+
*/
|
|
348
|
+
export function mergeXrefsIntoContent(content, xrefs) {
|
|
349
|
+
if (xrefs.length === 0)
|
|
350
|
+
return content;
|
|
351
|
+
const parsed = parseFrontmatter(content);
|
|
352
|
+
if (parsed.frontmatter?.trim()) {
|
|
353
|
+
if (!isParseableYamlMapping(parsed.frontmatter)) {
|
|
354
|
+
throw new UsageError("--xref cannot merge into this document: its frontmatter is not a parseable YAML mapping, and rewriting it would drop the values the parser could not read.", "INVALID_FLAG_VALUE", "Fix the document's frontmatter (e.g. an unterminated quote) and retry.");
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const existingValue = parsed.data.xrefs;
|
|
358
|
+
const existing = Array.isArray(existingValue)
|
|
359
|
+
? existingValue.filter((v) => typeof v === "string" && v.trim().length > 0)
|
|
360
|
+
: typeof existingValue === "string" && existingValue.trim()
|
|
361
|
+
? [existingValue.trim()]
|
|
362
|
+
: [];
|
|
363
|
+
const merged = [...existing];
|
|
364
|
+
for (const ref of xrefs) {
|
|
365
|
+
if (!merged.includes(ref))
|
|
366
|
+
merged.push(ref);
|
|
367
|
+
}
|
|
368
|
+
return assembleAsset({ ...parsed.data, xrefs: merged }, parsed.content);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* True when a raw frontmatter block (the text between the `---` fences)
|
|
372
|
+
* parses as a YAML mapping — the precondition for any round-trip rewrite.
|
|
373
|
+
* Malformed YAML falls back to `parseFrontmatter`'s lossy lenient scanner
|
|
374
|
+
* (scalars only), and re-serializing that result destroys list/nested values
|
|
375
|
+
* (`tags: [a, b]` → `tags: ""`), so writers must refuse instead of rewriting.
|
|
376
|
+
*/
|
|
377
|
+
function isParseableYamlMapping(frontmatter) {
|
|
378
|
+
try {
|
|
379
|
+
const fmValue = yamlParse(frontmatter);
|
|
380
|
+
return fmValue !== null && typeof fmValue === "object" && !Array.isArray(fmValue);
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/** Resolve any qualified supersedes ref as the mutation target for remember/import. */
|
|
387
|
+
export function resolveSupersedesWriteTarget(rawRefs, target) {
|
|
388
|
+
const config = loadConfig();
|
|
389
|
+
let effectiveTarget = target;
|
|
390
|
+
for (const parsed of parseWriteRefs(rawRefs, "--supersedes")) {
|
|
391
|
+
if (!parsed.origin)
|
|
392
|
+
continue;
|
|
393
|
+
const resolved = resolveMutationTarget(config, { type: parsed.type, name: parsed.name, origin: parsed.origin }, effectiveTarget).target;
|
|
394
|
+
effectiveTarget = resolved.selector ?? resolved.source.name;
|
|
395
|
+
}
|
|
396
|
+
return effectiveTarget;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Asset types `--supersedes` must refuse to demote: the demotion writes a YAML
|
|
400
|
+
* frontmatter block onto the target file, and these types are RAW files whose
|
|
401
|
+
* bytes are the value (a secret's entire content is the credential; a task is
|
|
402
|
+
* pure YAML that a prepended second document breaks; scripts have arbitrary
|
|
403
|
+
* syntax). Prepending frontmatter corrupts them. `akm mv` excludes the same
|
|
404
|
+
* types as "not markdown assets" (plus `script`, unresolvable by design).
|
|
405
|
+
*/
|
|
406
|
+
const SUPERSEDE_REJECTED_TYPES = new Set(["secret", "env", "task", "script"]);
|
|
407
|
+
/**
|
|
408
|
+
* Validate `--supersedes` flag values before ANY write happens.
|
|
409
|
+
*
|
|
410
|
+
* The conventions' corrections pattern needs TWO writes: the new correction
|
|
411
|
+
* asset (with an xref to what it corrects) and a metadata edit demoting the
|
|
412
|
+
* old asset (`beliefState: superseded` + `supersededBy: [<new ref>]`). This
|
|
413
|
+
* helper performs the validation half: each ref must resolve to a real asset
|
|
414
|
+
* (same resolver + root set as {@link resolveXrefsForWrite}); an unresolvable
|
|
415
|
+
* ref throws {@link UsageError} (exit 2) naming every bad ref, so a failed
|
|
416
|
+
* validation leaves the stash untouched — no partial correction.
|
|
417
|
+
*
|
|
418
|
+
* Because the demotion PREPENDS a YAML frontmatter block when the target file
|
|
419
|
+
* has none, only markdown assets may be demoted: refs of a raw asset type
|
|
420
|
+
* ({@link SUPERSEDE_REJECTED_TYPES}) and refs resolving to any non-`.md` file
|
|
421
|
+
* (for example a task YAML file) are rejected with {@link UsageError} BEFORE
|
|
422
|
+
* any write — never silently corrupted.
|
|
423
|
+
*
|
|
424
|
+
* Demotion targets must live under the resolved write target's source path or
|
|
425
|
+
* the working stash — honoring the "only operate on writable sources"
|
|
426
|
+
* constraint (and never dirtying a non-target source outside its boundary
|
|
427
|
+
* commit). A ref that resolves only in another configured source — read-only
|
|
428
|
+
* OR writable-but-not-the-target — is returned with `writable: false` and a
|
|
429
|
+
* reason (naming the `--target` remedy when the source is writable); the
|
|
430
|
+
* caller writes the correction anyway and reports the demotion as not
|
|
431
|
+
* applied.
|
|
432
|
+
*
|
|
433
|
+
* Returns the deduplicated plan in argv order; empty input returns [].
|
|
434
|
+
*/
|
|
435
|
+
export function resolveSupersedesForWrite(rawRefs, target) {
|
|
436
|
+
const parsedRefs = parseWriteRefs(rawRefs, "--supersedes");
|
|
437
|
+
if (parsedRefs.length === 0)
|
|
438
|
+
return [];
|
|
439
|
+
const { roots } = resolveWriteRefRoots(target);
|
|
440
|
+
const plan = [];
|
|
441
|
+
const unresolved = [];
|
|
442
|
+
for (const parsed of parsedRefs) {
|
|
443
|
+
const orderedRoots = rootsForWriteRef(parsed, roots);
|
|
444
|
+
// Data-corruption gate (SPEC-5): demotion is a frontmatter write; a raw
|
|
445
|
+
// asset type must be rejected up front — resolving it and mutating the
|
|
446
|
+
// file would prepend a YAML block over its raw bytes.
|
|
447
|
+
if (SUPERSEDE_REJECTED_TYPES.has(parsed.type)) {
|
|
448
|
+
throw new UsageError(`--supersedes cannot demote ${parsed.ref}: asset type "${parsed.type}" uses raw files, and the demotion writes YAML frontmatter that would corrupt them.`, "INVALID_FLAG_VALUE", "Only markdown assets (e.g. memories/note, knowledge/guide, facts/team/tool-stack) can carry the beliefState/supersededBy demotion. Replace or delete the raw asset instead.");
|
|
449
|
+
}
|
|
450
|
+
let located = null;
|
|
451
|
+
for (const root of orderedRoots) {
|
|
452
|
+
const filePath = locateWriteRefInRoot(parsed.type, parsed.name, root.path);
|
|
453
|
+
if (filePath !== null) {
|
|
454
|
+
located = {
|
|
455
|
+
root: root.path,
|
|
456
|
+
source: root.source,
|
|
457
|
+
bundleId: root.bundleId,
|
|
458
|
+
mutable: root.mutable,
|
|
459
|
+
filePath,
|
|
460
|
+
};
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
if (located === null) {
|
|
465
|
+
unresolved.push(parsed);
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
// Belt-and-suspenders for the same corruption class: whatever the type,
|
|
469
|
+
// the demotion may only touch a markdown file. Rejects, for example, a task
|
|
470
|
+
// YAML file reached through a malformed or stale ref.
|
|
471
|
+
if (!located.filePath.toLowerCase().endsWith(".md")) {
|
|
472
|
+
throw new UsageError(`--supersedes ${parsed.ref} resolves to a non-markdown file (${located.filePath}) — the demotion writes YAML frontmatter and would corrupt it.`, "INVALID_FLAG_VALUE", "Only markdown assets can carry the beliefState/supersededBy demotion. Replace or delete the file instead.");
|
|
473
|
+
}
|
|
474
|
+
const { root, source, bundleId, mutable: writable, filePath } = located;
|
|
475
|
+
// The eligibility rule is write-target-or-working-stash, NOT source
|
|
476
|
+
// writability: mutating a non-target writable source would leave it dirty
|
|
477
|
+
// outside any boundary commit. Name the remedy when one exists.
|
|
478
|
+
const namedWritableSource = source?.writable === true ? source.registryId : undefined;
|
|
479
|
+
const canonicalRef = canonicalWriteRef(parsed, bundleId);
|
|
480
|
+
if (plan.some((item) => item.ref === canonicalRef))
|
|
481
|
+
continue;
|
|
482
|
+
plan.push({
|
|
483
|
+
ref: canonicalRef,
|
|
484
|
+
filePath,
|
|
485
|
+
stashRoot: root,
|
|
486
|
+
writable,
|
|
487
|
+
...(writable
|
|
488
|
+
? {}
|
|
489
|
+
: {
|
|
490
|
+
reason: namedWritableSource
|
|
491
|
+
? `resolves outside the write target and the working stash, in writable source "${namedWritableSource}" at ${root}; ` +
|
|
492
|
+
`re-run with --target ${namedWritableSource} to demote it there`
|
|
493
|
+
: `resolves outside the write target and the working stash, in a read-only source at ${root}; ` +
|
|
494
|
+
"demotion only applies to assets in the write target or the working stash",
|
|
495
|
+
}),
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
if (unresolved.length > 0) {
|
|
499
|
+
throw unresolvedRefsError("--supersedes", unresolved);
|
|
500
|
+
}
|
|
501
|
+
return plan;
|
|
502
|
+
}
|
|
114
503
|
// ── Asset writing ────────────────────────────────────────────────────────────
|
|
115
504
|
/**
|
|
116
505
|
* Write a markdown asset (knowledge or memory) to the resolved write target.
|
|
@@ -122,35 +511,143 @@ export async function readKnowledgeInput(source, options) {
|
|
|
122
511
|
*/
|
|
123
512
|
export async function writeMarkdownAsset(options) {
|
|
124
513
|
const cfg = loadConfig();
|
|
125
|
-
const target = resolveWriteTarget(cfg, options.target);
|
|
126
|
-
const { source, config } = target;
|
|
127
|
-
const typeRoot = path.join(source.path, options.type === "knowledge" ? "knowledge" : "memories");
|
|
128
514
|
// `--name` is the flat asset name; `--path` is the subdirectory under the
|
|
129
515
|
// type root. Combine them into the nested name the path resolver expects.
|
|
130
516
|
const subPath = normalizeCreateSubPath(options.path);
|
|
131
517
|
const baseName = normalizeMarkdownAssetName(options.name, inferAssetName(options.content, options.fallbackPrefix, options.preferredName));
|
|
132
518
|
const normalizedName = combineCreatePath(subPath, baseName);
|
|
519
|
+
const resolved = resolveMutationTarget(cfg, { type: options.type, name: normalizedName }, options.target);
|
|
520
|
+
const { target } = resolved;
|
|
521
|
+
const { source, config } = target;
|
|
522
|
+
const typeRoot = path.join(source.path, options.type === "knowledge" ? "knowledge" : "memories");
|
|
133
523
|
// Pre-flight: existence + force semantics. The helper itself overwrites
|
|
134
524
|
// unconditionally; the CLI surfaces a friendlier UsageError before any
|
|
135
525
|
// disk activity when --force is absent.
|
|
136
|
-
const assetPath =
|
|
526
|
+
const assetPath = assetPathForName(options.type, typeRoot, normalizedName);
|
|
137
527
|
if (!isWithin(assetPath, typeRoot)) {
|
|
138
528
|
throw new UsageError(`Resolved ${options.type} path escapes the stash: "${normalizedName}"`);
|
|
139
529
|
}
|
|
140
530
|
if (fs.existsSync(assetPath) && !options.force) {
|
|
141
531
|
throw new UsageError(`${options.type === "knowledge" ? "Knowledge" : "Memory"} "${normalizedName}" already exists. Re-run with --force to overwrite it.`, "RESOURCE_ALREADY_EXISTS");
|
|
142
532
|
}
|
|
143
|
-
|
|
144
|
-
|
|
533
|
+
// A correction cannot supersede ITSELF. Under `--force` the ref resolves to
|
|
534
|
+
// the very file this command is about to overwrite, and the demotion would
|
|
535
|
+
// immediately mark the fresh correction superseded (plus a self-xref) —
|
|
536
|
+
// silently hiding the fix from `--belief current` and capping its rank.
|
|
537
|
+
// Input validation: exit 2, before any write, nothing demoted.
|
|
538
|
+
for (const item of options.supersedes ?? []) {
|
|
539
|
+
if (path.resolve(item.filePath) === path.resolve(assetPath)) {
|
|
540
|
+
throw new UsageError(`--supersedes ${item.ref} resolves to the asset being written ("${resolved.displayRef}") — a correction cannot supersede itself.`, "INVALID_FLAG_VALUE", "Write the correction under a different --name, or drop --supersedes when overwriting an asset in place with --force.");
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
const result = await writeAssetToSource(source, config, resolved.ref, options.content);
|
|
544
|
+
const durableRef = result.ref;
|
|
545
|
+
result.ref = resolved.displayRef;
|
|
546
|
+
// SPEC-5 (--supersedes): demote each superseded asset by mutating its
|
|
547
|
+
// frontmatter (`beliefState: superseded` + sorted-set-append `supersededBy`;
|
|
548
|
+
// every other key and the body are preserved). Ordered BEFORE
|
|
549
|
+
// commitWriteTargetBoundary so a git target batches the correction and the
|
|
550
|
+
// demoted incumbent into the single boundary commit instead of leaving the
|
|
551
|
+
// metadata edit as dirty residue after it.
|
|
552
|
+
const superseded = [];
|
|
553
|
+
const demotedByRoot = new Map();
|
|
554
|
+
for (const item of options.supersedes ?? []) {
|
|
555
|
+
if (!item.writable) {
|
|
556
|
+
const reason = item.reason ?? "target is not writable";
|
|
557
|
+
warn(`Warning: superseded asset ${item.ref} was NOT demoted (${reason}). ` +
|
|
558
|
+
"The correction was written and cites it in xrefs; demote the old asset where it is writable.");
|
|
559
|
+
superseded.push({ ref: item.ref, applied: false, reason });
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
// The demotion round-trips the old file's frontmatter through the YAML
|
|
563
|
+
// parser. A malformed block would silently fall back to the lossy lenient
|
|
564
|
+
// scanner and re-serializing that result destroys list/nested values —
|
|
565
|
+
// skip instead of rewriting, mirroring mergeXrefsIntoContent's
|
|
566
|
+
// abort-on-malformed policy (the correction itself still writes).
|
|
567
|
+
let oldFrontmatter = null;
|
|
568
|
+
try {
|
|
569
|
+
oldFrontmatter = parseFrontmatter(fs.readFileSync(item.filePath, "utf8")).frontmatter;
|
|
570
|
+
}
|
|
571
|
+
catch {
|
|
572
|
+
// Unreadable file — let writeSupersededEdge surface the real fs error.
|
|
573
|
+
}
|
|
574
|
+
if (oldFrontmatter?.trim() && !isParseableYamlMapping(oldFrontmatter)) {
|
|
575
|
+
const reason = "its existing frontmatter is not a parseable YAML mapping — rewriting it would drop the values the parser could not read";
|
|
576
|
+
warn(`Warning: superseded asset ${item.ref} was NOT demoted (${reason}). ` +
|
|
577
|
+
"The correction was written and cites it in xrefs; fix the old asset's frontmatter and re-run the correction with --force.");
|
|
578
|
+
superseded.push({ ref: item.ref, applied: false, reason });
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
// A demotion failure (fs error, concurrent delete, malformed YAML the
|
|
582
|
+
// pre-check missed) must NOT abort the correction: the new asset is
|
|
583
|
+
// already on disk, and bailing out here would skip the boundary commit and
|
|
584
|
+
// the write-path indexing below — leaving the correction unindexed and,
|
|
585
|
+
// on a git target, uncommitted (and a re-run hits RESOURCE_ALREADY_EXISTS).
|
|
586
|
+
// Degrade to the same applied:false report the non-writable path uses.
|
|
587
|
+
try {
|
|
588
|
+
const sameSource = path.resolve(item.stashRoot) === path.resolve(source.path);
|
|
589
|
+
writeSupersededEdge(item.filePath, durableRef);
|
|
590
|
+
if (sameSource) {
|
|
591
|
+
recordWriteTargetPath(source, item.filePath);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
catch (error) {
|
|
595
|
+
const reason = `demotion failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
596
|
+
warn(`Warning: superseded asset ${item.ref} was NOT demoted (${reason}). ` +
|
|
597
|
+
"The correction was written and cites it in xrefs; demote the old asset manually or re-run the correction with --force.");
|
|
598
|
+
superseded.push({ ref: item.ref, applied: false, reason });
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
superseded.push({ ref: item.ref, applied: true });
|
|
602
|
+
const files = demotedByRoot.get(item.stashRoot) ?? [];
|
|
603
|
+
files.push(item.filePath);
|
|
604
|
+
demotedByRoot.set(item.stashRoot, files);
|
|
605
|
+
}
|
|
145
606
|
// 0.9.0 (issue #507): single batch commit at the write boundary for git
|
|
146
607
|
// targets. No-op for filesystem/primary-stash targets.
|
|
147
|
-
commitWriteTargetBoundary(target, `Update ${formatRefForMessage(ref)}`);
|
|
608
|
+
commitWriteTargetBoundary(target, `Update ${formatRefForMessage(resolved.ref)}`);
|
|
148
609
|
// Write-path indexing: the asset is searchable immediately. Fail-open; reads
|
|
149
|
-
// no longer trigger reindexes, so keeping the index current is the writer's
|
|
150
|
-
|
|
610
|
+
// no longer trigger reindexes, so keeping the index current is the writer's
|
|
611
|
+
// job. Demoted files reindex under their own containing root (usually the
|
|
612
|
+
// write target itself; the working stash when writing to a --target) so
|
|
613
|
+
// `--belief current` filtering and the beliefState ranking demotion take
|
|
614
|
+
// effect without waiting for the next full index.
|
|
615
|
+
const demotedInTargetRoot = demotedByRoot.get(source.path) ?? [];
|
|
616
|
+
demotedByRoot.delete(source.path);
|
|
617
|
+
await indexWrittenAssets(source.path, [result.path, ...demotedInTargetRoot], { bundleId: resolved.ref.origin });
|
|
618
|
+
const sourceEntries = resolveSourceEntries(undefined, cfg);
|
|
619
|
+
const sourceInstallations = deriveInstallations(sourceEntries);
|
|
620
|
+
for (const [root, files] of demotedByRoot) {
|
|
621
|
+
const sourceIndex = sourceEntries.findIndex((entry) => path.resolve(entry.path) === path.resolve(root));
|
|
622
|
+
await indexWrittenAssets(root, files, { bundleId: sourceInstallations[sourceIndex]?.id });
|
|
623
|
+
}
|
|
624
|
+
// Placement hint (stash-organization conventions): CLI writers never receive
|
|
625
|
+
// the resolveStashStandards prompt injection LLM flows get, so a type-root
|
|
626
|
+
// write into a stash that carries convention/meta facts points the writer at
|
|
627
|
+
// the placement conventions. Additive output key, advisory only — parallel
|
|
628
|
+
// to search's `tip`. Fail-open: the hint must never break a completed write.
|
|
629
|
+
let hint;
|
|
630
|
+
if (!subPath && !normalizedName.includes("/")) {
|
|
631
|
+
try {
|
|
632
|
+
if (resolveStashStandards(source.path).trim().length > 0) {
|
|
633
|
+
// Only point at the canonical organization fact when it actually
|
|
634
|
+
// exists — resolveStashStandards fires for ANY convention/meta fact,
|
|
635
|
+
// and a dead `akm show` pointer is worse than generic wording.
|
|
636
|
+
const orgFactPath = path.join(source.path, "facts", "conventions", "organization.md");
|
|
637
|
+
hint = fs.existsSync(orgFactPath)
|
|
638
|
+
? `Wrote to the ${options.type} root. This stash has placement conventions — see \`akm show facts/conventions/organization\`.`
|
|
639
|
+
: `Wrote to the ${options.type} root. This stash has placement conventions — see the convention facts under its facts/ directory.`;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
catch {
|
|
643
|
+
// Advisory only.
|
|
644
|
+
}
|
|
645
|
+
}
|
|
151
646
|
return {
|
|
152
647
|
ref: result.ref,
|
|
153
648
|
path: result.path,
|
|
154
649
|
stashDir: source.path,
|
|
650
|
+
...(hint ? { hint } : {}),
|
|
651
|
+
...(superseded.length > 0 ? { superseded } : {}),
|
|
155
652
|
};
|
|
156
653
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { toErrorMessage } from "../../core/common.js";
|
|
5
5
|
import { DEFAULT_CONFIG } from "../../core/config/config.js";
|
|
6
6
|
import { warn } from "../../core/warn.js";
|
|
7
|
-
import {
|
|
7
|
+
import { resolveRegistryProviderFactory } from "../../registry/factory.js";
|
|
8
8
|
// ── Eagerly import providers to trigger self-registration ───────────────────
|
|
9
9
|
import "../../registry/providers/index.js";
|
|
10
10
|
// ── Public API ──────────────────────────────────────────────────────────────
|
|
@@ -142,7 +142,7 @@ export function resolveRegistries(configRegistries) {
|
|
|
142
142
|
// ── Provider resolution ─────────────────────────────────────────────────────
|
|
143
143
|
function createProvider(entry, warnings) {
|
|
144
144
|
const providerType = entry.provider ?? "static-index";
|
|
145
|
-
const factory =
|
|
145
|
+
const factory = resolveRegistryProviderFactory(providerType);
|
|
146
146
|
if (!factory) {
|
|
147
147
|
const label = entry.name ? `${entry.name} (${entry.url})` : entry.url;
|
|
148
148
|
warnings.push(`Registry ${label}: unknown provider type "${providerType}"`);
|